FileDocCategorySizeDatePackage
AbstractPreferences.javaAPI DocAndroid 1.5 API31733Wed May 06 22:41:04 BST 2009java.util.prefs

AbstractPreferences

public abstract class AbstractPreferences extends Preferences
This abstract class is a partial implementation of the abstract class Preferences, which can be used to simplify {@code Preferences} provider's implementation. This class defines nine abstract SPI methods, which must be implemented by a preference provider.
since
Android 1.0

Fields Summary
private static final List
events
The unhandled events collection.
private static final EventDispatcher
dispatcher
The event dispatcher thread.
boolean
userNode
True, if this node is in user preference hierarchy.
protected final Object
lock
The object used to lock this node.
protected boolean
newNode
This field is true if this node is created while it doesn't exist in the backing store. This field's default value is false, and it is checked when the node creation is completed, and if it is true, the node change event will be fired for this node's parent.
private Map
cachedNode
Cached child nodes
private List
nodeChangeListeners
private List
preferenceChangeListeners
private String
nodeName
private AbstractPreferences
parentPref
private boolean
isRemoved
private AbstractPreferences
root
Constructors Summary
protected AbstractPreferences(AbstractPreferences parent, String name)
Constructs a new {@code AbstractPreferences} instance using the given parent node and node name.

param
parent the parent node of the new node or {@code null} to indicate that the new node is a root node.
param
name the name of the new node or an empty string to indicate that this node is called "root".
throws
IllegalArgumentException if the name contains a slash character or is empty if {@code parent} is not {@code null}.
since
Android 1.0

        if ((null == parent ^ name.length() == 0) || name.indexOf("/") >= 0) { //$NON-NLS-1$
            throw new IllegalArgumentException();
        }
        root = null == parent ? this : parent.root;
        nodeChangeListeners = new LinkedList<EventListener>();
        preferenceChangeListeners = new LinkedList<EventListener>();
        isRemoved = false;
        cachedNode = new HashMap<String, AbstractPreferences>();
        nodeName = name;
        parentPref = parent;
        lock = new Lock();
        userNode = root.userNode;
    
Methods Summary
public java.lang.StringabsolutePath()

        if (parentPref == null) {
            return "/"; //$NON-NLS-1$
        } else if (parentPref == root) {
            return "/" + nodeName; //$NON-NLS-1$
        }
        return parentPref.absolutePath() + "/" + nodeName; //$NON-NLS-1$
    
public voidaddNodeChangeListener(java.util.prefs.NodeChangeListener ncl)

        if (null == ncl) {
            throw new NullPointerException();
        }
        checkState();
        synchronized (nodeChangeListeners) {
            nodeChangeListeners.add(ncl);
        }
    
public voidaddPreferenceChangeListener(java.util.prefs.PreferenceChangeListener pcl)

        if (null == pcl) {
            throw new NullPointerException();
        }
        checkState();
        synchronized (preferenceChangeListeners) {
            preferenceChangeListeners.add(pcl);
        }
    
protected final java.util.prefs.AbstractPreferences[]cachedChildren()
Returns an array of all cached child nodes.

return
the array of cached child nodes.
since
Android 1.0

        return cachedNode.values().toArray(new AbstractPreferences[cachedNode.size()]);
    
private voidcheckState()

        if (isRemoved()) {
            // prefs.9=This node has been removed\!
            throw new IllegalStateException(Messages.getString("prefs.9"));  //$NON-NLS-1$
        }
    
protected abstract java.util.prefs.AbstractPreferenceschildSpi(java.lang.String name)
Returns the child preference node with the given name, creating it if it does not exist. The caller of this method should ensure that the given name is valid and that this node has not been removed or cached. If the named node has just been removed, the implementation of this method must create a new one instead of reactivating the removed one.

The new creation is not required to be persisted immediately until the flush method will be invoked.

param
name the name of the child preference to be returned.
return
the child preference node.
since
Android 1.0

