/* This file is part of the source code for 3D-XplorMath-J, Version 1.0 (January 2008). * Copyright (c) 2008 The 3D-XplorMath Consortium (http://3d-xplormath.org). * This source code is released under a BSD License, which allows redistribution * in source and binary form, with or without modification, provided copyright * and license information are included, and with no warranty or guarantee of * any kind. For details, see http://3d-xplormath.org/j/source/BSDLicense.txt */ package vmm.core; import java.util.HashMap; import java.util.Map; import java.util.prefs.Preferences; /** * Provides a simple mechanism for saving and retrieving user preferences, * with a default implementation based on the standard package java.util.prefs. * (There is a way to use a different implementation, which is provided to * allow, for example, using the WebStart Persistance service for storing the * preferences. See {@link #setPrefs(Prefs)}.) *
Preferences are stored as aset of key/value pairs, where both the * key and value are Strings. The key string must be non-null and cannot * be the empty string. (Also, it should probably not contain the "/" character. * Some convenience methods * are provided for working with values of type int, double, and boolean, but * these just automate the converions of the values to and from Strings. *
Note that the design philosopy of this class is that it should always
* be harmless to call methods from this class, even in applets where security
* restrictions might make it impossible to access the Preferences database.
*/
public class Prefs {
private static Prefs prefs; // The actual preferences implementation;
// might be replaced by an object belonging
// to a subclass.
/**
* This string (in the default Prefs implementation) is prepended to the key
* parameter in all the methods defined in this class to give the key that
* is actually used in cals to the Java Preferences API. It represents
* a unique path name that should not be used by any other program.
*/
protected final static String DEFAULT_PREFIX = "/org/virtualmathmuseum/vmm/";
/**
* All preference values that have been associated with keys by calling
* {@link #put(String, String)}, {@link #putInt(String, int)}, etc., are
* not acutally sent to persistent storage until this method is called.
* They are, however, remembered by this class so that subsequent calles
* to {@link #get(String)}, {@link #getInt(String, int)}, etc., will
* return the correct values while the program is running.
* This method does not throw any exception (in the default implementation), but is not guaranteed to
* save the data. For example, it will probably fail to save the data if called
* from an applet.
* @see #save(String)
* @return true if the data is successfully saved, false if it cannot be saved.
* The return value will probably be disregarded in most cases.
*/
synchronized public static boolean save() {
if (prefs == null)
return true; // No preferences have been set, so there is nothing to save.
else
return prefs.doSave();
}
/**
* The preference value, if any, that has been associated with the
* given key is saved to persitent on-disk storage.
* @see #save()
* @param key the key whose value is to be saved to persistent storage.
* @return true if the data is successfully saved, false if it cannot be saved.
* The return value will probably be disregarded in most cases.
*/
synchronized public static boolean save(String key) {
if (prefs == null)
return true; // No preferences have been set, so there is nothing to save.
else
return prefs.doSave(key);
}
/**
* Associate a value with a key in the preferences database. This is not
* automatically saved to persistent storage.
* @see #save()
* @param key a non-null, non-empty string that identifies the preference value.
* A null or empty string will generate an IllegalArgumentException (in the
* default implementation).
* @param value The value that is to be associated to the key. The value
* can be null. However, note that no way is provided to differentiate
* between a key that has a null value and a key that has no value at
* all.
*/
synchronized public static void put(String key, String value) {
if (prefs == null)
prefs = new Prefs();
prefs.doPut(key,value);
}
/**
* Associate a value with a key in the preferences database, and then save that
* preference to persistent storage if possible. The return value tells whether
* the value was successfully saved to persistent storage. This methos simply
* calls {@link #put(String, String)} and {@link #save(String)}.
*/
synchronized public static boolean putAndSave(String key, String value) {
prefs.doPut(key,value);
return prefs.doSave(key);
}
/**
* Get the preferences value associated with a given key. This method never
* throws an exception (in the default implemtation).
* @see #put(String, String)
* @param key a non-null, non-empty string that identifies the preference value.
* If the key is a null or empty string, no error occurs, but the return value
* is null.
* @return the preference value associated with the key. This value
* can be null. If a value has
* been set for the key with a put method, that value is
* returned. Otherwise, an attempt is made to read the value from
* persistant storage; if attempt fails, the return value is null.
*/
synchronized public static String get(String key) {
if (prefs == null)
prefs = new Prefs();
return prefs.doGet(key);
}
/**
* A convenience method that calls put(key,""+value).
* @see #put(String, String)
*/
public static void putInt(String key, int value) {
put(key,""+value);
}
/**
* A convenience method that calls put(key,""+value),
* except that the values Double.NaN, Double.POSITIVE_INFINITY,
* and Double.NEGATIVE_INFINITY are encoded as "NaN", "+INF",
* and "-INF", respectively.
* @see #put(String, String)
*/
public static void putDouble(String key, double value) {
if (Double.isNaN(value))
put (key,"NaN");
else if (value == Double.POSITIVE_INFINITY)
put(key,"+INF");
else if (value == Double.NEGATIVE_INFINITY)
put(key,"-INF");
else
put(key,""+value);
}
/**
* A convenience method that calls put(key,"true")
* or put(key,"false"), depending on the value.
* @see #put(String, String)
*/
public static void putBoolean(String key, boolean value) {
put(key, value? "true" : "false");
}
/**
* Returns the preference string associated with a given key, or deflt if
* no value is associated with the key. This method never
* throws an exception.
* @param key the key whose associated preference value is to be returned
* @param deflt the value that will be returned if the key has no
* associated preference value or if an error occurs when trying
* to read the preferenece value from persistent storage.
*/
public static String get(String key, String deflt) {
String val = get(key);
return (val == null? deflt : val);
}
/**
* Returns Integer.parseInt(get(key)), or deflt if
* no value is associated with the given key or if the string
* associated with that key is not an integer. This method never
* throws an exception.
* @see #get(String)
* @param key the key whose associated preference value is to be returned
* @param deflt the value that will be returned if the key has no
* associated preference value or if the value does not represent
* an integer, or if an error occurs while trying to read the
* value from persistent storage.
*/
public static int getInt(String key, int deflt) {
String val = get(key);
if (val == null)
return deflt;
else {
try {
return Integer.parseInt(val);
}
catch (Exception e) {
return deflt;
}
}
}
/**
* Returns Double.parseDouble(get(key)), or deflt if
* no value is associated with the given key or if the string
* associated with that key is not an integer. The strings
* "NaN", "+INF", and "-INF" are traslated into the special
* values Double.NaN, Double.POSITIVE_INFINTY, and Double.NEGATIVE_INFINITY.
* This method never throws an exception.
* @see #get(String)
* @param key the key whose associated preference value is to be returned
* @param deflt the value that will be returned if the key has no
* associated preference value or if the value does not represent
* a real number, or if an error occurs while trying to read the
* value from persistent storage.
*/
public static double getDouble(String key, double deflt) {
String val = get(key);
if (val == null)
return deflt;
else if (val.equals("NaN"))
return Double.NaN;
else if (val.equals("+INF"))
return Double.POSITIVE_INFINITY;
else if (val.equals("-INF"))
return Double.NEGATIVE_INFINITY;
else {
try {
return Double.parseDouble(val);
}
catch (Exception e) {
return deflt;
}
}
}
/**
* Returns true if get(key) equals "true",
* or false if get(key) equals "false", or deflt
* if the value of get(key) is some other value.
* This method never throws an exception.
* @see #get(String)
* @param key the key whose associated preference value is to be returned
* @param deflt the value that will be returned if the key has no
* associated preference value or if the value does not represent
* a boolean value, or if an error occurs while trying to read the
* value from persistent storage.
*/
public static boolean getBoolean(String key, boolean deflt) {
String val = get(key);
if (val == null)
return deflt;
else if (val.equalsIgnoreCase("true"))
return true;
else if (val.equalsIgnoreCase("false"))
return false;
else
return deflt;
}
/**
* Set the object of type Prefs that actually handles the storage and retrival
* of prefernce values. By default, the object is just an object of type
* Prefs, but it could be changed to an object belonging to a sub-class of
* Prefs by calling this method. This method should ordinarily be called
* at the start of a program, before any calls to other static methods in
* this class. If prefs is null, then a default object will
* be created of type Prefs.
*/
public static void setPrefs(Prefs prefs) {
Prefs.prefs = prefs;
}
/**
* Returns the object that is used to handle storage of preference values.
* The return value is non-null.
* @see #setPrefs(Prefs)
*/
public static Prefs getPrefs() {
if (prefs == null)
prefs = new Prefs();
return prefs;
}
//---------------------------- Default implementation of preferences ----------------------
private HashMap