Skip to content

Internal Workings of the Anathema Repository

Curtis Tasker edited this page Jul 23, 2013 · 4 revisions

Written by @curttasker for anathema/anathema#192

I spent some quality time trying to understand our preferences system, mainly how we go about handling the default repository preference.

Since this sort of thing helps me understand code like this, I'm just going to do a brain dump of what I've found, and hopefully this is all mostly correct, and can help someone dealing with the preference system it in the future.

Key Classes

AnathemaPreferences

  • Singleton, constructed in Anathema, stores Preferences.userRoot().node(SYSTEM_PREFERENCES_NODE)) locally as its java.util.prefs.Preferences data store.
  • getRepositoryLocationPreferences(defaultLocation) calls Preferences.get( REPOSITORY_PREFERENCE, DEFAULT_REPOSITORY_LOCATION) This will return the Preferences value for the key REPOSITORY_REFERENCE, but if this value does not exist, returns the literal value of DEFAULT_REPOSITORY_LOCATION

RepositoryLocationResolver

  • Constructed with an IAnathemaPreferences object, stores it privately.
  • resolve() looks for System.getProperty("repository"), and returns its value. This is the linux shell script override for changing your repository at the command line.
  • If the above property is not found, it calls AnathemaPreferences.getRepositoryLocationPreferences() with the argument of System.getProperty("defaultrepository") ). AnathemaPreferences.getRepositoryLocationPreferences() then returns either the user's custom chosen repository, or the value of System.getProperty("defaultrepository"). If the user has no custom repository folder, and the "defaultrepository" property is not set, then it defaults to ./repository/.
  • resolve() looks like it attempts to strip out the user's home folder from the path of the repository. LeadingPropertyResolver is being created to parse "%USER_HOME%", "user.home". I'm very confused as to what this achieves.
  • resolve() is used by RepositoryFolderCreator and DefaultAnathemaReflections only. update Figured this one out. It only happens when I build a full mac application and run, not during testing. Java prepends some garbage onto the path that needs to be stripped off.

RepositoryPreferencesElement

  • Displays the preferences elements from the window shown above.
  • Uses SYSTEM_PREFERENCES.get(REPOSITORY_PREFERENCE, DEFAULT_REPOSITORY_LOCATION)) to load the repository directory. This will return the Preferences value for the key REPOSITORY_PREFERENCE, but if this value does not exist, returns the literal value of DEFAULT_REPOSITORY_LOCATION.
  • savePreferences() Saves the repository's location to Preferences, using the key REPOSITORY_PREFERENCE. If the user's selected repository location equals the system default location, then remove the key REPOSITORY_PREFERENCE from Preferences.
  • Thus, in absence of any user selected repository locaiton, this class always assumes the default repository location of DEFAULT_REPOSITORY_LOCATION, which is "./repository".

There are many more PreferencesElements that all use SYSTEM_PREFERENCES.get(KEY_HERE) method to get (and set) their preferences.

RepositoryFolderCreator

  • Called by AnathemaModelInitializer & RepositoryPreferencesElement.isValid()
  • Uses RepositoryLocationResolver to find the repository folder
  • Creates, the repository folder, if it does not exist, and returns a File reference to the current repository folder.

AnathemaModelInitializer

  • Uses RepositoryFolderCreator to get a File reference to the repository folder.
  • Passes this repository reference into AnathemaModel, and from there its used downstream by most of the application (GsonEquipmentDatabse, for example), to find the location of the Repository.

DefaultAnathemaReflections

  • Uses RepositoryLocationResolver to find the location of the repository, and adds the repository location to the classpath list it uses.

RepositoryPreferenceUpdater

  • Rips the key/value pair for OLD_REPOSITORY_PREFERENCE out Properties, and re-stores the value under the key REPOSITORY_PREFERENCE.
  • It looks like this deletes the Preferences key for the old repository entirely. So I'm not sure how this "allows users to run current versions of Anathema in parallel with 3.1.x versions" as is stated in the class's comment. It looks like once you run 4.0.0, your preferences are moved to the new format for life.

AnathemaPreferencesAction

  • execute() Called when someone changes a preference in the preferences menu. It goes through every preference in the menu, checks to see if it has been changed (isDirty()), and if so, calls that preference class' savePreferences() method. In this case, it will call RepositoryPreferencesElement.savePreferences()
  • execute() brings up the "Please restart Anathema" dialog when you change a preference.

Constants Referenced

IAnathemaPreferencesConstants.REPOSITORY_PREFERENCE = "RepositoryForAnathema4orHigher"; IAnathemaPreferencesConstants.DIRECTORY_CHOOSER_NODE = "DirectoryChooser"; IAnathemaPreferencesConstants.DEFAULT_REPOSITORY_LOCATION = "./repository/"; IAnathemaPreferencesConstants.SYSTEM_PREFERENCES_NODE = "anathema/system"; IPreferencesElement.SYSTEM_PREFERENCES = Preferences.userRoot().node(SYSTEM_PREFERENCES_NODE); RepositoryPreferencesElement.REPOSITORY_PREFERENCE_DIRECTORY_CHOOSER_VALUE = "RepositoryPreference"; RepositoryPreferenceUpdater.OLD_REPOSITORY_PREFERENCE = "Repository";

Notes

  • The Mac client uses the System.getProperty("defaultrepository") property to set the default repository location.

  • The Linux shell script launcher uses the System.getProperty("repository") property to set the default repository location.

  • The Windows Installer (for both all users and just you) uses a hardcoded ./repository folder off of the installed root of the application.

  • Rulling the application as a jar file on any OS uses a hardcoded ./repository folder off of the anathema.jar file location.

  • Java Preferences - The implementation of the actual storage for Preferences depends on the platform, and OS version.

    • Mac OS X 10.7.3 stores them in a file called ~/Library/Preferences/com.apple.java.util.prefs.plist.
    • Windows 7 stores the preferences in the registry under HKEY_CURRENT_USER\Software\JavaSoft\Prefs\

Summary

So the system is largely based around hardcoded ./repository folders rooted at the location of the Anathema executable. The system can be overridden using System properties, with defaultrepository and repository both working, though in different ways. The value of the key defaultrepository is only used as the repository location if the user has not selected a custom repository location (which would be now stored in the Preferences bundle). The repository key is a master override, and setting a value for this key will force anathema to ignore any custom repository location in favor of the value of the key.

There doesn't seem to be any single point of entry for systems wishing to know where the repository is located, at the moment. We have RepositoryPreferencesElement (among others) checking directly against the Preferences bundle, and we have the AnathemaModelInitializer using RepositoryLocationResolver to grab the location from the System Properties, rather than the Preferences.

Intent: It looks like the intention was to use the two System Properties keys, "repository" and "defaultrepository" to allow overriding the user selected repository, and setting the default repository location, respectively. Unfortunately, these properties are only used in the linux shell script and mac app file, respectively. Everywhere else the system just assumes a ./repository folder. When referenced in code, the constant DEFAULT_REPOSITORY_LOCATION (shown above) is used. The ./repository value is hardcoded into the windows installer in anathema.nsi

The actual Preferences bundle works well, though there is a little confusion over how to access the repository folder. We have RepositoryPreferencesElement duplicating some of the RepositoryLocationResolver code, and directly accessing the Properties bundle to retrieve the repository location.