Using preferences in java

Class Preferences

A node in a hierarchical collection of preference data. This class allows applications to store and retrieve user and system preference and configuration data. This data is stored persistently in an implementation-dependent backing store. Typical implementations include flat files, OS-specific registries, directory servers and SQL databases. The user of this class needn’t be concerned with details of the backing store.

There are two separate trees of preference nodes, one for user preferences and one for system preferences. Each user has a separate user preference tree, and all users in a given system share the same system preference tree. The precise description of «user» and «system» will vary from implementation to implementation. Typical information stored in the user preference tree might include font choice, color choice, or preferred window location and size for a particular application. Typical information stored in the system preference tree might include installation configuration data for an application.

Nodes in a preference tree are named in a similar fashion to directories in a hierarchical file system. Every node in a preference tree has a node name (which is not necessarily unique), a unique absolute path name, and a path name relative to each ancestor including itself.

The root node has a node name of the empty string («»). Every other node has an arbitrary node name, specified at the time it is created. The only restrictions on this name are that it cannot be the empty string, and it cannot contain the slash character (‘/’).

Читайте также:  Wordpress css and javascript

The root node has an absolute path name of «/» . Children of the root node have absolute path names of «/» + . All other nodes have absolute path names of + «/» + . Note that all absolute path names begin with the slash character.

  • No relative path names begin with the slash character.
  • Every node’s path name relative to itself is the empty string.
  • Every node’s path name relative to its parent is its node name (except for the root node, which does not have a parent).
  • Every node’s path name relative to the root is its absolute path name with the initial slash character removed.
  • No path name contains multiple consecutive slash characters.
  • No path name with the exception of the root’s absolute path name ends in the slash character.
  • Any string that conforms to these two rules is a valid path name.

All of the methods that modify preferences data are permitted to operate asynchronously; they may return immediately, and changes will eventually propagate to the persistent backing store with an implementation-dependent delay. The flush method may be used to synchronously force updates to the backing store. Normal termination of the Java Virtual Machine will not result in the loss of pending updates — an explicit flush invocation is not required upon termination to ensure that pending updates are made persistent.

All of the methods that read preferences from a Preferences object require the invoker to provide a default value. The default value is returned if no value has been previously set or if the backing store is unavailable. The intent is to allow applications to operate, albeit with slightly degraded functionality, even if the backing store becomes unavailable. Several methods, like flush , have semantics that prevent them from operating if the backing store is unavailable. Ordinary applications should have no need to invoke any of these methods, which can be identified by the fact that they are declared to throw BackingStoreException .

Читайте также:  Python if несколько условий and

The methods in this class may be invoked concurrently by multiple threads in a single JVM without the need for external synchronization, and the results will be equivalent to some serial execution. If this class is used concurrently by multiple JVMs that store their preference data in the same backing store, the data store will not be corrupted, but no other guarantees are made concerning the consistency of the preference data.

This class contains an export/import facility, allowing preferences to be «exported» to an XML document, and XML documents representing preferences to be «imported» back into the system. This facility may be used to back up all or part of a preference tree, and subsequently restore from the backup.

The XML document has the following DOCTYPE declaration:

