Ticket #1706 (closed enhancement: moved)

Opened 6 years ago

Last modified 5 years ago

Preferences for Multiple Instances, Applications, and Versions

Reported by: gharris Owned by: curtis
Priority: minor Milestone: imagej-2.0.0
Component: Core Version:
Severity: minor Keywords:
Cc: Blocked By:
Blocking: #1451

Description

Regarding Preferences support for Multiple Instances, Applications, and Versions

Right now, Prefs are stored in the userRoot() by Class<?> and name.

I don't think that this allows us to support any of these scenarios:

  • multiple applications (that use the application framework)
  • multiple versions of the same application
  • multiple instances (contexts) of the same application

I all of these cases, they will stomp on each other by reading/writing the same Prefs.

I'd like to propose an extension to the Prefs mechanism which follows:

When an application launches, if it does not find a node for itself (applicationA/v2.0), it could optionally copy or translate the values from an old version node (applicationA/v2.0). The Prefs class could provide some helper methods for this. The Prefs nodes could be something like this:

userRoot()

/applicationA

/v1.01

/...

/v1.02

/...

/applicationB

/v2.0

/...

To deal with multiple instances (contexts) of the same application, it might make sense to have the prefs stored by context (perhaps under a node for application and a node for each version. It seems that each instance would need to have an identifier, and this identifier would need to be set when the app. (re-)launches, perhaps using a command line argument.

While less common, the ability to have multiple instances (contexts) of the same application can be useful in two use cases I can think of: 1) running instances running headless on a server, 2) having multiple users of an application on the same OS user account (like 'guest'). A context identifier would also enable separate prefs settings for these situations.

Using context identifiers, perhaps the Prefs nodes could be something like this:

userRoot()

/applicationA

/v1.01

/...
/cID1

/...

/v1.02

/...

/applicationB

/v2.0

/cID1

/...

/cID2

/...


For example, if a context identifier is provided, the app. would use the nodes under /applicationA/v1.01/cID1... and if a context identifier is not provided, the app. would use the nodes under /applicationA/v1.01/...

Perhaps Prefs could be Contextual, and then use getTitle(), getVersion().
(For the context, I suppose one kluge would be to add something to the Title...)

There may be some related issues, e.g. in ConfigFileParameters, this is hardcoded: CONFIG_FILE = "ImageJ.cfg";

Related Tickets #1451 and #1093

Change History

comment:1 Changed 6 years ago by curtis

  • Blocking 1451 added

Firstly, note that the preferences are loaded and saved as part of the preprocessing chain during command execution. The relevant preprocessors are:

And the actual saving and loading code for module items is unfortunately  hardcoded right now.

From my perspective, it is clear from your comments that this logic should be refactored into its own service class as part of the ticket #1451 work. That way, any future deficiencies in the persistence mechanism could be fixed downstream by using an alternate service implementation.

When an application launches, if it does not find a node for itself, it could optionally copy or translate the values from an old version node

Yes, it would need to copy the values from the next level up the tree. And when persisting the values, it would need to store them to its node, as well as higher level nodes ("stomping on" the previous values) for the benefit of future contexts. This scheme would allow concurrent contexts to keep separate track of preferences, avoiding some concurrency issues at the expense of increased complexity. (E.g., some people might be surprised or confused when different contexts retrieve different persisted values from what they might assume would be a common storage mechanism.)

Another concern I have is what to use for the context identifiers. If we use positive increasing ID numbers, when a context first starts up in a fresh JVM it might inherit the persisted values from the previous JVM's context(s), assuming we start again from "1" each time. Or we could persist the last-used context ID, and have an always-incrementing long, which would ensure each context has a nearly-eternally-unique ID, but then the persisted preferences would become major cruft over time. Alternately, rather than using the Preferences API for context-specific preferences, we could store them in a data structure of the service rather than on disk via the Preferences API, which would be my tentative preference.

Thoughts?

comment:2 Changed 6 years ago by curtis

  • Milestone changed from imagej-2.1.0 to imagej-2.0.0

comment:3 Changed 6 years ago by gharris

I think making persisted preferences a service makes sense to me.

I was thinking that the context identifiers could be managed by a human on a given computer.

Concerning where the values are stored, alternate backstores can implement PreferencesFactory (see  http://www.onjava.com/pub/a/onjava/synd/2001/10/17/j2se.html?page=2)

And Commons Configuration has numerous options for reading/writing:  http://commons.apache.org/proper/commons-configuration/

comment:4 Changed 6 years ago by gharris

Here's another option that backends to JDBC:  http://code.google.com/p/java-util-prefs-jdbc-backend/

comment:5 Changed 6 years ago by curtis

Thanks. These are all cool things, but strike me as something that downstream code could easily do using an alternative PrefsService—or maybe even using the DefaultPrefsService with a different PreferencesFactory. For the standard preferences behavior shipped in ImageJ2, we can continue to use the default behavior of the Java Preferences API, as long as we provide a seam to override as discussed above.

As for managing context identifiers by hand... were you thinking a string value in the options somewhere?

comment:6 Changed 6 years ago by gharris

Yes, perhaps just a unique (on this machine) string in the command line args seems like ti would work for most use cases I can think of... so far...

comment:7 Changed 5 years ago by hinerm

  • Status changed from new to closed
  • Resolution set to moved
Note: See TracTickets for help on using tickets.