package app.astrosoft.pref; import java.io.*; import java.util.*; import java.util.prefs.*; /** * An implementation of Preferences. There are issues with the default implementation * provided by Java, such as throwing endless exceptions due to invalid assumptions * about file permissions, this implementation does not have those problems. * <p> * Nodes are named using a / separated naming convention. The preferences are * stored in a tree-like structure, with the root node named "" per the * preferences specification. A node directly below the root node would be * referenced by a / followed by the node name, for example "/node0". Node below * the initial child nodes follow the same convention, so "/node0/child0/kid2" * references a node 3 levels below the root node. * <p> * To store a value, call one of the various <code>put</code> methods. For example, * to store a username, you might call <code>put("/myapp/userinfo/username", username)</code>. * To get the value, call one of the various <code>get</code> methods. For example, * to get the username, you might call <code>get("/myapp/userinfor/username", "")</code>. * <p> * Nodes are stored in $user.home/.ise_prefs. In this implementation, system nodes * are the same as user nodes. * @author Dale Anson, Jan 2004 */ public class UserPreferences extends AbstractPreferences { private Hashtable root; private Hashtable children; private boolean isRemoved = false; /** * Makes a node with <code>prefs</code> as parent and <code>name</code> as * the name of this node. As per the Preferences spec, if <code>prefs</code> * is null and <code>name</code> is "", this node will be a root node. * @param prefs parent preferences * @param name name for this node */ public UserPreferences( UserPreferences prefs, String name ) { super( prefs, name ); root = new Hashtable(); children = new Hashtable(); try { sync(); } catch ( Exception e ) { e.printStackTrace(); } } protected void putSpi( String key, String value ) { root.put( key, value ); } protected String getSpi( String key ) { return ( String ) root.get( key ); } protected void removeSpi( String key ) { root.remove( key ); } protected void removeNodeSpi() throws BackingStoreException { isRemoved = true; } protected String[] keysSpi() throws BackingStoreException { return ( String[] ) root.keySet().toArray( new String[] {} ); } protected String[] childrenNamesSpi() throws BackingStoreException { return ( String[] ) children.keySet().toArray( new String[] {} ); } protected AbstractPreferences childSpi( String name ) { UserPreferences child = ( UserPreferences ) children.get( name ); if ( child == null || child.isRemoved() ) { try { child = new UserPreferences( this, name ); children.put( name, child ); } catch ( Exception e ) { e.printStackTrace(); child = null; } } return child; } /** * Returns the directory in which this node stores values, creating the directory * and its parents if necessary. * @return the directory in which this node stores values. */ protected File getDirectory() { try { String name = name(); if ( name == null || name.equals( "" ) ) name = "root"; File dir; if ( parent() == null ) dir = UserPreferencesFactory.PREFS_ROOT; else dir = ( ( UserPreferences ) parent() ).getDirectory(); File my_dir = new File( dir, name ); my_dir.mkdirs(); return my_dir; } catch ( Exception e ) { //e.printStackTrace(); return null; } } protected void syncSpi() throws BackingStoreException { // no-op } public void sync() throws BackingStoreException { try { if ( isRemoved() ) { parent().sync(); return ; } if ( root == null ) { root = new Hashtable(); } File f = new File( getDirectory(), "prefs" ); if ( !f.exists() ) return ; ObjectInputStream decoder = new ObjectInputStream( new FileInputStream( f ) ); Hashtable map = ( Hashtable ) decoder.readObject(); decoder.close(); root.putAll( map ); } catch ( Exception e ) { //e.printStackTrace(); } } public void flushSpi() throws BackingStoreException { try { if ( root == null || root.size() == 0 ) { return ; } if ( isRemoved() ) { parent().flush(); return ; } File dir = getDirectory(); if ( dir == null ) throw new BackingStoreException( "Can't open directory." ); File f = new File( dir, "prefs" ); ObjectOutputStream encoder = new ObjectOutputStream( new FileOutputStream( f ) ); encoder.writeObject( root ); encoder.close(); } catch ( BackingStoreException bse ) { throw bse; } catch ( Exception e ) { // ignore } } protected boolean isRemoved() { return isRemoved; } }