public java.lang.String[]childrenNames()

        synchronized (lock) {
            checkState();
            TreeSet<String> result = new TreeSet<String>(cachedNode.keySet());
            String[] names = childrenNamesSpi();
            for (int i = 0; i < names.length; i++) {
                result.add(names[i]);
            }
            return result.toArray(new String[0]);
        }
    
protected abstract java.lang.String[]childrenNamesSpi()
Returns the names of all of the child nodes of this node or an empty array if this node has no children. The names of cached children are not required to be returned.

return
the names of this node's children.
throws
BackingStoreException if the backing store is unavailable or causes an operation failure.
since
Android 1.0

public voidclear()

        synchronized (lock) {
            String[] keyList = keys();
            for (int i = 0; i < keyList.length; i++) {
                remove(keyList[i]);
            }
        }
    
public voidexportNode(java.io.OutputStream ostream)

        if(ostream == null) {
            // prefs.5=Stream is null
            throw new NullPointerException(Messages.getString("prefs.5"));  //$NON-NLS-1$
        }
        checkState();
        XMLParser.exportPrefs(this, ostream, false);

    
public voidexportSubtree(java.io.OutputStream ostream)

        if(ostream == null) {
            // prefs.5=Stream is null
            throw new NullPointerException(Messages.getString("prefs.5"));  //$NON-NLS-1$
        }
        checkState();
        XMLParser.exportPrefs(this, ostream, true);
    
public voidflush()

        synchronized (lock) {
            flushSpi();
        }
        AbstractPreferences[] cc = cachedChildren();
        int i;
        for (i = 0; i < cc.length; i++) {
            cc[i].flush();
        }
    
