Find JSRs
Submit this Search


Ad Banner
 
 
 
 

Usage Notes for the Proposed Java Preferences API

Usage Notes for the Proposed Javatm Preferences API

Typical Uses

Here is a typical use of the preferences facility:
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(this);

        int numRows = prefs.getInt(NUM_ROWS, 40);
        int numCols = prefs.getInt(NUM_COLS, 80);

        ...
    }
}
Note that static final fields are used for the key names ( NUM_ROWS and NUM_COLS) in place of inline String literals). 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. Finally note that these are per-user preferences. If a single per-system value were desired, the first line in foo would be replaced by:
        Preferences prefs = Preferences.systemNodeForPackage(this);
The above samples contains an idiom for obtaining the Preferences objects (system and user) pertaining to the enclosing class. Note that these idioms only work inside instance methods. In a static method (or static initializer), you need to provide the name of the package explicitly:
    Static String ourNodeName = "/com/acme/widget";

    static void foo() {
        Preferences prefs = Preferences.userRoot().node(ourNodeName);

        ...
    }
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);
It is generally 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 may return the appropriate node for the calling user, hence it's critical that calls to userNodeForPackage or userRoot are made from the appropriate thread at the appropriate time. If a piece of code may eventually be used in such server environment, it is good, conservative practice to obtain user prefrences objects immediately before they are used, as in the first example on this page. The current default Preferences implementations do not behave differently in a server environment, but it is anticipated that future implementations may behave in this fashion.

Atomic Updates

The preferences API does not offer "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;
        }
        ...
    }

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. Here's 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;
    }
Copyright 2000 Sun Microsystems, Inc., 901 San Antonio Road, Palo Alto, California 94303 U.S.A. All rights reserved.