ucar.util.prefs.PreferencesExt Maven / Gradle / Ivy
/*
* Copyright (c) 1998-2018 University Corporation for Atmospheric Research/Unidata
* See LICENSE for license information.
*/
package ucar.util.prefs;
import java.util.*;
import java.util.prefs.*;
/**
* An extension of java.util.prefs.Preferences (jdk 1.4) that provides a
* platform-independent implementation using XML files as backing store.
* To save Java beans, use putBean() and putBeanCollection(). This uses
* reflection to get/set properties that have simple single-valued accessor methods
* of primitive and String type.
*
For arbitrary objects, use putBeanObject(), which uses the
* XMLEncode/XMLDecode API (jdk 1.4).
*
* To obtain a PreferencesExt object, instantiate an XMLStore object and
* call XMLStore.getPreferences().
*
* @see ucar.util.prefs.XMLStore
* @see java.util.prefs.Preferences
* @author John Caron
*/
public class PreferencesExt extends java.util.prefs.AbstractPreferences implements ucar.util.prefs.PersistenceManager {
static Preferences userRoot = new PreferencesExt(null, ""); // ??
static Preferences systemRoot = new PreferencesExt(null, "");
/** Set the user root you get when you call Preferences.userRoot(). */
static public void setUserRoot( PreferencesExt prefs) { userRoot = prefs; }
/** Set the system root you get when you call Preferences.systemRoot(). */
static public void setSystemRoot( PreferencesExt prefs) {
systemRoot = prefs;
}
private PreferencesExt parent;
private HashMap keyValues, children;
private PreferencesExt storedDefaults = null;
/**
* Constructor. Usually you get a PreferencesExt object from XMLStore.getPrefs(),
* rather than constructing one directly.
* For the root node, parent = null and name = "".
*/
public PreferencesExt(PreferencesExt parent, String name) {
super(parent, name);
this.parent = parent;
keyValues = new HashMap(20);
children = new HashMap(10);
}
void setStoredDefaults( PreferencesExt storedDefaults) {
this.storedDefaults = storedDefaults;
}
private PreferencesExt getStoredDefaults() {
return (parent == null) ? storedDefaults : parent.getStoredDefaults();
}
/** return true unless this is the systemRoot node */
public boolean isUserNode() { return this != systemRoot; } // ??
////////////////////////////////////////////////////////
// get/put beans
/**
* Get the object that has the specified key.
* This returns the object itself, not a copy, so
* if you change the bean and call store.save(), any changes to the object will be saved,
* even without calling putBean(). If you want to change the object without saving the
* changes, you must make a copy of the object yourself.
*
* @param key get the object with this key.
* @param def the default value to be returned in the event that this
* preference node has no value associated with key.
* @return the value associated with key, or def
* if no value is associated with key.
* @throws IllegalStateException if this node (or an ancestor) has been
* removed with the {@link #removeNode()} method.
* @throws NullPointerException if key is null. (A
* null default is permitted.)
*/
public Object getBean(String key, Object def) {
if (key==null)
throw new NullPointerException("Null key");
if (isRemoved())
throw new IllegalStateException("Node has been removed.");
synchronized(lock) {
Object result = null;
try {
result = _getObject( key);
if (result != null) {
if (result instanceof Bean.Collection)
result = ((Bean.Collection)result).getCollection();
else if (result instanceof Bean)
result = ((Bean)result).getObject();
}
} catch (Exception e) {
// Ignoring exception causes default to be returned
}
return (result==null ? def : result);
}
}
/**
* Stores an object using simple bean properties.
* If the exact key and value are already in
* the storedDefaults (using equals() to test for equality), then it is not
* stored.
*
* @param key key with which the specified value is to be associated.
* @param newValue store this bean.
* @throws NullPointerException if key or value is null.
* @throws IllegalStateException if this node (or an ancestor) has been
* removed with the {@link #removeNode()} method.
*/
public void putBean(String key, Object newValue) {
// if matches a stored Default, dont store
Object oldValue = getBean(key, null);
if ((oldValue == null) || !oldValue.equals( newValue))
keyValues.put( key, new Bean(newValue));
}
/**
* Stores a Collection of beans. The beans are stored using simple bean properties.
* The collection of beans must all be of the same class.
*
* @param key key with which the specified collection is to be associated.
* @param newValue store this collection of beans.
* @throws NullPointerException if key or value is null.
* @throws IllegalStateException if this node (or an ancestor) has been
* removed with the {@link #removeNode()} method.
*/
public void putBeanCollection(String key, Collection newValue) {
// if matches a stored Default, dont store
Object oldValue = getBean(key, null);
if ((oldValue == null) || !oldValue.equals( newValue))
keyValues.put( key, new Bean.Collection(newValue));
}
/**
* Stores an object using XMLEncoder/XMLDecoder. Use this for arbitrary objects.
* If the exact key and value are already in
* the storedDefaults (using equals() to test for equality), then it is not
* stored.
*
* @param key key with which the specified value is to be associated.
* @param newValue store this bean object.
* @throws NullPointerException if key or value is null.
* @throws IllegalStateException if this node (or an ancestor) has been
* removed with the {@link #removeNode()} method.
*/
public void putBeanObject(String key, Object newValue) {
// if matches a stored Default, dont store
Object oldValue = getBean(key, null);
if ((oldValue == null) || !oldValue.equals( newValue))
keyValues.put( key, newValue);
}
////////////////////////////////////////////////////////
// get/put list
/**
* Get an arrayList. This returns a copy of the stored list.
*
* @param key key whose associated value is to be returned.
* @param def the value to be returned in the event that this
* preference node has no value associated with key.
* @return the value associated with key, or def
* if no value is associated with key.
*/
public List getList(String key, List def) {
try {
Object bean = getBean(key, def);
return (List) bean;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* Stores the value with this key, if the exact key and value are not already in
* the storedDefaults (using equals() to test for equality).
* "Two lists are defined to be equal if they contain the same elements in the same order."
*
* @param key key with which the specified value is to be associated.
* @param newValue value to be associated with the specified key.
*/
public void putList(String key, List newValue) {
putBeanObject(key, newValue);
}
/////// the SPI interface
/**
* Implements AbstractPreferences childrenNamesSpi() method.
* Find all children nodes of this node (or of identically named nodes in
* storedDefaults)
*/
protected String[] childrenNamesSpi() {
HashSet allKids = new HashSet(children.keySet());
PreferencesExt sd = getStoredDefaults();
if (sd != null)
allKids.addAll( sd.childrenNamesSpi(absolutePath()));
ArrayList list = new ArrayList( allKids);
Collections.sort(list);
String result[] = new String[list.size()];
for (int i=0; i