protected abstract voidflushSpi()
Flushes changes of this node to the backing store. This method should only flush this node and should not include the descendant nodes. Any implementation that wants to provide functionality to flush all nodes at once should override the method {@link #flush() flush()}.

throws
BackingStoreException if the backing store is unavailable or causes an operation failure.
since
Android 1.0

public java.lang.Stringget(java.lang.String key, java.lang.String deflt)

        if (key == null) {
            throw new NullPointerException();
        }
        String result;
        synchronized (lock) {
            checkState();
            try {
                result = getSpi(key);
            } catch (Exception e) {
                result = null;
            }
        }
        return (result == null ? deflt : result);
    
public booleangetBoolean(java.lang.String key, boolean deflt)

        String result = get(key, null);
        if (result == null) {
            return deflt;
        } else if (result.equalsIgnoreCase("true")) { //$NON-NLS-1$
            return true;
        } else if (result.equalsIgnoreCase("false")) { //$NON-NLS-1$
            return false;
        } else {
            return deflt;
        }
    
public byte[]getByteArray(java.lang.String key, byte[] deflt)

        String svalue = get(key, null);
        if (svalue == null) {
            return deflt;
        }
        if (svalue.length() == 0) { 
            return new byte[0];
        }
        byte[] dres;
        try {
            byte[] bavalue = svalue.getBytes("US-ASCII"); //$NON-NLS-1$
            if (bavalue.length % 4 != 0) {
                return deflt;
            }
            dres = Base64.decode(bavalue);
        } catch (Exception e) {
            dres = deflt;
        }
        return dres;
    
protected java.util.prefs.AbstractPreferencesgetChild(java.lang.String name)
Returns the child node with the specified name or {@code null} if it doesn't exist. Implementers can assume that the name supplied to this method will be a valid node name string (conforming to the node naming format) and will not correspond to a node that has been cached or removed.

param
name the name of the desired child node.
return
the child node with the given name or {@code null} if it doesn't exist.
throws
BackingStoreException if the backing store is unavailable or causes an operation failure.
since
Android 1.0

        synchronized (lock) {
            checkState();
            AbstractPreferences result = null;
            String[] childrenNames = childrenNames();
            for (int i = 0; i < childrenNames.length; i++) {
                if (childrenNames[i].equals(name)) {
                    result = childSpi(name);
                    break;
                }
            }
            return result;
        }

    
public doublegetDouble(java.lang.String key, double deflt)

        String result = get(key, null);
        if (result == null) {
            return deflt;
        }
        double dres;
        try {
            dres = Double.parseDouble(result);
        } catch (NumberFormatException e) {
            dres = deflt;
        }
        return dres;
    
public floatgetFloat(java.lang.String key, float deflt)

        String result = get(key, null);
        if (result == null) {
            return deflt;
        }
        float fres;
        try {
            fres = Float.parseFloat(result);
        } catch (NumberFormatException e) {
            fres = deflt;
        }
        return fres;
    
public intgetInt(java.lang.String key, int deflt)

        String result = get(key, null);
        if (result == null) {
            return deflt;
        }
        int ires;
        try {
            ires = Integer.parseInt(result);
        } catch (NumberFormatException e) {
            ires = deflt;
        }
        return ires;
    
public longgetLong(java.lang.String key, long deflt)

        String result = get(key, null);
        if (result == null) {
            return deflt;
        }
        long lres;
        try {
            lres = Long.parseLong(result);
        } catch (NumberFormatException e) {
            lres = deflt;
        }
        return lres;
    
private java.util.prefs.AbstractPreferencesgetNodeFromBackend(boolean createNew, java.util.prefs.AbstractPreferences currentNode, java.lang.String name)

        AbstractPreferences temp;
        if (name.length() > MAX_NAME_LENGTH) {
            // prefs.8=Name length is too long: {0}
            throw new IllegalArgumentException(Messages.getString("prefs.8",  //$NON-NLS-1$
                    name));
        }
        if (createNew) {
            temp = currentNode.childSpi(name);
            currentNode.cachedNode.put(name, temp);
            if (temp.newNode && currentNode.nodeChangeListeners.size() > 0) {
                currentNode.notifyChildAdded(temp);
            }
        } else {
            temp = currentNode.getChild(name);
        }
        return temp;
    
protected abstract java.lang.StringgetSpi(java.lang.String key)
Gets the preference value mapped to the given key. The caller of this method should ensure that the given key is valid and that this node has not been removed. This method should not throw any exceptions but if it does, the caller will ignore the exception, regarding it as a {@code null} return value.

param
key the given key to be searched for.
return
the preference value mapped to the given key.
since
Android 1.0

protected booleanisRemoved()
Returns whether this node has been removed by invoking the method {@code removeNode()}.

return
{@code true}, if this node has been removed, {@code false} otherwise.
since
Android 1.0

        synchronized (lock) {
            return isRemoved;
        }
    
public booleanisUserNode()

        return root == Preferences.userRoot();
    
public java.lang.String[]keys()

        synchronized (lock) {
            checkState();
            return keysSpi();
        }
    
protected abstract java.lang.String[]keysSpi()
Returns an array of all preference keys of this node or an empty array if no preferences have been found. The caller of this method should ensure that this node has not been removed.

return
the array of all preference keys.
throws
BackingStoreException if the backing store is unavailable or causes an operation failure.
since
Android 1.0

public java.lang.Stringname()

        return nodeName;
    
public java.util.prefs.Preferencesnode(java.lang.String name)

        AbstractPreferences startNode = null;
        synchronized (lock) {
            checkState();
            validateName(name);
            if ("".equals(name)) { //$NON-NLS-1$
                return this;
            } else if ("/".equals(name)) { //$NON-NLS-1$
                return root;
            }
            if (name.startsWith("/")) { //$NON-NLS-1$
                startNode = root;
                name = name.substring(1);
            } else {
                startNode = this;
            }
        }
        Preferences result = null;
        try {
            result = startNode.nodeImpl(name, true);
        } catch (BackingStoreException e) {
            //should not happen
        }
        return result;
    
public booleannodeExists(java.lang.String name)

        AbstractPreferences startNode = null;
        synchronized (lock) {
            if (isRemoved()) {
                if ("".equals(name)) { //$NON-NLS-1$
                    return false;
                }
                // prefs.9=This node has been removed\!
                throw new IllegalStateException(Messages.getString("prefs.9"));  //$NON-NLS-1$
            }
            validateName(name);
            if ("".equals(name) || "/".equals(name)) { //$NON-NLS-1$ //$NON-NLS-2$
                return true;
            }
            if (name.startsWith("/")) { //$NON-NLS-1$
                startNode = root;
                name = name.substring(1);
            } else {
                startNode = this;
            }
        }
        try {
            Preferences result = startNode.nodeImpl(name, false);
            return null == result ? false : true;
        } catch(IllegalArgumentException e) {
            return false;
        }
    
private java.util.prefs.AbstractPreferencesnodeImpl(java.lang.String path, boolean createNew)

        StringTokenizer st = new StringTokenizer(path, "/"); //$NON-NLS-1$
        AbstractPreferences currentNode = this;
        AbstractPreferences temp = null;
        while (st.hasMoreTokens() && null != currentNode) {
            String name = st.nextToken();
            synchronized (currentNode.lock) {
                temp = currentNode.cachedNode.get(name);
                if (temp == null) {
                    temp = getNodeFromBackend(createNew, currentNode, name);
                }
            }

            currentNode = temp;
        }
        return currentNode;
    
private voidnotifyChildAdded(java.util.prefs.Preferences child)

        NodeChangeEvent nce = new NodeAddEvent(this, child);
        synchronized (events) {
            events.add(nce);
            events.notifyAll();
        }
    
private voidnotifyChildRemoved(java.util.prefs.Preferences child)

        NodeChangeEvent nce = new NodeRemoveEvent(this, child);
        synchronized (events) {
            events.add(nce);
            events.notifyAll();
        }
    
private voidnotifyPreferenceChange(java.lang.String key, java.lang.String newValue)

        PreferenceChangeEvent pce = new PreferenceChangeEvent(this, key,
                newValue);
        synchronized (events) {
            events.add(pce);
            events.notifyAll();
        }
    
public java.util.prefs.Preferencesparent()

        checkState();
        return parentPref;
    
public voidput(java.lang.String key, java.lang.String value)

        if (null == key || null == value) {
            throw new NullPointerException();
        }
        if (key.length() > MAX_KEY_LENGTH || value.length() > MAX_VALUE_LENGTH) {
            throw new IllegalArgumentException();
        }
        synchronized (lock) {
            checkState();
            putSpi(key, value);
        }
        notifyPreferenceChange(key, value);
    
public voidputBoolean(java.lang.String key, boolean value)

        String sval = String.valueOf(value);
        put(key, sval);
    
public voidputByteArray(java.lang.String key, byte[] value)

        try {
            put(key, Base64.encode(value, "US-ASCII")); //$NON-NLS-1$
        } catch (UnsupportedEncodingException e) {
            throw new AssertionError(e);
        }
    
public voidputDouble(java.lang.String key, double value)

        String sval = Double.toString(value);
        put(key, sval);
    
public voidputFloat(java.lang.String key, float value)

        String sval = Float.toString(value);
        put(key, sval);
    
public voidputInt(java.lang.String key, int value)

        String sval = Integer.toString(value);
        put(key, sval);
    
public voidputLong(java.lang.String key, long value)

        String sval = Long.toString(value);
        put(key, sval);
    
protected abstract voidputSpi(java.lang.String name, java.lang.String value)
Puts the given key-value pair into this node. Caller of this method should ensure that both of the given values are valid and that this node has not been removed.

param
name the given preference key.
param
value the given preference value.
since
Android 1.0

public voidremove(java.lang.String key)

        synchronized (lock) {
            checkState();
            removeSpi(key);
        }
        notifyPreferenceChange(key, null);
    
public voidremoveNode()

        if (root == this) {
            // prefs.A=Cannot remove root node\!
            throw new UnsupportedOperationException(Messages.getString("prefs.A"));  //$NON-NLS-1$
        }
        synchronized (parentPref.lock) {
            removeNodeImpl();
        }
    
public voidremoveNodeChangeListener(java.util.prefs.NodeChangeListener ncl)

        checkState();
        synchronized (nodeChangeListeners) {
            int pos;
            if ((pos = nodeChangeListeners.indexOf(ncl)) == -1) {
                throw new IllegalArgumentException();
            }
            nodeChangeListeners.remove(pos);
        }
    
private voidremoveNodeImpl()

        synchronized (lock) {
            checkState();
            String[] childrenNames = childrenNamesSpi();
            for (int i = 0; i < childrenNames.length; i++) {
                if (null == cachedNode.get(childrenNames[i])) {
                    AbstractPreferences child = childSpi(childrenNames[i]);
                    cachedNode.put(childrenNames[i], child);
                }
            }
            AbstractPreferences[] children = cachedNode
                    .values().toArray(new AbstractPreferences[0]);
            for (int i = 0; i < children.length; i++) {
                children[i].removeNodeImpl();
            }
            removeNodeSpi();
            isRemoved = true;
            parentPref.cachedNode.remove(nodeName);
        }
        if (parentPref.nodeChangeListeners.size() > 0) {
            parentPref.notifyChildRemoved(this);
        }
    
protected abstract voidremoveNodeSpi()
Removes this node from the preference hierarchy tree. The caller of this method should ensure that this node has no child nodes, which means the method {@link Preferences#removeNode() Preferences.removeNode()} should invoke this method multiple-times in bottom-up pattern. The removal is not required to be persisted until after it is flushed.

throws
BackingStoreException if the backing store is unavailable or causes an operation failure.
since
Android 1.0

public voidremovePreferenceChangeListener(java.util.prefs.PreferenceChangeListener pcl)

        checkState();
        synchronized (preferenceChangeListeners) {
            int pos;
            if ((pos = preferenceChangeListeners.indexOf(pcl)) == -1) {
                throw new IllegalArgumentException();
            }
            preferenceChangeListeners.remove(pos);
        }
    
protected abstract voidremoveSpi(java.lang.String key)
Removes the preference with the specified key. The caller of this method should ensure that the given key is valid and that this node has not been removed.

param
key the key of the preference that is to be removed.
since
Android 1.0

public voidsync()

        synchronized (lock) {
            checkState();
            syncSpi();
        }
        AbstractPreferences[] cc = cachedChildren();
        int i;
        for (i = 0; i < cc.length; i++) {
            cc[i].sync();
        }
    
protected abstract voidsyncSpi()
Synchronizes this node with the backing store. This method should only synchronize this node and should not include the descendant nodes. An implementation that wants to provide functionality to synchronize all nodes at once should override the method {@link #sync() sync()}.

throws
BackingStoreException if the backing store is unavailable or causes an operation failure.
since
Android 1.0

public java.lang.StringtoString()

        StringBuffer sb = new StringBuffer();
        sb.append(isUserNode() ? "User" : "System"); //$NON-NLS-1$ //$NON-NLS-2$
        sb.append(" Preference Node: "); //$NON-NLS-1$
        sb.append(absolutePath());
        return sb.toString();
    
private voidvalidateName(java.lang.String name)

        if (name.endsWith("/") && name.length() > 1) { //$NON-NLS-1$
            // prefs.6=Name cannot end with '/'\!
            throw new IllegalArgumentException(Messages.getString("prefs.6"));  //$NON-NLS-1$
        }
        if (name.indexOf("//") >= 0) { //$NON-NLS-1$
            // prefs.7=Name cannot contains consecutive '/'\!
            throw new IllegalArgumentException(
                    Messages.getString("prefs.7"));  //$NON-NLS-1$
        }