Preferences in JMRI are stored in two different formats within three different spaces.
The access structure for JMRI preferences is based upon the access structure for project properties (called the Auxiliary Configuration for a project) and preferences within the NetBeans IDE.
There are two APIs, PreferencesManager and PreferencesPanel that implement the access to and control of preferences within a JMRI application.
Most preferences are stored together within a single Profile. There are two spaces within a Profile, the shared space and the private space.
A Profile has a location, a name, and an identity. The identity is formed of two parts, a "safe" version of the name that can be used in file or directory names, and a random number (8 hexidecimal digits) to ensure uniqueness.
It is recommended that Profile locations have the extension .jmri
to allow
Profiles to be assigned a Uniform Type Identifier (UTI) in iOS and macOS. JMRI applications
default to including the extension in the Profile location when creating one, but use of this
extension is not enforced. See Startup Scripts for more
details on UTIs and their use.
Shared preferences are preferences within a single profile that are shared across multiple computers running that profile. An example of a shared preference is the use of the LocoNet connection "LocoNet".
Shared preferences are stored in the root of the profile
directory within the
Profile.
Private preferences are preferences within a single profile that are only used on a single computer running that profile. An example of a private preference is the use of the port "COM3" to get to the system the connection "LocoNet" uses.
Private preferences are stored in directories named jmri-UUID-ID
where "UUID"
is a universally unique identifier for the computer and "ID" is the random digits in the
identity of the profile. A unique private preferences directory is created for each user for
each computer a profile is used on.
The settings directory is where JMRI retains preferences that are not stored within a single profile, and which are only used on a single computer. An example of a preference in the Settings Directory are the preferences for how a JMRI application selects the Profile to use.
The settings directory is per user account on a single computer.
There's more information on the Profile File Structure page.
Preferences within a JMRI application may be stored as XML elements or as Java Preferences.
The XML elements for JMRI preferences are stored in two different files within a single
space: profile.xml
(or preferences.xml
) and
user-interface.xml
. Within the two different files, preferences are stored using
the same means and same structure, however the intention of the two files are different.
A manager for preferences using either of these files manages a type of preference, for example, connection configurations or table state. The manager uses the methods in AuxiliaryConfiguration to get, put, or remove these XML elements. These methods all require the Element or the Element's name and if the Element is shared or private.
XML elements for JMRI preferences must all have valid and resolvable namespaces. These namespaces do not have to be unique to or defined within the jmri.org website.
properties.xml
should contain preferences that have been explicitly
set by the user within the JMRI Preferences user interface. These preferences tend to have
significant impact on how an application operates and may require that the application be
restarted to take effect.
preferences.xml
only contains preferences that apply to all profiles
operating under a single user on a single computer.
profile.xml
should contain preferences that have been explicitly set
by the user within the JMRI Preferences user interface. These preferences tend to have
significant impact on how an application operates and may require that the application be
restarted to take effect.
Shared and private versions of profile.xml
are retained within a single
profile.
user-interface.xml
contains implicit preferences, such as window size and
location, table sort order, and other captured user-interface state that is automatically
restored as needed.
user-interface.xml
is only private within a single profile.
JMRI application preferences that a simple (a number, boolean, or string), or a list of simple preferences, and can only be meaningfully used once within a single Profile are candidates for storage as Java Preferences.
JMRI uses a Properties format for storing Java Preferences in the file
profile.properties
within both Shared and Private spaces in a single Profile.
The file preferences.properties
is used for storing preferences that apply to
all profiles run by a single user within a single computer.
JMRI further constrains Java Preferences by putting them in separate "namespaces" based on package names. This allows preferences in two different packages to use the same name for a preference (for example, the JMRI Web Server and Simple Server both have a "port" property, but because these are in different packages, they do not conflict).
If another class is already controlling the preferences you want to access, use that class's methods to access that preference. If not, create a class to manage that preference on behalf of other classes within a JMRI application.
Direct access to the preferences files outlined above is strongly discouraged, as direct access could result in one preferences manager overwriting another manager's preferences. Use the methods in ProfileUtils to access the AuxiliaryConfiguration and Java Preferences for a single Profile or the application settings (pass null for the profile to get application settings).
PreferenceManagers are the primary handlers of preference retrieval and storage in JMRI applications.
The JMRI library has a number of Preferences Managers. These managers all provide an implementation of the PreferencesManager interface to allow them to be discovered. Preferences managers are loaded by the JMRI configuration manager, which uses the ServiceLoader API to create an instance of every preferences manager (this allows third-party JARs to implement preferences managers; see the ServiceLoader API docs for details on how this works and the jmri.spi API docs for details of how JMRI meets the ServiceLoader API requirements).
Because the mechanism by which preferences managers are discovered has no deterministic order, the preferences managers API includes methods that allow a preference manager to require that other specific preference managers are correctly initialized before it is initialized.
PreferencePanels are the user interface for interacting with Preferences Managers within the Preferences window of a JMRI application.
When the Preferences window is initialized, it uses the ServiceLoader API to create an instance of every preferences panel (this allows third-party JARs to implement preferences panels).
Preferences panels provide hints for grouping the panels together, but do not provide hints for ordering preferences panels. Some groupings of preferences panels are well know within the Preferences window, and are given in a specific order, after which every other group of preferences panels are ordered alphabetically.
The following scripts included in the JMRI distribution show how to access preferences within a script: