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";

    private static Preferences prefs =
        Preferences.userNodeForPackage(Gadget.class);

    public void foo() {
        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. Note additionally that a single Preferences instance is obtained and stored in a static variable: it is perfectly acceptable for multiple threads to use a single Preferences instance concurrently with no external synchronization. Note finally that the above code accesses per-user preferences. If a single per-system value were desired, the first line in foo would be replaced by:

    private static Preferences sysPrefs =
        Preferences.systemNodeForPackage(Gadget.class);
The use of system preferences should be rare compared to user preferences. We anticipate that they will be used chiefly to store configuration information (such as what version of a program is installed or what resources it uses). In typical Java platform implementations, ordinary users will not be able to modify system preferences as backing stores typically demand administrative privileges to modify system-wide data.

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(position.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;
        }
        ...
    }

Saving and Restoring Preferences

The exportNode, importSubtree and importPreferences calls make it easy to save and restore preferences externally for offline backup or "canned configurations." For example, the following program saves all preferences for the current user to the standard output stream:
import java.util.prefs.*;
import java.io.IOException;

public class SavePrefs {
    public static void main(String[] args)
            throws IOException, BackingStoreException {
        Preferences root = Preferences.userRoot();
        root.exportSubtree(System.out);
    }
}
Running this program with the following command line produces a backup of user preferences:
java SavePrefs > backup.prefs
The following simple program imports preferences from the standard input stream:
import java.util.prefs.*;
import java.io.IOException;

public class RestorePrefs {
    public static void main(String[] args)
            throws IOException, InvalidPreferencesFormatException {
        Preferences.importPreferences(System.in);
    }
}
Running this program with the following command line restores the user preferences from the file produced by the previous command line:
java RestorePrefs < backup.prefs
If it is run by a user other than the one that saved the preferences in the first place, it copies the preferences from that user to the current user.

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 Preferences prefs =
        Preferences.userNodeForPackage(ThisClass.class);

    private static boolean backingStoreAvailable() {
        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.