/* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package java.util.prefs;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.MalformedURLException;
import java.util.ServiceLoader;
/**
* An instance of the class {@code Preferences} represents one node in a
* preference tree, which provides a mechanism to store and access configuration
* data in a hierarchical way. Two hierarchy trees are maintained, one for
* system preferences shared by all users and the other for user preferences
* specific to the user. {@code Preferences} hierarchy trees and data are stored
* in an implementation-dependent back-end.
* <p>
* Every node has one name and one unique absolute path following the same
* notational conventions as directories in a file system. The root node's
* name is "", and other node name strings cannot contain the slash character
* and cannot be empty. The root node's absolute path is "/", and all other
* nodes' absolute paths are constructed in the standard way: <parent's
* absolute path> + "/" + <node's name>. Since the set of nodes forms a
* tree with the root node at its base, all absolute paths start with the slash
* character. Every node has one relative path to each of its ancestors. The
* relative path doesn't start with slash: it equals the node's absolute path
* with leading substring removed corresponding to the ancestor's absolute path
* and a slash.
* <p>
* Modification to preferences data may be asynchronous, which means that
* preference update method calls may return immediately instead of blocking.
* The {@code flush()} and {@code sync()} methods force the back-end to
* synchronously perform all pending updates, but the implementation is
* permitted to perform the modifications on the underlying back-end data
* at any time between the moment the request is made and the moment the
* {@code flush()} or {@code sync()} method returns. Please note that if the JVM
* exits normally, the implementation must assure all modifications are
* persisted implicitly.
* <p>
* When invoking a method that retrieves preferences, the user must provide
* a default value. The default value is returned when the preferences cannot
* be found or the back-end is unavailable. Some other methods will throw
* {@code BackingStoreException} when the back-end is unavailable.
* </p>
* <p>
* Preferences can be exported to and imported from an XML files. These
* documents must have an XML DOCTYPE declaration:
* <pre>{@code
* <!DOCTYPE preferences SYSTEM "http://java.sun.com/dtd/preferences.dtd">
* }</pre>
* This system URI is not really accessed by network, it is only a
* identification string. Visit the DTD location to see the actual format
* permitted.
* <p>
* There must be a concrete {@code PreferencesFactory} type for every concrete
* {@code Preferences} type developed. Every J2SE implementation must provide a
* default implementation for every supported platform, and must also provide a
* means of replacing the default implementation. This implementation uses the
* system property {@code java.util.prefs.PreferencesFactory} to determine which
* preferences implementation to use.
* <p>
* The methods of this class are thread-safe. If multiple JVMs are using the
* same back-end concurrently, the back-end won't be corrupted, but no other
* behavior guarantees are made.
*
* @see PreferencesFactory
*
* @since 1.4
*/
public abstract class Preferences {
/**
* Maximum size in characters allowed for a preferences key.
*/
public static final int MAX_KEY_LENGTH = 80;
/**
* Maximum size in characters allowed for a preferences name.
*/
public static final int MAX_NAME_LENGTH = 80;
/**
* Maximum size in characters allowed for a preferences value.
*/
public static final int MAX_VALUE_LENGTH = 8192;
// factory used to get user/system prefs root
private static volatile PreferencesFactory factory = findPreferencesFactory();
/**
* @hide for testing only.
*/
public static PreferencesFactory setPreferencesFactory(PreferencesFactory pf) {
PreferencesFactory previous = factory;
factory = pf;
return previous;
}
private static PreferencesFactory findPreferencesFactory() {
// Try the system property first...
PreferencesFactory result = ServiceLoader.loadFromSystemProperty(PreferencesFactory.class);
if (result != null) {
return result;
}
// Then use ServiceLoader for META-INF/services/...
for (PreferencesFactory impl : ServiceLoader.load(PreferencesFactory.class)) {
return impl;
}
// Finally return a default...
return new FilePreferencesFactoryImpl();
}
/**
* Default constructor, for use by subclasses only.
*/
protected Preferences() {
}
/**
* Gets the absolute path string of this preference node.
*
* @return the preference node's absolute path string.
*/
public abstract String absolutePath();
/**
* Returns the names of all children of this node or an empty array if this
* node has no children.
*
* @return the names of all children of this node.
* @throws BackingStoreException
* if backing store is unavailable or causes an operation
* failure.
* @throws IllegalStateException
* if this node has been removed.
*/
public abstract String[] childrenNames() throws BackingStoreException;
/**
* Removes all preferences of this node.
*
* @throws BackingStoreException
* if backing store is unavailable or causes an operation
* failure.
* @throws IllegalStateException
* if this node has been removed.
*/
public abstract void clear() throws BackingStoreException;
/**
* Exports all of the preferences of this node to a XML document using the
* given output stream.
* <p>
* This XML document uses the UTF-8 encoding and is written according to the
* DTD in its DOCTYPE declaration, which is the following:
*
* <pre>
* <!DOCTYPE preferences SYSTEM "http://java.sun.com/dtd/preferences.dtd">
* </pre>
*
* <i>Please note that (unlike the methods of this class that don't concern
* serialization), this call is not thread-safe.</i>
* </p>
*
* @param ostream
* the output stream to write the XML-formatted data to.
* @throws IOException
* if an error occurs while exporting.
* @throws BackingStoreException
* if the backing store is unavailable or causes an operation
* failure.
* @throws IllegalStateException
* if this node has been removed.
*/
public abstract void exportNode(OutputStream ostream) throws IOException, BackingStoreException;
/**
* Exports all of the preferences of this node and all its descendants to a
* XML document using the given output stream.
* <p>
* This XML document uses the UTF-8 encoding and is written according to the
* DTD in its DOCTYPE declaration, which is the following:
*
* <pre>
* <!DOCTYPE preferences SYSTEM "http://java.sun.com/dtd/preferences.dtd">
* </pre>
*
* <i>Please note that (unlike the methods of this class that don't concern
* serialization), this call is not thread-safe.</i>
* </p>
*
* @param ostream
* the output stream to write the XML-formatted data to.
* @throws IOException
* if an error occurs while exporting.
* @throws BackingStoreException
* if the backing store is unavailable or causes an operation
* failure.
* @throws IllegalStateException
* if this node has been removed.
*/
public abstract void exportSubtree(OutputStream ostream) throws IOException,
BackingStoreException;
/**
* Forces all pending updates to this node and its descendants to be
* persisted in the backing store.
* <p>
* If this node has been removed, the invocation of this method only flushes
* this node, not its descendants.
* </p>
*
* @throws BackingStoreException
* if the backing store is unavailable or causes an operation
* failure.
*/
public abstract void flush() throws BackingStoreException;
/**
* Gets the {@code String} value mapped to the given key or its default
* value if no value is mapped or no backing store is available.
* <p>
* Some implementations may store default values in backing stores. In this
* case, if there is no value mapped to the given key, the stored default
* value is returned.
* </p>
*
* @param key
* the preference key.
* @param deflt
* the default value, which will be returned if no value is
* mapped to the given key or no backing store is available.
* @return the preference value mapped to the given key.
* @throws IllegalStateException
* if this node has been removed.
* @throws NullPointerException
* if the parameter {@code key} is {@code null}.
*/
public abstract String get(String key, String deflt);
/**
* Gets the {@code boolean} value mapped to the given key or its default
* value if no value is mapped, if the backing store is unavailable, or if
* the value is invalid.
* <p>
* The only valid values are the {@code String} "true", which represents
* {@code true} and "false", which represents {@code false}, ignoring case.
* </p>
* <p>
* Some implementations may store default values in backing stores. In this
* case, if there is no value mapped to the given key, the stored default
* value is returned.
* </p>
*
* @param key
* the preference key.
* @param deflt
* the default value, which will be returned if no value is
* mapped to the given key, if the backing store is unavailable,
* or if the value is invalid.
* @return the boolean value mapped to the given key.
* @throws IllegalStateException
* if this node has been removed.
* @throws NullPointerException
* if the parameter {@code key} is {@code null}.
*/
public abstract boolean getBoolean(String key, boolean deflt);
/**
* Gets the {@code byte} array value mapped to the given key or its default
* value if no value is mapped, if the backing store is unavailable, or if
* the value is an invalid string.
* <p>
* To be valid, the value string must be Base64-encoded binary data. The
* Base64 encoding is as defined in <a
* href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045</a>, section 6.8.
* </p>
* <p>
* Some implementations may store default values in backing stores. In this
* case, if there is no value mapped to the given key, the stored default
* value is returned.
* </p>
*
* @param key
* the preference key.
* @param deflt
* the default value, which will be returned if no value is
* mapped to the given key, if the backing store is unavailable,
* or if the value is invalid.
* @return the byte array value mapped to the given key.
* @throws IllegalStateException
* if this node has been removed.
* @throws NullPointerException
* if the parameter {@code key} is {@code null}.
*/
public abstract byte[] getByteArray(String key, byte[] deflt);
/**
* Gets the {@code double} value mapped to the given key or its default
* value if no value is mapped, if the backing store is unavailable, or if
* the value is an invalid string.
* <p>
* To be valid, the value string must be a string that can be converted to a
* {@code double} by {@link Double#parseDouble(String)
* Double.parseDouble(String)}.
* <p>
* Some implementations may store default values in backing stores. In this
* case, if there is no value mapped to the given key, the stored default
* value is returned.
* </p>
*
* @param key
* the preference key.
* @param deflt
* the default value, which will be returned if no value is
* mapped to the given key, if the backing store is unavailable, or if the
* value is invalid.
* @return the double value mapped to the given key.
* @throws IllegalStateException
* if this node has been removed.
* @throws NullPointerException
* if the parameter {@code key} is {@code null}.
*/
public abstract double getDouble(String key, double deflt);
/**
* Gets the {@code float} value mapped to the given key or its default value
* if no value is mapped, if the backing store is unavailable, or if the
* value is an invalid string.
* <p>
* To be valid, the value string must be a string that can be converted to a
* {@code float} by {@link Float#parseFloat(String)
* Float.parseFloat(String)}.
* </p>
* <p>
* Some implementations may store default values in backing stores. In this
* case, if there is no value mapped to the given key, the stored default
* value is returned.
* </p>
*
* @param key
* the preference key.
* @param deflt
* the default value, which will be returned if no value is
* mapped to the given key, if the backing store is unavailable, or if the
* value is invalid.
* @return the float value mapped to the given key.
* @throws IllegalStateException
* if this node has been removed.
* @throws NullPointerException
* if the parameter {@code key} is {@code null}.
*/
public abstract float getFloat(String key, float deflt);
/**
* Gets the {@code int} value mapped to the given key or its default value
* if no value is mapped, if the backing store is unavailable, or if the
* value is an invalid string.
* <p>
* To be valid, the value string must be a string that can be converted to
* an {@code int} by {@link Integer#parseInt(String)
* Integer.parseInt(String)}.
* </p>
* <p>
* Some implementations may store default values in backing stores. In this
* case, if there is no value mapped to the given key, the stored default
* value is returned.
* </p>
*
* @param key
* the preference key.
* @param deflt
* the default value, which will be returned if no value is
* mapped to the given key, if the backing store is unavailable,
* or if the value is invalid.
* @return the integer value mapped to the given key.
* @throws IllegalStateException
* if this node has been removed.
* @throws NullPointerException
* if the parameter {@code key} is {@code null}.
*/
public abstract int getInt(String key, int deflt);
/**
* Gets the {@code long} value mapped to the given key or its default value
* if no value is mapped, if the backing store is unavailable, or if the
* value is an invalid string.
* <p>
* To be valid, the value string must be a string that can be converted to a
* {@code long} by {@link Long#parseLong(String) Long.parseLong(String)}.
* </p>
* <p>
* Some implementations may store default values in backing stores. In this
* case, if there is no value mapped to the given key, the stored default
* value is returned.
* </p>
*
* @param key
* the preference key.
* @param deflt
* the default value, which will be returned if no value is
* mapped to the given key, if the backing store is unavailable,
* or if the value is invalid.
* @return the long value mapped to the given key.
* @throws IllegalStateException
* if this node has been removed.
* @throws NullPointerException
* if the parameter {@code key} is {@code null}.
*/
public abstract long getLong(String key, long deflt);
/**
* Imports all the preferences from an XML document using the given input
* stream.
* <p>
* This XML document uses the UTF-8 encoding and must be written according
* to the DTD in its DOCTYPE declaration, which must be the following:
*
* <pre>
* <!DOCTYPE preferences SYSTEM "http://java.sun.com/dtd/preferences.dtd">
* </pre>
*
* <i>Please note that (unlike the methods of this class that don't concern
* serialization), this call is not thread-safe.</i>
* </p>
*
* @param istream
* the input stream to read the data from.
* @throws InvalidPreferencesFormatException
* if the data read from the given input stream is not from a
* valid XML document.
* @throws IOException
* if an error occurs while importing.
*/
public static void importPreferences (InputStream istream) throws InvalidPreferencesFormatException, IOException {
if (istream == null){
throw new MalformedURLException("Inputstream cannot be null");
}
XMLParser.importPrefs(istream);
}
/**
* Returns whether this is a user preference node.
*
* @return {@code true}, if this is a user preference node, {@code false} if
* this is a system preference node.
*/
public abstract boolean isUserNode();
/**
* Returns all preference keys stored in this node or an empty array if no
* key was found.
*
* @return the list of all preference keys of this node.
* @throws BackingStoreException
* if the backing store is unavailable or causes an operation
* failure.
* @throws IllegalStateException
* if this node has been removed.
*/
public abstract String[] keys() throws BackingStoreException;
/**
* Returns the name of this node.
*
* @return the name of this node.
*/
public abstract String name();
/**
* Returns the preference node with the given path name. The path name can
* be relative or absolute. The requested node and its ancestors will
* be created if they do not exist.
* <p>
* The path is treated as relative to this node if it doesn't start with a
* slash, otherwise it will be treated as an absolute path.
* </p>
*
* @param path
* the path name of the requested preference node.
* @return the requested preference node.
* @throws IllegalStateException
* if this node has been removed.
* @throws IllegalArgumentException
* if the path name is invalid.
* @throws NullPointerException
* if the given path is {@code null}.
*/
public abstract Preferences node(String path);
/**
* Returns whether the preference node with the given path name exists. The
* path is treated as relative to this node if it doesn't start with a slash,
* otherwise it is treated as an absolute path.
* <p>
* Please note that if this node has been removed, an invocation of this
* node will throw an {@code IllegalStateException} unless the given path is
* an empty string, which will return {@code false}.
* </p>
*
* @param path
* the path name of the preference node to query.
* @return {@code true}, if the queried preference node exists, {@code false}
* otherwise.
* @throws IllegalStateException
* if this node has been removed and the path is not an empty
* string.
* @throws IllegalArgumentException
* if the path name is invalid.
* @throws NullPointerException
* if the given path is {@code null}.
* @throws BackingStoreException
* if the backing store is unavailable or causes an operation
* failure.
*/
public abstract boolean nodeExists(String path) throws BackingStoreException;
/**
* Returns the parent preference node of this node or {@code null} if this
* node is the root node.
*
* @return the parent preference node of this node.
* @throws IllegalStateException
* if this node has been removed.
*/
public abstract Preferences parent();
/**
* Adds a new preference to this node using the given key and value or
* updates the value if a preference with the given key already exists.
*
* @param key
* the preference key to be added or updated.
* @param value
* the preference value for the given key.
* @throws NullPointerException
* if the given key or value is {@code null}.
* @throws IllegalArgumentException
* if the given key's length is bigger than {@code
* MAX_KEY_LENGTH} or the value's length is bigger than {@code
* MAX_VALUE_LENGTH}.
* @throws IllegalStateException
* if this node has been removed.
*/
public abstract void put(String key, String value);
/**
* Adds a new preference with a {@code boolean} value to this node using the
* given key and value or updates the value if a preference with the given
* key already exists.
*
* @param key
* the preference key to be added or updated.
* @param value
* the preference {@code boolean} value for the given key.
* @throws NullPointerException
* if the given key is {@code null}.
* @throws IllegalArgumentException
* if the given key's length is bigger than {@code
* MAX_KEY_LENGTH}.
* @throws IllegalStateException
* if this node has been removed.
*/
public abstract void putBoolean(String key, boolean value);
/**
* Adds a new preference to this node using the given key and the string
* form of the given value or updates the value if a preference with the
* given key already exists.
* <p>
* The string form of the value is the Base64-encoded binary data of the
* given byte array. The Base64 encoding is as defined in <a
* href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045</a>, section 6.8.
* </p>
*
* @param key
* the preference key to be added or updated.
* @param value
* the preference value for the given key.
* @throws NullPointerException
* if the given key or value is {@code null}.
* @throws IllegalArgumentException
* if the given key's length is bigger than {@code
* MAX_KEY_LENGTH} or value's length is bigger than three
* quarters of {@code MAX_KEY_LENGTH}.
* @throws IllegalStateException
* if this node has been removed.
*/
public abstract void putByteArray(String key, byte[] value);
/**
* Adds a new preference to this node using the given key and {@code double}
* value or updates the value if a preference with the
* given key already exists.
* <p>
* The value is stored in its string form, which is the result of invoking
* {@link Double#toString(double) Double.toString(double)}.
* </p>
*
* @param key
* the preference key to be added or updated.
* @param value
* the preference value for the given key.
* @throws NullPointerException
* if the given key is {@code null}.
* @throws IllegalArgumentException
* if the given key's length is bigger than {@code
* MAX_KEY_LENGTH}.
* @throws IllegalStateException
* if this node has been removed.
*/
public abstract void putDouble(String key, double value);
/**
* Adds a new preference to this node using the given key and {@code float}
* value or updates the value if a preference with the
* given key already exists.
* <p>
* The value is stored in its string form, which is the result of invoking
* {@link Float#toString(float) Float.toString(float)}.
* </p>
*
* @param key
* the preference key to be added or updated.
* @param value
* the preference value for the given key.
* @throws NullPointerException
* if the given key is {@code null}.
* @throws IllegalArgumentException
* if the given key's length is bigger than {@code
* MAX_KEY_LENGTH}.
* @throws IllegalStateException
* if this node has been removed.
*/
public abstract void putFloat(String key, float value);
/**
* Adds a new preference to this node using the given key and {@code int}
* value or updates the value if a preference with the
* given key already exists.
* <p>
* The value is stored in its string form, which is the result of invoking
* {@link Integer#toString(int) Integer.toString(int)}.
* </p>
*
* @param key
* the preference key to be added or updated.
* @param value
* the preference value for the given key.
* @throws NullPointerException
* if the given key is {@code null}.
* @throws IllegalArgumentException
* if the given key's length is bigger than {@code
* MAX_KEY_LENGTH}.
* @throws IllegalStateException
* if this node has been removed.
*/
public abstract void putInt(String key, int value);
/**
* Adds a new preference to this node using the given key and {@code long}
* value or updates the value if a preference with the
* given key already exists.
* <p>
* The value is stored in its string form, which is the result of invoking
* {@link Long#toString(long) Long.toString(long)}.
* </p>
*
* @param key
* the preference key to be added or updated.
* @param value
* the preference value for the given key.
* @throws NullPointerException
* if the given key is {@code null}.
* @throws IllegalArgumentException
* if the given key's length is bigger than {@code
* MAX_KEY_LENGTH}.
* @throws IllegalStateException
* if this node has been removed.
*/
public abstract void putLong(String key, long value);
/**
* Removes the preference mapped to the given key from this node.
*
* @param key
* the key of the preference to be removed.
* @throws NullPointerException
* if the given key is {@code null}.
* @throws IllegalStateException
* if this node has been removed.
*/
public abstract void remove(String key);
/**
* Removes this preference node with all its descendants. The removal won't
* necessarily be persisted until the method {@code flush()} is invoked.
*
* @throws BackingStoreException
* if the backing store is unavailable or causes an operation
* failure.
* @throws IllegalStateException
* if this node has been removed.
* @throws UnsupportedOperationException
* if this is a root node.
*/
public abstract void removeNode() throws BackingStoreException;
/**
* Registers a {@code NodeChangeListener} instance for this node, which will
* handle {@code NodeChangeEvent}s. {@code NodeChangeEvent}s will be fired
* when a child node has been added to or removed from this node.
*
* @param ncl
* the listener to be registered.
* @throws NullPointerException
* if the given listener is {@code null}.
* @throws IllegalStateException
* if this node has been removed.
*/
public abstract void addNodeChangeListener(NodeChangeListener ncl);
/**
* Registers a {@code PreferenceChangeListener} instance for this node,
* which will handle {@code PreferenceChangeEvent}s. {@code
* PreferenceChangeEvent}s will be fired when a preference has been added
* to, removed from, or updated for this node.
*
* @param pcl
* the listener to be registered.
* @throws NullPointerException
* if the given listener is {@code null}.
* @throws IllegalStateException
* if this node has been removed.
*/
public abstract void addPreferenceChangeListener (PreferenceChangeListener pcl);
/**
* Removes the given {@code NodeChangeListener} instance from this node.
*
* @param ncl
* the listener to be removed.
* @throws IllegalArgumentException
* if the given listener is {@code null}.
* @throws IllegalStateException
* if this node has been removed.
*/
public abstract void removeNodeChangeListener (NodeChangeListener ncl);
/**
* Removes the given {@code PreferenceChangeListener} instance from this
* node.
*
* @param pcl
* the listener to be removed.
* @throws IllegalArgumentException
* if the given listener is {@code null}.
* @throws IllegalStateException
* if this node has been removed.
*/
public abstract void removePreferenceChangeListener (PreferenceChangeListener pcl);
/**
* Synchronizes the data of this preference node and its descendants with
* the back-end preference store. Any changes found in the back-end data
* should be reflected in this node and its descendants, and at the same
* time any local changes to this node and descendants should be persisted.
*
* @throws BackingStoreException
* if the backing store is unavailable or causes an operation
* failure.
* @throws IllegalStateException
* if this node has been removed.
*/
public abstract void sync() throws BackingStoreException;
/**
* <strong>Legacy code; do not use.</strong> On Android, the Preference nodes
* corresponding to the "system" and "user" preferences are stored in sections
* of the file system that are inaccessible to apps. Further, allowing apps to set
* "system wide" preferences is contrary to android's security model.
*
* Returns the system preference node for the package of the given class.
* The absolute path of the returned node is one slash followed by the given
* class's full package name, replacing each period character ('.') with
* a slash. For example, the absolute path of the preference associated with
* the class Object would be "/java/lang". As a special case, the unnamed
* package is associated with a preference node "/<unnamed>". This
* method will create the node and its ancestors as needed. Any nodes created
* by this method won't necessarily be persisted until the method {@code
* flush()} is invoked.
*
* @param c
* the given class.
* @return the system preference node for the package of the given class.
* @throws NullPointerException
* if the given class is {@code null}.
*/
public static Preferences systemNodeForPackage(Class<?> c) {
return factory.systemRoot().node(getNodeName(c));
}
/**
* <strong>Legacy code; do not use.</strong> On Android, the Preference nodes
* corresponding to the "system" and "user" preferences are stored in sections
* of the file system that are inaccessible to apps. Further, allowing apps to set
* "system wide" preferences is contrary to android's security model.
*
* Returns the root node of the system preference hierarchy.
*
* @return the system preference hierarchy root node.
*/
public static Preferences systemRoot() {
return factory.systemRoot();
}
/**
*
* <strong>Legacy code; do not use.</strong> On Android, the Preference nodes
* corresponding to the "system" and "user" preferences are stored in sections
* of the file system that are inaccessible to apps. Further, allowing apps to set
* "system wide" preferences is contrary to android's security model.
*
* <p>
* Returns the user preference node for the package of the given class.
* The absolute path of the returned node is one slash followed by the given
* class's full package name, replacing each period character ('.') with
* a slash. For example, the absolute path of the preference associated with
* the class Object would be "/java/lang". As a special case, the unnamed
* package is associated with a preference node "/<unnamed>". This
* method will create the node and its ancestors as needed. Any nodes created
* by this method won't necessarily be persisted until the method {@code
* flush()} is invoked.
*
* @return the user preference node for the package of the given class.
* @throws NullPointerException
* if the given class is {@code null}.
*/
public static Preferences userNodeForPackage(Class<?> c) {
return factory.userRoot().node(getNodeName(c));
}
//parse node's absolute path from class instance
private static String getNodeName(Class<?> c){
Package p = c.getPackage();
if (p == null){
return "/<unnamed>";
}
return "/"+p.getName().replace('.', '/');
}
/**
* <strong>Legacy code; do not use.</strong> On Android, the Preference nodes
* corresponding to the "system" and "user" preferences are stored in sections
* of the file system that are inaccessible to apps. Further, allowing apps to set
* "system wide" preferences is contrary to android's security model.
*
* Returns the root node of the user preference hierarchy.
*
* @return the user preference hierarchy root node.
*/
public static Preferences userRoot() {
return factory.userRoot();
}
/**
* Returns a string representation of this node. The format is "User/System
* Preference Node: " followed by this node's absolute path.
*
* @return the string representation of this node.
*/
@Override
public abstract String toString();
}