Note that the system URI (http://java.sun.com/dtd/preferences.dtd) is not accessed when exporting or importing preferences; it merely serves as a string to uniquely identify the DTD, which is:

Every Preferences implementation must have an associated PreferencesFactory implementation. Every Java(TM) SE implementation must provide some means of specifying which PreferencesFactory implementation is used to generate the root preferences nodes. This allows the administrator to replace the default preferences implementation with an alternative implementation.

  1. If the system property java.util.prefs.PreferencesFactory is defined, then it is taken to be the fully-qualified name of a class implementing the PreferencesFactory interface. The class is loaded and instantiated; if this process fails then an unspecified error is thrown.
  2. If a PreferencesFactory implementation class file has been installed in a jar file that is visible to the system class loader , and that jar file contains a provider-configuration file named java.util.prefs.PreferencesFactory in the resource directory META-INF/services , then the first class name specified in that file is taken. If more than one such jar file is provided, the first one found will be used. The class is loaded and instantiated; if this process fails then an unspecified error is thrown.
  3. Finally, if neither the above-mentioned system property nor an extension jar file is provided, then the system-wide default PreferencesFactory implementation for the underlying platform is loaded and instantiated.

Источник

Preferences API Overview

All of the methods that modify preference data are permitted to operate asynchronously. They may return immediately, and changes will eventually propagate to the persistent backing store. The flush method can be used to force updates to the backing store.

The methods in the Preferences class may be invoked concurrently by multiple threads in a single JVM without the need for external synchronization, and the results will be equivalent to some serial execution. If this class is used concurrently by multiple JVMs that store their preference data in the same backing store, the data store will not be corrupted, but no other guarantees are made concerning the consistency of the preference data.

For more details, choose from the following links:

Comparing Preferences API to Other Mechanisms

Prior to the introduction of the Preferences API, developers could choose to manage preference and configuration data in an ad hoc fashion, by using the Properties API or the JNDI API as described below.

Often, preference and configuration data was stored in properties files, accessed through the java.util.Properties API. However, there are no standards as to where such files should reside on disk, or what they should be called. Using this mechanism, it is extremely difficult to backup a user’s preference data, or transfer it from one machine to another. As the number of applications increases, the possibility of file name conflicts increases. Also, this mechanism is of no help on platforms that lack a local disk, or where it is desirable that the data be stored in an external data store (such as an enterprise-wide LDAP directory service).

Less frequently, developers stored user preference and configuration data in a directory service, accessed through the Java Naming and Directory Interface (JNDI) API. Unlike the Properties API, JNDI allows the use of arbitrary data stores (back-end neutrality). While JNDI is extremely powerful, it is also rather large, consisting of 5 packages and 83 classes. JNDI provides no policy as to where in the directory name space the preference data should be stored, or in which name space.

Neither Properties nor JNDI provide a simple, ubiquitous, back-end neutral preferences management facility. The Preferences API does provide such a facility, combining the simplicity of Properties with the back-end neutrality of JNDI. It provides sufficient built-in policy to prevent name clashes, foster consistency, and encourage robustness in the face of inaccessibility of the backing data store.

Usage Notes

The material contained in this section is not part of the Preferences API specification, instead it is intended to provide some examples of how the Preferences API might be used.

Obtaining Preferences Objects for an Enclosing Class

The following examples illustrate how you might obtain the Preferences objects (system and user) pertaining to the enclosing class. These examples would work only inside instance methods.

Note that static final fields, rather than inline String literals, are used for the key names ( NUM_ROWS and NUM_COLS ). This reduces the likelihood of runtime bugs from typographical errors in key names.

Note also that reasonable defaults are provided for each of the preference values obtained. These defaults will be returned if no preference value has been set, or if the backing store is inaccessible.

package com.acme.widget; import java.util.prefs.*; public class Gadget < // Preference keys for this package private static final String NUM_ROWS = "num_rows"; private static final String NUM_COLS = "num_cols"; void foo() < Preferences prefs = Preferences.userNodeForPackage(Gadget.class); int numRows = prefs.getInt(NUM_ROWS, 40); int numCols = prefs.getInt(NUM_COLS, 80); . >>

The above example obtains per-user preferences. If a single, per-system value were desired, the first line in foo would be replaced by:

Preferences prefs = Preferences.systemNodeForPackage(Gadget.class);

Obtaining Preferences Objects for a Static Method

The examples in the prior section illustrate obtaining Preferences objects pertaining to the enclosing class, and work inside instance methods. In a static method (or static initializer), you need to explicitly provide the name of the package:

Static String ourNodeName = «/com/acme/widget»; static void foo()

It is always acceptable to obtain a system preferences object once, in a static initializer, and use it whenever system preferences are required:

static Preferences prefs = Preferences.systemRoot().node(ourNodeName);

In general, it is acceptable to do the same thing for a user preferences object, but not if the code in question is to be used in a server, wherein multiple users will be running concurrently or serially. In such a system, userNodeForPackage and userRoot will return the appropriate node for the calling user, thus it’s critical that calls to userNodeForPackage or userRoot be made from the appropriate thread at the appropriate time. If a piece of code may eventually be used in such a server environment, it is good, conservative practice to obtain user preferences objects immediately before they are used, as in the prior example.

Atomic Updates

The preferences API does not provide database like «transactions» wherein multiple preferences are modified atomically. Occasionally, it is necessary to modify two or more preferences as a unit. For example, suppose you are storing the x and y coordinates where a window is to be placed. The only way to achieve atomicity is to store both values in a single preference. Many encodings are possible. Here’s a simple one:

int x, y; . prefs.put(POSITION, x + "," + y);

When such a «compound preference» is read, it must be decoded. For robustness, allowances should be made for a corrupt (unparseable) value:

static int X_DEFAULT = 50, Y_DEFAULT = 25; void baz() < String position = prefs.get(POSITION, X_DEFAULT + "," + Y_DEFAULT); int x, y; try < int i = position.indexOf(','); x = Integer.parseInt(coordinates.substring(0, i)); y = Integer.parseInt(position.substring(i + 1)); >catch(Exception e) < // Value was corrupt, just use defaults x = X_DEFAULT; y = Y_DEFAULT; >. >

Determining Backing Store Status

Typical application code has no need to know whether the backing store is available. It should almost always be available, but if it isn’t, the code should continue to execute using default values in place of preference values from the backing store. Very rarely, some advanced program might want to vary its behavior (or simply refuse to run) if the backing store were unavailable. Following is a method that determines whether the backing store is available by attempting to modify a preference value and flush the result to the backing store.

private static final String BACKING_STORE_AVAIL = "BackingStoreAvail"; private static boolean backingStoreAvailable() < Preferences prefs = Preferences.userRoot().node(""); try < boolean oldValue = prefs.getBoolean(BACKING_STORE_AVAIL, false); prefs.putBoolean(BACKING_STORE_AVAIL, !oldValue); prefs.flush(); >catch(BackingStoreException e) < return false; >return true; >

Источник

Оцените статью