summaryrefslogtreecommitdiffstats
path: root/prefs
diff options
context:
space:
mode:
authorThe Android Open Source Project <initial-contribution@android.com>2009-03-03 19:28:47 -0800
committerThe Android Open Source Project <initial-contribution@android.com>2009-03-03 19:28:47 -0800
commitadc854b798c1cfe3bfd4c27d68d5cee38ca617da (patch)
tree6aed8b4923ca428942cbaa7e848d50237a3d31e0 /prefs
parent1c0fed63c71ddb230f3b304aac12caffbedf2f21 (diff)
downloadlibcore-adc854b798c1cfe3bfd4c27d68d5cee38ca617da.zip
libcore-adc854b798c1cfe3bfd4c27d68d5cee38ca617da.tar.gz
libcore-adc854b798c1cfe3bfd4c27d68d5cee38ca617da.tar.bz2
auto import from //depot/cupcake/@135843
Diffstat (limited to 'prefs')
-rw-r--r--prefs/MODULE_LICENSE_APACHE20
-rw-r--r--prefs/src/main/java/java/util/prefs/AbstractPreferences.java974
-rw-r--r--prefs/src/main/java/java/util/prefs/BackingStoreException.java56
-rw-r--r--prefs/src/main/java/java/util/prefs/FilePreferencesFactoryImpl.java44
-rw-r--r--prefs/src/main/java/java/util/prefs/FilePreferencesImpl.java236
-rw-r--r--prefs/src/main/java/java/util/prefs/InvalidPreferencesFormatException.java71
-rw-r--r--prefs/src/main/java/java/util/prefs/NodeChangeEvent.java99
-rw-r--r--prefs/src/main/java/java/util/prefs/NodeChangeListener.java54
-rw-r--r--prefs/src/main/java/java/util/prefs/NodeSet.java38
-rw-r--r--prefs/src/main/java/java/util/prefs/PreferenceChangeEvent.java116
-rw-r--r--prefs/src/main/java/java/util/prefs/PreferenceChangeListener.java45
-rw-r--r--prefs/src/main/java/java/util/prefs/Preferences.java1043
-rw-r--r--prefs/src/main/java/java/util/prefs/PreferencesFactory.java49
-rw-r--r--prefs/src/main/java/java/util/prefs/XMLParser.java621
-rw-r--r--prefs/src/main/java/java/util/prefs/package.html14
-rw-r--r--prefs/src/main/java/org/apache/harmony/prefs/internal/nls/Messages.java140
-rw-r--r--prefs/src/main/java/org/apache/harmony/prefs/internal/nls/messages.properties33
-rw-r--r--prefs/src/main/resources/META-INF/services/java.util.prefs.PreferencesFactory1
-rw-r--r--prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/AbstractPreferencesTest.java1468
-rw-r--r--prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/AllTests.java48
-rw-r--r--prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/BackingStoreExceptionTest.java96
-rw-r--r--prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/FilePreferencesImplTest.java286
-rw-r--r--prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/InvalidPreferencesFormatExceptionTest.java119
-rw-r--r--prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/MockAbstractPreferences.java245
-rw-r--r--prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/MockNodeChangeListener.java132
-rw-r--r--prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/MockPreferenceChangeListener.java118
-rw-r--r--prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/MockSecurityManager.java60
-rw-r--r--prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/NodeChangeEventTest.java155
-rw-r--r--prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/NodeChangeListenerTest.java85
-rw-r--r--prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/PreferenceChangeEventTest.java199
-rw-r--r--prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/PreferenceChangeListenerTest.java64
-rw-r--r--prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/PreferencesFactoryTest.java77
-rw-r--r--prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/PreferencesTest.java1980
-rw-r--r--prefs/src/test/java/tests/prefs/AllTests.java38
-rw-r--r--prefs/src/test/resources/prefs/java/util/prefs/preferences.dtd56
-rw-r--r--prefs/src/test/resources/prefs/java/util/prefs/userprefs-ascii.xml63
-rw-r--r--prefs/src/test/resources/prefs/java/util/prefs/userprefs-badencoding.xml64
-rw-r--r--prefs/src/test/resources/prefs/java/util/prefs/userprefs-badform.xml54
-rw-r--r--prefs/src/test/resources/prefs/java/util/prefs/userprefs-badtype.xml64
-rw-r--r--prefs/src/test/resources/prefs/java/util/prefs/userprefs-higherversion.xml64
-rw-r--r--prefs/src/test/resources/prefs/java/util/prefs/userprefs.xml76
-rw-r--r--prefs/src/test/resources/serialization/org/apache/harmony/prefs/tests/java/util/prefs/BackingStoreExceptionTest.golden.serbin0 -> 1547 bytes
-rw-r--r--prefs/src/test/resources/serialization/org/apache/harmony/prefs/tests/java/util/prefs/InvalidPreferencesFormatExceptionTest.golden.serbin0 -> 1583 bytes
43 files changed, 9245 insertions, 0 deletions
diff --git a/prefs/MODULE_LICENSE_APACHE2 b/prefs/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/prefs/MODULE_LICENSE_APACHE2
diff --git a/prefs/src/main/java/java/util/prefs/AbstractPreferences.java b/prefs/src/main/java/java/util/prefs/AbstractPreferences.java
new file mode 100644
index 0000000..711cc01
--- /dev/null
+++ b/prefs/src/main/java/java/util/prefs/AbstractPreferences.java
@@ -0,0 +1,974 @@
+/*
+ * 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.OutputStream;
+import java.io.UnsupportedEncodingException;
+import java.util.EventListener;
+import java.util.EventObject;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.StringTokenizer;
+import java.util.TreeSet;
+
+import org.apache.harmony.luni.util.Base64;
+import org.apache.harmony.prefs.internal.nls.Messages;
+
+/**
+ * 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
+ */
+public abstract class AbstractPreferences extends Preferences {
+ /*
+ * -----------------------------------------------------------
+ * Class fields
+ * -----------------------------------------------------------
+ */
+ /**
+ * The unhandled events collection.
+ */
+ private static final List<EventObject> events = new LinkedList<EventObject>();
+
+ /**
+ * The event dispatcher thread.
+ */
+ private static final EventDispatcher dispatcher = new EventDispatcher("Preference Event Dispatcher"); //$NON-NLS-1$
+
+ /*
+ * -----------------------------------------------------------
+ * Class initializer
+ * -----------------------------------------------------------
+ */
+ static {
+ dispatcher.setDaemon(true);
+ dispatcher.start();
+ Runtime.getRuntime().addShutdownHook(new Thread() {
+ @Override
+ public void run() {
+ Preferences uroot = Preferences.userRoot();
+ Preferences sroot = Preferences.systemRoot();
+ try {
+ uroot.flush();
+ } catch (BackingStoreException e) {//ignore
+ }
+ try {
+ sroot.flush();
+ } catch (BackingStoreException e) {//ignore
+ }
+ }
+ });
+ }
+
+ /*
+ * -----------------------------------------------------------
+ * Instance fields (package-private)
+ * -----------------------------------------------------------
+ */
+ /**
+ * True, if this node is in user preference hierarchy.
+ */
+ boolean userNode;
+
+ /*
+ * -----------------------------------------------------------
+ * Instance fields (private)
+ * -----------------------------------------------------------
+ */
+ /**
+ * Marker class for 'lock' field.
+ */
+ private static class Lock {
+ }
+
+ /**
+ * The object used to lock this node.
+ *
+ * @since Android 1.0
+ */
+ protected final Object lock;
+
+ /**
+ * 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.
+ *
+ * @since Android 1.0
+ */
+ protected boolean newNode;
+
+ /**
+ * Cached child nodes
+ */
+ private Map<String, AbstractPreferences> cachedNode;
+
+ //the collections of listeners
+ private List<EventListener> nodeChangeListeners;
+ private List<EventListener> preferenceChangeListeners;
+
+ //this node's name
+ private String nodeName;
+
+ //handler to this node's parent
+ private AbstractPreferences parentPref;
+
+ //true if this node has been removed
+ private boolean isRemoved;
+
+ //handler to this node's root node
+ private AbstractPreferences root;
+
+ /*
+ * -----------------------------------------------------------
+ * Constructors
+ * -----------------------------------------------------------
+ */
+ /**
+ * 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
+ */
+ protected AbstractPreferences(AbstractPreferences parent, String name) {
+ 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
+ * -----------------------------------------------------------
+ */
+ /**
+ * Returns an array of all cached child nodes.
+ *
+ * @return the array of cached child nodes.
+ * @since Android 1.0
+ */
+ protected final AbstractPreferences[] cachedChildren() {
+ return cachedNode.values().toArray(new AbstractPreferences[cachedNode.size()]);
+ }
+
+ /**
+ * 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
+ */
+ protected AbstractPreferences getChild(String name)
+ throws BackingStoreException {
+ 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;
+ }
+
+ }
+
+ /**
+ * 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
+ */
+ protected boolean isRemoved() {
+ synchronized (lock) {
+ return isRemoved;
+ }
+ }
+
+ /**
+ * 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
+ */
+ protected abstract void flushSpi() throws BackingStoreException;
+
+ /**
+ * 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
+ */
+ protected abstract String[] childrenNamesSpi() throws BackingStoreException;
+
+ /**
+ * 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.
+ * <p>
+ * The new creation is not required to be persisted immediately until the
+ * flush method will be invoked.
+ * </p>
+ *
+ * @param name
+ * the name of the child preference to be returned.
+ * @return the child preference node.
+ * @since Android 1.0
+ */
+ protected abstract AbstractPreferences childSpi(String name);
+
+
+ /**
+ * 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
+ */
+ protected abstract void putSpi(String name, String value);
+
+ /**
+ * 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 abstract String getSpi(String key);
+
+
+ /**
+ * 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
+ */
+ protected abstract String[] keysSpi() throws BackingStoreException;
+
+ /**
+ * 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
+ */
+ protected abstract void removeNodeSpi() throws BackingStoreException;
+
+ /**
+ * 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
+ */
+ protected abstract void removeSpi(String key);
+
+ /**
+ * 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
+ */
+ protected abstract void syncSpi() throws BackingStoreException;
+
+ /*
+ * -----------------------------------------------------------
+ * Methods inherited from Preferences
+ * -----------------------------------------------------------
+ */
+ @Override
+ public String absolutePath() {
+ if (parentPref == null) {
+ return "/"; //$NON-NLS-1$
+ } else if (parentPref == root) {
+ return "/" + nodeName; //$NON-NLS-1$
+ }
+ return parentPref.absolutePath() + "/" + nodeName; //$NON-NLS-1$
+ }
+
+ @Override
+ public String[] childrenNames() throws BackingStoreException {
+ 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]);
+ }
+ }
+
+ @Override
+ public void clear() throws BackingStoreException {
+ synchronized (lock) {
+ String[] keyList = keys();
+ for (int i = 0; i < keyList.length; i++) {
+ remove(keyList[i]);
+ }
+ }
+ }
+
+ @Override
+ public void exportNode(OutputStream ostream) throws IOException,
+ BackingStoreException {
+ if(ostream == null) {
+ // prefs.5=Stream is null
+ throw new NullPointerException(Messages.getString("prefs.5")); //$NON-NLS-1$
+ }
+ checkState();
+ XMLParser.exportPrefs(this, ostream, false);
+
+ }
+
+ @Override
+ public void exportSubtree(OutputStream ostream) throws IOException,
+ BackingStoreException {
+ if(ostream == null) {
+ // prefs.5=Stream is null
+ throw new NullPointerException(Messages.getString("prefs.5")); //$NON-NLS-1$
+ }
+ checkState();
+ XMLParser.exportPrefs(this, ostream, true);
+ }
+
+ @Override
+ public void flush() throws BackingStoreException {
+ synchronized (lock) {
+ flushSpi();
+ }
+ AbstractPreferences[] cc = cachedChildren();
+ int i;
+ for (i = 0; i < cc.length; i++) {
+ cc[i].flush();
+ }
+ }
+
+ @Override
+ public String get(String key, 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);
+ }
+
+ @Override
+ public boolean getBoolean(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;
+ }
+ }
+
+ @Override
+ public byte[] getByteArray(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;
+ }
+
+ @Override
+ public double getDouble(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;
+ }
+
+ @Override
+ public float getFloat(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;
+ }
+
+ @Override
+ public int getInt(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;
+ }
+
+ @Override
+ public long getLong(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;
+ }
+
+ @Override
+ public boolean isUserNode() {
+ return root == Preferences.userRoot();
+ }
+
+ @Override
+ public String[] keys() throws BackingStoreException {
+ synchronized (lock) {
+ checkState();
+ return keysSpi();
+ }
+ }
+
+ @Override
+ public String name() {
+ return nodeName;
+ }
+
+ @Override
+ public Preferences node(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;
+ }
+
+ private void validateName(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$
+ }
+ }
+
+ private AbstractPreferences nodeImpl(String path, boolean createNew)
+ throws BackingStoreException {
+ 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 AbstractPreferences getNodeFromBackend(boolean createNew,
+ AbstractPreferences currentNode, String name)
+ throws BackingStoreException {
+ 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;
+ }
+
+ @Override
+ public boolean nodeExists(String name) throws BackingStoreException {
+ 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;
+ }
+ }
+
+ @Override
+ public Preferences parent() {
+ checkState();
+ return parentPref;
+ }
+
+ private void checkState() {
+ if (isRemoved()) {
+ // prefs.9=This node has been removed\!
+ throw new IllegalStateException(Messages.getString("prefs.9")); //$NON-NLS-1$
+ }
+ }
+
+ @Override
+ public void put(String key, 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);
+ }
+
+ @Override
+ public void putBoolean(String key, boolean value) {
+ String sval = String.valueOf(value);
+ put(key, sval);
+ }
+
+ @Override
+ public void putByteArray(String key, byte[] value) {
+ try {
+ put(key, Base64.encode(value, "US-ASCII")); //$NON-NLS-1$
+ } catch (UnsupportedEncodingException e) {
+ throw new AssertionError(e);
+ }
+ }
+
+ @Override
+ public void putDouble(String key, double value) {
+ String sval = Double.toString(value);
+ put(key, sval);
+ }
+
+ @Override
+ public void putFloat(String key, float value) {
+ String sval = Float.toString(value);
+ put(key, sval);
+ }
+
+ @Override
+ public void putInt(String key, int value) {
+ String sval = Integer.toString(value);
+ put(key, sval);
+ }
+
+ @Override
+ public void putLong(String key, long value) {
+ String sval = Long.toString(value);
+ put(key, sval);
+ }
+
+ @Override
+ public void remove(String key) {
+ synchronized (lock) {
+ checkState();
+ removeSpi(key);
+ }
+ notifyPreferenceChange(key, null);
+ }
+
+ @Override
+ public void removeNode() throws BackingStoreException {
+ if (root == this) {
+ // prefs.A=Cannot remove root node\!
+ throw new UnsupportedOperationException(Messages.getString("prefs.A")); //$NON-NLS-1$
+ }
+ synchronized (parentPref.lock) {
+ removeNodeImpl();
+ }
+ }
+
+ private void removeNodeImpl() throws BackingStoreException {
+ 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);
+ }
+ }
+
+ @Override
+ public void addNodeChangeListener(NodeChangeListener ncl) {
+ if (null == ncl) {
+ throw new NullPointerException();
+ }
+ checkState();
+ synchronized (nodeChangeListeners) {
+ nodeChangeListeners.add(ncl);
+ }
+ }
+
+ @Override
+ public void addPreferenceChangeListener(PreferenceChangeListener pcl) {
+ if (null == pcl) {
+ throw new NullPointerException();
+ }
+ checkState();
+ synchronized (preferenceChangeListeners) {
+ preferenceChangeListeners.add(pcl);
+ }
+ }
+
+ @Override
+ public void removeNodeChangeListener(NodeChangeListener ncl) {
+ checkState();
+ synchronized (nodeChangeListeners) {
+ int pos;
+ if ((pos = nodeChangeListeners.indexOf(ncl)) == -1) {
+ throw new IllegalArgumentException();
+ }
+ nodeChangeListeners.remove(pos);
+ }
+ }
+
+ @Override
+ public void removePreferenceChangeListener(PreferenceChangeListener pcl) {
+ checkState();
+ synchronized (preferenceChangeListeners) {
+ int pos;
+ if ((pos = preferenceChangeListeners.indexOf(pcl)) == -1) {
+ throw new IllegalArgumentException();
+ }
+ preferenceChangeListeners.remove(pos);
+ }
+ }
+
+ @Override
+ public void sync() throws BackingStoreException {
+ synchronized (lock) {
+ checkState();
+ syncSpi();
+ }
+ AbstractPreferences[] cc = cachedChildren();
+ int i;
+ for (i = 0; i < cc.length; i++) {
+ cc[i].sync();
+ }
+ }
+
+ @Override
+ public String toString() {
+ 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 void notifyChildAdded(Preferences child) {
+ NodeChangeEvent nce = new NodeAddEvent(this, child);
+ synchronized (events) {
+ events.add(nce);
+ events.notifyAll();
+ }
+ }
+
+ private void notifyChildRemoved(Preferences child) {
+ NodeChangeEvent nce = new NodeRemoveEvent(this, child);
+ synchronized (events) {
+ events.add(nce);
+ events.notifyAll();
+ }
+ }
+
+ private void notifyPreferenceChange(String key, String newValue) {
+ PreferenceChangeEvent pce = new PreferenceChangeEvent(this, key,
+ newValue);
+ synchronized (events) {
+ events.add(pce);
+ events.notifyAll();
+ }
+ }
+
+ private static class EventDispatcher extends Thread {
+ EventDispatcher(String name){
+ super(name);
+ }
+
+ @Override
+ public void run() {
+ while (true) {
+ EventObject event = null;
+ try {
+ event = getEventObject();
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ continue;
+ }
+ AbstractPreferences pref = (AbstractPreferences) event
+ .getSource();
+ if (event instanceof NodeAddEvent) {
+ dispatchNodeAdd((NodeChangeEvent) event,
+ pref.nodeChangeListeners);
+ } else if (event instanceof NodeRemoveEvent) {
+ dispatchNodeRemove((NodeChangeEvent) event,
+ pref.nodeChangeListeners);
+ } else if (event instanceof PreferenceChangeEvent) {
+ dispatchPrefChange((PreferenceChangeEvent) event,
+ pref.preferenceChangeListeners);
+ }
+ }
+ }
+
+ private EventObject getEventObject() throws InterruptedException {
+ synchronized (events) {
+ if (events.isEmpty()) {
+ events.wait();
+ }
+ EventObject event = events.get(0);
+ events.remove(0);
+ return event;
+ }
+ }
+
+ private void dispatchPrefChange(PreferenceChangeEvent event,
+ List<EventListener> preferenceChangeListeners) {
+ synchronized (preferenceChangeListeners) {
+ Iterator<EventListener> i = preferenceChangeListeners.iterator();
+ while (i.hasNext()) {
+ PreferenceChangeListener pcl = (PreferenceChangeListener) i
+ .next();
+ pcl.preferenceChange(event);
+ }
+ }
+ }
+
+ private void dispatchNodeRemove(NodeChangeEvent event,
+ List<EventListener> nodeChangeListeners) {
+ synchronized (nodeChangeListeners) {
+ Iterator<EventListener> i = nodeChangeListeners.iterator();
+ while (i.hasNext()) {
+ NodeChangeListener ncl = (NodeChangeListener) i.next();
+ ncl.childRemoved(event);
+ }
+ }
+ }
+
+ private void dispatchNodeAdd(NodeChangeEvent event,
+ List<EventListener> nodeChangeListeners) {
+ synchronized (nodeChangeListeners) {
+ Iterator<EventListener> i = nodeChangeListeners.iterator();
+ while (i.hasNext()) {
+ NodeChangeListener ncl = (NodeChangeListener) i.next();
+ ncl.childAdded(event);
+ }
+ }
+ }
+ }
+
+ private static class NodeAddEvent extends NodeChangeEvent {
+ //The base class is NOT serializable, so this class isn't either.
+ private static final long serialVersionUID = 1L;
+
+ public NodeAddEvent(Preferences p, Preferences c) {
+ super(p, c);
+ }
+ }
+
+ private static class NodeRemoveEvent extends NodeChangeEvent {
+ //The base class is NOT serializable, so this class isn't either.
+ private static final long serialVersionUID = 1L;
+
+ public NodeRemoveEvent(Preferences p, Preferences c) {
+ super(p, c);
+ }
+ }
+}
diff --git a/prefs/src/main/java/java/util/prefs/BackingStoreException.java b/prefs/src/main/java/java/util/prefs/BackingStoreException.java
new file mode 100644
index 0000000..e8a805c
--- /dev/null
+++ b/prefs/src/main/java/java/util/prefs/BackingStoreException.java
@@ -0,0 +1,56 @@
+/*
+ * 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;
+
+
+/**
+ * An exception to indicate that an error was encountered while accessing the
+ * backing store.
+ *
+ * @since Android 1.0
+ */
+public class BackingStoreException extends Exception {
+
+ private static final long serialVersionUID = 859796500401108469L;
+
+ /**
+ * Constructs a new {@code BackingStoreException} instance with a detailed exception
+ * message.
+ *
+ * @param s
+ * the detailed exception message.
+ * @since Android 1.0
+ */
+ public BackingStoreException (String s) {
+ super(s);
+ }
+
+ /**
+ * Constructs a new {@code BackingStoreException} instance with a nested {@code Throwable}.
+ *
+ * @param t
+ * the nested {@code Throwable}.
+ * @since Android 1.0
+ */
+ public BackingStoreException (Throwable t) {
+ super(t);
+ }
+}
+
+
+
diff --git a/prefs/src/main/java/java/util/prefs/FilePreferencesFactoryImpl.java b/prefs/src/main/java/java/util/prefs/FilePreferencesFactoryImpl.java
new file mode 100644
index 0000000..cc68e62
--- /dev/null
+++ b/prefs/src/main/java/java/util/prefs/FilePreferencesFactoryImpl.java
@@ -0,0 +1,44 @@
+/* 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;
+
+/**
+ * The default implementation of <code>PreferencesFactory</code> for the Linux
+ * platform, using the file system as its back end.
+ *
+ * @since Android 1.0
+ */
+class FilePreferencesFactoryImpl implements PreferencesFactory {
+ // user root preferences
+ private static final Preferences USER_ROOT = new FilePreferencesImpl(true);
+
+ // system root preferences
+ private static final Preferences SYSTEM_ROOT = new FilePreferencesImpl(false);
+
+ public FilePreferencesFactoryImpl() {
+ super();
+ }
+
+ public Preferences userRoot() {
+ return USER_ROOT;
+ }
+
+ public Preferences systemRoot() {
+ return SYSTEM_ROOT;
+ }
+
+}
diff --git a/prefs/src/main/java/java/util/prefs/FilePreferencesImpl.java b/prefs/src/main/java/java/util/prefs/FilePreferencesImpl.java
new file mode 100644
index 0000000..cf85fa0
--- /dev/null
+++ b/prefs/src/main/java/java/util/prefs/FilePreferencesImpl.java
@@ -0,0 +1,236 @@
+/* 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.File;
+import java.io.FilenameFilter;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Properties;
+import java.util.Set;
+
+import org.apache.harmony.prefs.internal.nls.Messages;
+
+/**
+ * The default implementation of <code>AbstractPreferences</code> for the Linux platform,
+ * using the file system as its back end.
+ *
+ * TODO some sync mechanism with backend, Performance - check file edit date
+ *
+ * @since Android 1.0
+ */
+class FilePreferencesImpl extends AbstractPreferences {
+
+ /*
+ * --------------------------------------------------------------
+ * Class fields
+ * --------------------------------------------------------------
+ */
+
+ //prefs file name
+ private static final String PREFS_FILE_NAME = "prefs.xml"; //$NON-NLS-1$
+
+ //home directory for user prefs
+ private static String USER_HOME;
+
+ //home directory for system prefs
+ private static String SYSTEM_HOME;
+
+ /*
+ * --------------------------------------------------------------
+ * Class initializer
+ * --------------------------------------------------------------
+ */
+ static {
+ AccessController.doPrivileged(new PrivilegedAction<Void>() {
+ public Void run() {
+ USER_HOME = System.getProperty("user.home") + "/.java/.userPrefs";//$NON-NLS-1$ //$NON-NLS-2$
+ SYSTEM_HOME = System.getProperty("java.home") + "/.systemPrefs";//$NON-NLS-1$//$NON-NLS-2$
+ return null;
+ }
+
+ });
+ }
+
+ /*
+ * --------------------------------------------------------------
+ * Instance fields
+ * --------------------------------------------------------------
+ */
+
+ //file path for this preferences node
+ private String path;
+
+ //internal cache for prefs key-value pair
+ private Properties prefs;
+
+ //file represents this preferences node
+ private File prefsFile;
+
+ //parent dir for this preferences node
+ private File dir;
+
+ //cache for removed prefs key-value pair
+ private Set<String> removed = new HashSet<String>();
+
+ //cache for updated prefs key-value pair
+ private Set<String> updated = new HashSet<String>();
+
+ /*
+ * --------------------------------------------------------------
+ * Constructors
+ * --------------------------------------------------------------
+ */
+
+ /**
+ * Construct root <code>FilePreferencesImpl</code> instance, construct
+ * user root if userNode is true, system root otherwise
+ */
+ FilePreferencesImpl(boolean userNode) {
+ super(null, ""); //$NON-NLS-1$
+ this.userNode = userNode;
+ path = userNode ? USER_HOME : SYSTEM_HOME;
+ initPrefs();
+ }
+
+ /**
+ * Construct a prefs using given parent and given name
+ */
+ private FilePreferencesImpl(AbstractPreferences parent, String name) {
+ super(parent, name);
+ path = ((FilePreferencesImpl) parent).path + File.separator + name;
+ initPrefs();
+ }
+
+ private void initPrefs() {
+ dir = new File(path);
+ newNode = (AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
+ public Boolean run() {
+ return Boolean.valueOf(!dir.exists());
+ }
+ })).booleanValue();
+ prefsFile = new File(path + File.separator + PREFS_FILE_NAME);
+ prefs = XMLParser.loadFilePrefs(prefsFile);
+ }
+
+ @Override
+ protected String[] childrenNamesSpi() throws BackingStoreException {
+ String[] names = AccessController
+ .doPrivileged(new PrivilegedAction<String[]>() {
+ public String[] run() {
+ return dir.list(new FilenameFilter() {
+ public boolean accept(File parent, String name) {
+ return new File(path + File.separator + name).isDirectory();
+ }
+ });
+
+ }
+ });
+ if (null == names) {// file is not a directory, exception case
+ // prefs.3=Cannot get children names for {0}!
+ throw new BackingStoreException(
+ Messages.getString("prefs.3", toString())); //$NON-NLS-1$
+ }
+ return names;
+ }
+
+ @Override
+ protected AbstractPreferences childSpi(String name) {
+ FilePreferencesImpl child = new FilePreferencesImpl(this, name);
+ return child;
+ }
+
+ @Override
+ protected void flushSpi() throws BackingStoreException {
+ try {
+ //if removed, return
+ if(isRemoved()){
+ return;
+ }
+ // reload
+ Properties currentPrefs = XMLParser.loadFilePrefs(prefsFile);
+ // merge
+ Iterator<String> it = removed.iterator();
+ while (it.hasNext()) {
+ currentPrefs.remove(it.next());
+ }
+ removed.clear();
+ it = updated.iterator();
+ while (it.hasNext()) {
+ Object key = it.next();
+ currentPrefs.put(key, prefs.get(key));
+ }
+ updated.clear();
+ // flush
+ prefs = currentPrefs;
+ XMLParser.flushFilePrefs(prefsFile, prefs);
+ } catch (Exception e) {
+ throw new BackingStoreException(e);
+ }
+ }
+
+ @Override
+ protected String getSpi(String key) {
+ try {
+ if (null == prefs) {
+ prefs = XMLParser.loadFilePrefs(prefsFile);
+ }
+ return prefs.getProperty(key);
+ } catch (Exception e) {// if Exception happened, return null
+ return null;
+ }
+ }
+
+ @Override
+ protected String[] keysSpi() throws BackingStoreException {
+ return prefs.keySet().toArray(new String[0]);
+ }
+
+ @Override
+ protected void putSpi(String name, String value) {
+ prefs.setProperty(name, value);
+ updated.add(name);
+ }
+
+ @Override
+ protected void removeNodeSpi() throws BackingStoreException {
+ boolean removeSucceed = (AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
+ public Boolean run() {
+ prefsFile.delete();
+ return Boolean.valueOf(dir.delete());
+ }
+ })).booleanValue();
+ if (!removeSucceed) {
+ // prefs.4=Cannot remove {0}!
+ throw new BackingStoreException(Messages.getString("prefs.4", toString())); //$NON-NLS-1$
+ }
+ }
+
+ @Override
+ protected void removeSpi(String key) {
+ prefs.remove(key);
+ updated.remove(key);
+ removed.add(key);
+ }
+
+ @Override
+ protected void syncSpi() throws BackingStoreException {
+ flushSpi();
+ }
+}
diff --git a/prefs/src/main/java/java/util/prefs/InvalidPreferencesFormatException.java b/prefs/src/main/java/java/util/prefs/InvalidPreferencesFormatException.java
new file mode 100644
index 0000000..b31b3a1
--- /dev/null
+++ b/prefs/src/main/java/java/util/prefs/InvalidPreferencesFormatException.java
@@ -0,0 +1,71 @@
+/*
+ * 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;
+
+/**
+ * An exception to indicate that the input XML file is not well-formed or could
+ * not be validated against the appropriate document type (specified by
+ * in the {@code Preferences}).
+ *
+ * @since Android 1.0
+ */
+public class InvalidPreferencesFormatException extends Exception {
+
+ private static final long serialVersionUID = -791715184232119669L;
+
+ /**
+ * Constructs a new {@code InvalidPreferencesFormatException} instance with a
+ * detailed exception message.
+ *
+ * @param s
+ * the detailed exception message.
+ * @since Android 1.0
+ */
+ public InvalidPreferencesFormatException (String s) {
+ super(s);
+ }
+
+ /**
+ * Constructs a new {@code InvalidPreferencesFormatException} instance with a
+ * detailed exception message and a nested {@code Throwable}.
+ *
+ * @param s
+ * the detailed exception message.
+ * @param t
+ * the nested {@code Throwable}.
+ * @since Android 1.0
+ */
+ public InvalidPreferencesFormatException (String s, Throwable t) {
+ super(s,t);
+ }
+
+ /**
+ * Constructs a new {@code InvalidPreferencesFormatException} instance with a nested
+ * {@code Throwable}.
+ *
+ * @param t
+ * the nested {@code Throwable}.
+ * @since Android 1.0
+ */
+ public InvalidPreferencesFormatException (Throwable t) {
+ super(t);
+ }
+}
+
+
+
diff --git a/prefs/src/main/java/java/util/prefs/NodeChangeEvent.java b/prefs/src/main/java/java/util/prefs/NodeChangeEvent.java
new file mode 100644
index 0000000..e9824bc
--- /dev/null
+++ b/prefs/src/main/java/java/util/prefs/NodeChangeEvent.java
@@ -0,0 +1,99 @@
+/* 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.Serializable;
+import java.util.EventObject;
+import java.io.ObjectOutputStream;
+import java.io.ObjectInputStream;
+import java.io.NotSerializableException;
+import java.io.IOException;
+
+/**
+ * This is the event class to indicate that one child of the preference node has
+ * been added or deleted.
+ * <p>
+ * Please note that the serialization functionality has not yet been implemented, so
+ * the serialization methods do nothing but throw a {@code NotSerializableException}.
+ * </p>
+ *
+ * @since Android 1.0
+ */
+public class NodeChangeEvent extends EventObject implements Serializable {
+
+ private static final long serialVersionUID = 8068949086596572957L;
+
+ private final Preferences parent;
+ private final Preferences child;
+
+ /**
+ * Constructs a new {@code NodeChangeEvent} instance.
+ *
+ * @param p
+ * the {@code Preferences} instance that fired this event; this object is
+ * considered as the event source.
+ * @param c
+ * the child {@code Preferences} instance that was added or deleted.
+ * @since Android 1.0
+ */
+ public NodeChangeEvent (Preferences p, Preferences c) {
+ super(p);
+ parent = p;
+ child = c;
+ }
+
+ /**
+ * Gets the {@code Preferences} instance that fired this event.
+ *
+ * @return the {@code Preferences} instance that fired this event.
+ * @since Android 1.0
+ */
+ public Preferences getParent() {
+ return parent;
+ }
+
+ /**
+ * Gets the child {@code Preferences} node that was added or removed.
+ *
+ * @return the added or removed child {@code Preferences} node.
+ * @since Android 1.0
+ */
+ public Preferences getChild() {
+ return child;
+ }
+
+ /*
+ * This method always throws a <code>NotSerializableException</code>,
+ * because this object cannot be serialized,
+ */
+ private void writeObject (ObjectOutputStream out) throws IOException {
+ throw new NotSerializableException();
+ }
+
+ /*
+ * This method always throws a <code>NotSerializableException</code>,
+ * because this object cannot be serialized,
+ */
+ private void readObject (ObjectInputStream in) throws IOException, ClassNotFoundException {
+ throw new NotSerializableException();
+ }
+}
+
+
+
+
diff --git a/prefs/src/main/java/java/util/prefs/NodeChangeListener.java b/prefs/src/main/java/java/util/prefs/NodeChangeListener.java
new file mode 100644
index 0000000..f16b206
--- /dev/null
+++ b/prefs/src/main/java/java/util/prefs/NodeChangeListener.java
@@ -0,0 +1,54 @@
+/* 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.util.EventListener;
+import java.util.prefs.NodeChangeEvent;
+
+/**
+ * This interface is used to handle preference node change events.
+ * The implementation of this interface can be installed by the {@code Preferences} instance.
+ *
+ * @see NodeChangeEvent
+ *
+ * @since Android 1.0
+ */
+public interface NodeChangeListener extends EventListener {
+
+ /**
+ * This method gets called whenever a child node is added to another node.
+ *
+ * @param e
+ * the node change event.
+ * @since Android 1.0
+ */
+ public void childAdded (NodeChangeEvent e);
+
+ /**
+ * This method gets called whenever a child node is removed from another
+ * node.
+ *
+ * @param e
+ * the node change event.
+ * @since Android 1.0
+ */
+ public void childRemoved (NodeChangeEvent e);
+}
+
+
+
diff --git a/prefs/src/main/java/java/util/prefs/NodeSet.java b/prefs/src/main/java/java/util/prefs/NodeSet.java
new file mode 100644
index 0000000..7edd030
--- /dev/null
+++ b/prefs/src/main/java/java/util/prefs/NodeSet.java
@@ -0,0 +1,38 @@
+package java.util.prefs;
+
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+
+/**
+ *
+ * @since Android 1.0
+ */
+class NodeSet implements NodeList {
+
+ ArrayList<Node> list = new ArrayList<Node>();
+
+ public NodeSet(Iterator<Node> nodes) {
+ while(nodes.hasNext()) {
+ list.add(nodes.next());
+ }
+ }
+
+ public int getLength() {
+ return list.size();
+ }
+
+ public Node item(int index) {
+ Node result = null;
+ try {
+ result = list.get(index);
+ } catch(IndexOutOfBoundsException ioobe) {
+ // TODO log this event?
+ return null;
+ }
+
+ return result;
+ }
+}
diff --git a/prefs/src/main/java/java/util/prefs/PreferenceChangeEvent.java b/prefs/src/main/java/java/util/prefs/PreferenceChangeEvent.java
new file mode 100644
index 0000000..f0f0787
--- /dev/null
+++ b/prefs/src/main/java/java/util/prefs/PreferenceChangeEvent.java
@@ -0,0 +1,116 @@
+/* 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.NotSerializableException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.util.EventObject;
+
+/**
+ * This is the event class to indicate that a preference has been added, deleted
+ * or updated.
+ * <p>
+ * Please note that the serialization functionality has not yet been implemented, so
+ * the serialization methods do nothing but throw a {@code NotSerializableException}.
+ * </p>
+ *
+ * @since Android 1.0
+ */
+public class PreferenceChangeEvent extends EventObject implements Serializable {
+
+ private static final long serialVersionUID = 793724513368024975L;
+
+ private final Preferences node;
+
+ private final String key;
+
+ private final String value;
+
+ /**
+ * Construct a new {@code PreferenceChangeEvent} instance.
+ *
+ * @param p
+ * the {@code Preferences} instance that fired this event; this object is
+ * considered as the event's source.
+ * @param k
+ * the changed preference key.
+ * @param v
+ * the new value of the changed preference, this value can be
+ * {@code null}, which means the preference has been removed.
+ * @since Android 1.0
+ */
+ public PreferenceChangeEvent(Preferences p, String k, String v) {
+ super(p);
+ node = p;
+ key = k;
+ value = v;
+ }
+
+ /**
+ * Gets the key of the changed preference.
+ *
+ * @return the changed preference's key.
+ * @since Android 1.0
+ */
+ public String getKey() {
+ return key;
+ }
+
+ /**
+ * Gets the new value of the changed preference or {@code null} if the
+ * preference has been removed.
+ *
+ * @return the new value of the changed preference or null if the preference
+ * has been removed.
+ * @since Android 1.0
+ */
+ public String getNewValue() {
+ return value;
+ }
+
+ /**
+ * Gets the {@code Preferences} instance that fired this event.
+ *
+ * @return the {@code Preferences} instance that fired this event.
+ * @since Android 1.0
+ */
+ public Preferences getNode() {
+ return node;
+ }
+
+ /*
+ * This method always throws a <code>NotSerializableException</code>,
+ * because this object cannot be serialized,
+ */
+ private void writeObject(ObjectOutputStream out) throws IOException {
+ throw new NotSerializableException();
+ }
+
+ /*
+ * This method always throws a <code>NotSerializableException</code>,
+ * because this object cannot be serialized,
+ */
+ private void readObject(ObjectInputStream in) throws IOException{
+ throw new NotSerializableException();
+ }
+}
+
+
diff --git a/prefs/src/main/java/java/util/prefs/PreferenceChangeListener.java b/prefs/src/main/java/java/util/prefs/PreferenceChangeListener.java
new file mode 100644
index 0000000..28bb763
--- /dev/null
+++ b/prefs/src/main/java/java/util/prefs/PreferenceChangeListener.java
@@ -0,0 +1,45 @@
+/* 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.util.EventListener;
+
+/**
+ * This interface is used to handle preferences change events. The implementation of
+ * this interface can be installed by the {@code Preferences} instance.
+ *
+ * @see PreferenceChangeEvent
+ *
+ * @since Android 1.0
+ */
+public interface PreferenceChangeListener extends EventListener {
+
+ /**
+ * This method gets invoked whenever a preference is added, deleted or
+ * updated.
+ *
+ * @param pce
+ * the event instance which describes the changed {@code Preferences}
+ * instance and the preference value.
+ * @since Android 1.0
+ */
+ void preferenceChange (PreferenceChangeEvent pce);
+}
+
+
+
diff --git a/prefs/src/main/java/java/util/prefs/Preferences.java b/prefs/src/main/java/java/util/prefs/Preferences.java
new file mode 100644
index 0000000..b7a0c70
--- /dev/null
+++ b/prefs/src/main/java/java/util/prefs/Preferences.java
@@ -0,0 +1,1043 @@
+/* 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;
+
+// BEGIN android-added
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.InputStreamReader;
+import java.net.URL;
+import java.util.Enumeration;
+// END android-added
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.MalformedURLException;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+
+import org.apache.harmony.prefs.internal.nls.Messages;
+
+/**
+ * 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: &lt;parent's absolute
+ * path&gt; + "/" + &lt;node's name&gt;. 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>
+ * <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 JVM exit normally, the implementation must assure all
+ * modifications are persisted implicitly.
+ * </p>
+ * <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.
+ * <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 detemine which preferences
+ * implementation to use.
+ * </p>
+ * <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.
+ * </p>
+ *
+ * @since Android 1.0
+ */
+public abstract class Preferences {
+
+ /*
+ * ---------------------------------------------------------
+ * Class fields
+ * ---------------------------------------------------------
+ */
+
+ /**
+ * Maximum size in characters allowed for a preferences key.
+ *
+ * @since Android 1.0
+ */
+ public static final int MAX_KEY_LENGTH = 80;
+
+ /**
+ * Maximum size in characters allowed for a preferences name.
+ *
+ * @since Android 1.0
+ */
+ public static final int MAX_NAME_LENGTH = 80;
+
+ /**
+ * Maximum size in characters allowed for a preferences value.
+ *
+ * @since Android 1.0
+ */
+ public static final int MAX_VALUE_LENGTH = 8192;
+
+ // BEGIN android-added
+ /**
+ * The name of the configuration file where preferences factory class names
+ * can be specified.
+ */
+ private static final String FACTORY_CONFIGURATION_FILE_NAME = "META-INF/services/java.util.prefs.PreferencesFactory"; //$NON-NLS-1$
+
+ /**
+ * The encoding of configuration files
+ */
+ private static final String CONFIGURATION_FILE_ENCODING = "UTF-8"; //$NON-NLS-1$
+
+ /**
+ * The comment string used in configuration files
+ */
+ private static final String CONFIGURATION_FILE_COMMENT = "#"; //$NON-NLS-1$
+
+ // END android-added
+
+ //permission
+ private static final RuntimePermission PREFS_PERM = new RuntimePermission("preferences"); //$NON-NLS-1$
+
+ //factory used to get user/system prefs root
+ private static final PreferencesFactory factory;
+
+ /**
+ * ---------------------------------------------------------
+ * Class initializer
+ * ---------------------------------------------------------
+ */
+ static{
+ String factoryClassName = AccessController.doPrivileged(new PrivilegedAction<String>() {
+ public String run() {
+ return System.getProperty("java.util.prefs.PreferencesFactory"); //$NON-NLS-1$
+ }
+ });
+ // BEGIN android-removed
+ // if(factoryClassName != null) {
+ // try {
+ // ClassLoader loader = Thread.currentThread().getContextClassLoader();
+ // if(loader == null){
+ // loader = ClassLoader.getSystemClassLoader();
+ // }
+ // Class<?> factoryClass = loader.loadClass(factoryClassName);
+ // factory = (PreferencesFactory) factoryClass.newInstance();
+ // } catch (Exception e) {
+ // // prefs.10=Cannot initiate PreferencesFactory: {0}. Caused by {1}
+ // throw new InternalError(Messages.getString("prefs.10", factoryClassName, e)); //$NON-NLS-1$
+ // }
+ // }
+ // END android-removed
+ // BEGIN android-added
+ ClassLoader loader = Thread.currentThread().getContextClassLoader();
+ if (loader == null) {
+ loader = ClassLoader.getSystemClassLoader();
+ }
+ if (factoryClassName == null) {
+ Enumeration<URL> en = null;
+ try {
+ en = loader.getResources(FACTORY_CONFIGURATION_FILE_NAME);
+ BufferedReader reader = null;
+ int commentIndex = 0;
+ while (en.hasMoreElements()) {
+ try {
+ InputStream is = en.nextElement().openStream();
+ // Read each line for charset provider class names
+ // BEGIN android-modified
+ reader = new BufferedReader(new InputStreamReader(is,
+ CONFIGURATION_FILE_ENCODING), 8192);
+ // END android-modified
+ factoryClassName = reader.readLine();
+ commentIndex = factoryClassName.indexOf(CONFIGURATION_FILE_COMMENT);
+ if (commentIndex > 0) {
+ factoryClassName = factoryClassName.substring(0, commentIndex).trim();
+ }
+ if (factoryClassName.length() > 0) {
+ break;
+ }
+ } catch (IOException ex) {
+ // ignore if a resource couldn't be read
+ }
+ }
+ } catch (Exception e) {
+ // prefs.10=Cannot initiate PreferencesFactory: {0}. Caused by
+ // {1}
+ throw new InternalError(Messages.getString("prefs.10",
+ FACTORY_CONFIGURATION_FILE_NAME, e)); //$NON-NLS-1$
+ }
+ }
+
+ if (factoryClassName == null) {
+ factoryClassName = "java.util.prefs.FilePreferencesFactoryImpl";
+ }
+
+ try {
+ Class<?> c = loader.loadClass(factoryClassName);
+ factory = (PreferencesFactory)c.newInstance();
+ } catch (Exception e) {
+ // prefs.10=Cannot initiate PreferencesFactory: {0}. Caused by {1}
+ throw new InternalError(Messages.getString("prefs.10", factoryClassName, e)); //$NON-NLS-1$
+ }
+ // END android-added
+ }
+
+ /*
+ * ---------------------------------------------------------
+ * Constructors
+ * ---------------------------------------------------------
+ */
+
+ /**
+ * Default constructor, for use by subclasses only.
+ *
+ * @since Android 1.0
+ */
+ protected Preferences() {
+ super();
+ }
+
+ /*
+ * ---------------------------------------------------------
+ * Methods
+ * ---------------------------------------------------------
+ */
+
+ /**
+ * Gets the absolute path string of this preference node.
+ *
+ * @return the preference node's absolute path string.
+ * @since Android 1.0
+ */
+ public abstract String absolutePath();
+
+ /**
+ * Returns the names of all children of this node or an empty string 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.
+ * @since Android 1.0
+ */
+ 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.
+ * @since Android 1.0
+ */
+ 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>
+ * &lt;!DOCTYPE preferences SYSTEM &quot;http://java.sun.com/dtd/preferences.dtd&quot;&gt;
+ * </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.
+ * @since Android 1.0
+ */
+ 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>
+ * &lt;!DOCTYPE preferences SYSTEM &quot;http://java.sun.com/dtd/preferences.dtd&quot;&gt;
+ * </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.
+ * @since Android 1.0
+ */
+ 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.
+ * @since Android 1.0
+ */
+ 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}.
+ * @since Android 1.0
+ */
+ 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}.
+ * @since Android 1.0
+ */
+ 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}.
+ * @since Android 1.0
+ */
+ 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>
+ * <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}.
+ * @since Android 1.0
+ */
+ 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}.
+ * @since Android 1.0
+ */
+ 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}.
+ * @since Android 1.0
+ */
+ 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}.
+ * @since Android 1.0
+ */
+ 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>
+ * &lt;!DOCTYPE preferences SYSTEM &quot;http://java.sun.com/dtd/preferences.dtd&quot;&gt;
+ * </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.
+ * @throws SecurityException
+ * if {@code RuntimePermission("preferences")} is denied by a
+ * SecurityManager.
+ * @since Android 1.0
+ */
+ public static void importPreferences (InputStream istream) throws InvalidPreferencesFormatException, IOException {
+ checkSecurity();
+ if(null == istream){
+ // prefs.0=Inputstream cannot be null\!
+ throw new MalformedURLException(Messages.getString("prefs.0")); //$NON-NLS-1$
+ }
+ 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.
+ * @since Android 1.0
+ */
+ 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.
+ * @since Android 1.0
+ */
+ public abstract String[] keys() throws BackingStoreException;
+
+ /**
+ * Returns the name of this node.
+ *
+ * @return the name of this node.
+ * @since Android 1.0
+ */
+ 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}.
+ * @since Android 1.0
+ */
+ 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.
+ * @since Android 1.0
+ */
+ 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.
+ * @since Android 1.0
+ */
+ 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.
+ * @since Android 1.0
+ */
+ 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.
+ * @since Android 1.0
+ */
+ 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.
+ * @since Android 1.0
+ */
+ 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.
+ * @since Android 1.0
+ */
+ 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.
+ * @since Android 1.0
+ */
+ 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.
+ * @since Android 1.0
+ */
+ 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.
+ * @since Android 1.0
+ */
+ 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.
+ * @since Android 1.0
+ */
+ 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.
+ * @since Android 1.0
+ */
+ 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.
+ * @since Android 1.0
+ */
+ 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.
+ * @since Android 1.0
+ */
+ 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.
+ * @since Android 1.0
+ */
+ 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.
+ * @since Android 1.0
+ */
+ 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.
+ * @since Android 1.0
+ */
+ public abstract void sync() throws BackingStoreException;
+
+ /**
+ * 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 "/&lt;unnamed&gt;". 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}.
+ * @throws SecurityException
+ * if the {@code RuntimePermission("preferences")} is denied by
+ * a SecurityManager.
+ * @since Android 1.0
+ */
+ public static Preferences systemNodeForPackage (Class<?> c) {
+ checkSecurity();
+ return factory.systemRoot().node(getNodeName(c));
+ }
+
+ /**
+ * Returns the root node of the system preference hierarchy.
+ *
+ * @return the system preference hierarchy root node.
+ * @throws SecurityException
+ * if the {@code RuntimePermission("preferences")} is denied by
+ * a SecurityManager.
+ * @since Android 1.0
+ */
+ public static Preferences systemRoot() {
+ checkSecurity();
+ return factory.systemRoot();
+ }
+
+ //check the RuntimePermission("preferences")
+ private static void checkSecurity() {
+ SecurityManager manager = System.getSecurityManager();
+ if(null != manager){
+ manager.checkPermission(PREFS_PERM);
+ }
+
+ }
+
+ /**
+ * 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 "/&lt;unnamed&gt;". 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 user preference node for the package of the given class.
+ * @throws NullPointerException
+ * if the given class is {@code null}.
+ * @throws SecurityException
+ * if the {@code RuntimePermission("preferences")} is denied by
+ * a SecurityManager.
+ * @since Android 1.0
+ */
+ public static Preferences userNodeForPackage (Class<?> c) {
+ checkSecurity();
+ return factory.userRoot().node(getNodeName(c));
+ }
+
+ //parse node's absolute path from class instance
+ private static String getNodeName(Class<?> c){
+ // ??? PREFS TODO change back to harmony code once getPackage
+ // delivers the correct results
+ // Package p = c.getPackage();
+ // if(null == p){
+ // return "/<unnamed>"; //$NON-NLS-1$
+ // }
+ // return "/"+p.getName().replace('.', '/'); //$NON-NLS-1$
+ int dotIndex = c.getName().lastIndexOf(".");
+ return "/" + c.getName().substring(0, dotIndex).replace(".", "/");
+ }
+
+ /**
+ * Returns the root node of the user preference hierarchy.
+ *
+ * @return the user preference hierarchy root node.
+ * @throws SecurityException
+ * if the {@code RuntimePermission("preferences")} is denied by
+ * a SecurityManager.
+ * @since Android 1.0
+ */
+ public static Preferences userRoot() {
+ checkSecurity();
+ 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.
+ * @since Android 1.0
+ */
+ @Override
+ public abstract String toString();
+}
diff --git a/prefs/src/main/java/java/util/prefs/PreferencesFactory.java b/prefs/src/main/java/java/util/prefs/PreferencesFactory.java
new file mode 100644
index 0000000..e56dd95
--- /dev/null
+++ b/prefs/src/main/java/java/util/prefs/PreferencesFactory.java
@@ -0,0 +1,49 @@
+/* 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;
+
+/**
+ * This interface is used by the {@link Preferences} class as factory class to
+ * create {@code Preferences} instances. This interface can be implemented and installed
+ * to replace the default preferences implementation.
+ *
+ * @since Android 1.0
+ */
+public interface PreferencesFactory {
+
+ /**
+ * Returns the root node of the preferences hierarchy for the calling user
+ * context.
+ *
+ * @return the user preferences hierarchy root node.
+ * @since Android 1.0
+ */
+ Preferences userRoot();
+
+ /**
+ * Returns the root node of the system preferences hierarchy.
+ *
+ * @return the system preferences hierarchy root node.
+ * @since Android 1.0
+ */
+ Preferences systemRoot();
+}
+
+
+
+
diff --git a/prefs/src/main/java/java/util/prefs/XMLParser.java b/prefs/src/main/java/java/util/prefs/XMLParser.java
new file mode 100644
index 0000000..2edfc71
--- /dev/null
+++ b/prefs/src/main/java/java/util/prefs/XMLParser.java
@@ -0,0 +1,621 @@
+/* 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.BufferedInputStream;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.StringReader;
+import java.nio.channels.FileChannel;
+import java.nio.channels.FileLock;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.security.PrivilegedActionException;
+import java.security.PrivilegedExceptionAction;
+import java.util.Properties;
+import java.util.StringTokenizer;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.FactoryConfigurationError;
+import javax.xml.parsers.ParserConfigurationException;
+// BEGIN android-removed
+// import javax.xml.transform.TransformerException;
+// END android-removed
+
+import org.apache.harmony.prefs.internal.nls.Messages;
+// BEGIN android-removed
+// import org.apache.xpath.XPathAPI;
+// END android-removed
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+import org.xml.sax.EntityResolver;
+import org.xml.sax.ErrorHandler;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
+
+// BEGIN android-added
+import java.util.ArrayList;
+import org.w3c.dom.DocumentType;
+import org.w3c.dom.Node;
+// END android-added
+
+/**
+ * Utility class for importing and exporting {@code Preferences} data from an XML file.
+ *
+ * @since Android 1.0
+ */
+class XMLParser {
+
+ /*
+ * Constant - the specified DTD URL
+ */
+ static final String PREFS_DTD_NAME = "http://java.sun.com/dtd/preferences.dtd"; //$NON-NLS-1$
+
+ /*
+ * Constant - the DTD string
+ */
+ static final String PREFS_DTD = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" //$NON-NLS-1$
+ + " <!ELEMENT preferences (root)>" //$NON-NLS-1$
+ + " <!ATTLIST preferences EXTERNAL_XML_VERSION CDATA \"0.0\" >" //$NON-NLS-1$
+ + " <!ELEMENT root (map, node*) >" //$NON-NLS-1$
+ + " <!ATTLIST root type (system|user) #REQUIRED >" //$NON-NLS-1$
+ + " <!ELEMENT node (map, node*) >" //$NON-NLS-1$
+ + " <!ATTLIST node name CDATA #REQUIRED >" //$NON-NLS-1$
+ + " <!ELEMENT map (entry*) >" //$NON-NLS-1$
+ + " <!ELEMENT entry EMPTY >" //$NON-NLS-1$
+ + " <!ATTLIST entry key CDATA #REQUIRED value CDATA #REQUIRED >"; //$NON-NLS-1$
+
+ /*
+ * Constant - the specified header
+ */
+ static final String HEADER = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"; //$NON-NLS-1$
+
+ /*
+ * Constant - the specified DOCTYPE
+ */
+ static final String DOCTYPE = "<!DOCTYPE preferences SYSTEM"; //$NON-NLS-1$
+
+ /*
+ * empty string array constant
+ */
+ private static final String[] EMPTY_SARRAY = new String[0];
+
+ /*
+ * Constant - used by FilePreferencesImpl, which is default implementation of Linux platform
+ */
+ private static final String FILE_PREFS = "<!DOCTYPE map SYSTEM 'http://java.sun.com/dtd/preferences.dtd'>"; //$NON-NLS-1$
+
+ /*
+ * Constant - specify the DTD version
+ */
+ private static final float XML_VERSION = 1.0f;
+
+ /*
+ * DOM builder
+ */
+ private static final DocumentBuilder builder;
+
+ /*
+ * specify the indent level
+ */
+ private static int indent = -1;
+
+ /*
+ * init DOM builder
+ */
+ static {
+ DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+ // BEGIN android-changed
+ factory.setValidating(false);
+ // END android-changed
+ try {
+ builder = factory.newDocumentBuilder();
+ } catch (ParserConfigurationException e) {
+ throw new Error(e);
+ }
+ builder.setEntityResolver(new EntityResolver() {
+ public InputSource resolveEntity(String publicId, String systemId)
+ throws SAXException, IOException {
+ if (systemId.equals(PREFS_DTD_NAME)) {
+ InputSource result = new InputSource(new StringReader(
+ PREFS_DTD));
+ result.setSystemId(PREFS_DTD_NAME);
+ return result;
+ }
+ // prefs.1=Invalid DOCTYPE declaration: {0}
+ throw new SAXException(
+ Messages.getString("prefs.1", systemId)); //$NON-NLS-1$
+ }
+ });
+ builder.setErrorHandler(new ErrorHandler() {
+ public void warning(SAXParseException e) throws SAXException {
+ throw e;
+ }
+
+ public void error(SAXParseException e) throws SAXException {
+ throw e;
+ }
+
+ public void fatalError(SAXParseException e) throws SAXException {
+ throw e;
+ }
+ });
+ }
+
+ private XMLParser() {// empty constructor
+ }
+
+ /***************************************************************************
+ * utilities for Preferences export
+ **************************************************************************/
+ static void exportPrefs(Preferences prefs, OutputStream stream,
+ boolean withSubTree) throws IOException, BackingStoreException {
+ indent = -1;
+ // BEGIN android-modified
+ BufferedWriter out = new BufferedWriter(new OutputStreamWriter(stream, "UTF-8"), 8192); //$NON-NLS-1$
+ // END android-modified
+ out.write(HEADER);
+ out.newLine();
+ out.newLine();
+
+ out.write(DOCTYPE);
+ out.write(" '"); //$NON-NLS-1$
+ out.write(PREFS_DTD_NAME);
+ out.write("'>"); //$NON-NLS-1$
+ out.newLine();
+ out.newLine();
+
+ flushStartTag(
+ "preferences", new String[] { "EXTERNAL_XML_VERSION" }, new String[] { String.valueOf(XML_VERSION) }, out); //$NON-NLS-1$ //$NON-NLS-2$
+ flushStartTag(
+ "root", new String[] { "type" }, new String[] { prefs.isUserNode() ? "user" : "system" }, out); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
+ flushEmptyElement("map", out); //$NON-NLS-1$
+
+ StringTokenizer ancestors = new StringTokenizer(prefs.absolutePath(),
+ "/"); //$NON-NLS-1$
+ exportNode(ancestors, prefs, withSubTree, out);
+
+ flushEndTag("root", out); //$NON-NLS-1$
+ flushEndTag("preferences", out); //$NON-NLS-1$
+ out.flush();
+ out = null;
+ }
+
+ private static void exportNode(StringTokenizer ancestors,
+ Preferences prefs, boolean withSubTree, BufferedWriter out)
+ throws IOException, BackingStoreException {
+ if (ancestors.hasMoreTokens()) {
+ String name = ancestors.nextToken();
+ flushStartTag(
+ "node", new String[] { "name" }, new String[] { name }, out); //$NON-NLS-1$ //$NON-NLS-2$
+ if (ancestors.hasMoreTokens()) {
+ flushEmptyElement("map", out); //$NON-NLS-1$
+ exportNode(ancestors, prefs, withSubTree, out);
+ } else {
+ exportEntries(prefs, out);
+ if (withSubTree) {
+ exportSubTree(prefs, out);
+ }
+ }
+ flushEndTag("node", out); //$NON-NLS-1$
+ }
+ }
+
+ private static void exportSubTree(Preferences prefs, BufferedWriter out)
+ throws BackingStoreException, IOException {
+ String[] names = prefs.childrenNames();
+ if (names.length > 0) {
+ for (int i = 0; i < names.length; i++) {
+ Preferences child = prefs.node(names[i]);
+ flushStartTag(
+ "node", new String[] { "name" }, new String[] { names[i] }, out); //$NON-NLS-1$ //$NON-NLS-2$
+ exportEntries(child, out);
+ exportSubTree(child, out);
+ flushEndTag("node", out); //$NON-NLS-1$
+ }
+ }
+ }
+
+ private static void exportEntries(Preferences prefs, BufferedWriter out)
+ throws BackingStoreException, IOException {
+ String[] keys = prefs.keys();
+ String[] values = new String[keys.length];
+ for (int i = 0; i < keys.length; i++) {
+ values[i] = prefs.get(keys[i], null);
+ }
+ exportEntries(keys, values, out);
+ }
+
+ private static void exportEntries(String[] keys, String[] values,
+ BufferedWriter out) throws IOException {
+ if (keys.length == 0) {
+ flushEmptyElement("map", out); //$NON-NLS-1$
+ return;
+ }
+ flushStartTag("map", out); //$NON-NLS-1$
+ for (int i = 0; i < keys.length; i++) {
+ if (values[i] != null) {
+ flushEmptyElement(
+ "entry", new String[] { "key", "value" }, new String[] { keys[i], values[i] }, out); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ }
+ }
+ flushEndTag("map", out); //$NON-NLS-1$
+ }
+
+ private static void flushEndTag(String tagName, BufferedWriter out)
+ throws IOException {
+ flushIndent(indent--, out);
+ out.write("</"); //$NON-NLS-1$
+ out.write(tagName);
+ out.write(">"); //$NON-NLS-1$
+ out.newLine();
+ }
+
+ private static void flushEmptyElement(String tagName, BufferedWriter out)
+ throws IOException {
+ flushIndent(++indent, out);
+ out.write("<"); //$NON-NLS-1$
+ out.write(tagName);
+ out.write(" />"); //$NON-NLS-1$
+ out.newLine();
+ indent--;
+ }
+
+ private static void flushEmptyElement(String tagName, String[] attrKeys,
+ String[] attrValues, BufferedWriter out) throws IOException {
+ flushIndent(++indent, out);
+ out.write("<"); //$NON-NLS-1$
+ out.write(tagName);
+ flushPairs(attrKeys, attrValues, out);
+ out.write(" />"); //$NON-NLS-1$
+ out.newLine();
+ indent--;
+ }
+
+ private static void flushPairs(String[] attrKeys, String[] attrValues,
+ BufferedWriter out) throws IOException {
+ for (int i = 0; i < attrKeys.length; i++) {
+ out.write(" "); //$NON-NLS-1$
+ out.write(attrKeys[i]);
+ out.write("=\""); //$NON-NLS-1$
+ out.write(htmlEncode(attrValues[i]));
+ out.write("\""); //$NON-NLS-1$
+ }
+ }
+
+ private static void flushIndent(int ind, BufferedWriter out)
+ throws IOException {
+ for (int i = 0; i < ind; i++) {
+ out.write(" "); //$NON-NLS-1$
+ }
+ }
+
+ private static void flushStartTag(String tagName, String[] attrKeys,
+ String[] attrValues, BufferedWriter out) throws IOException {
+ flushIndent(++indent, out);
+ out.write("<"); //$NON-NLS-1$
+ out.write(tagName);
+ flushPairs(attrKeys, attrValues, out);
+ out.write(">"); //$NON-NLS-1$
+ out.newLine();
+ }
+
+ private static void flushStartTag(String tagName, BufferedWriter out)
+ throws IOException {
+ flushIndent(++indent, out);
+ out.write("<"); //$NON-NLS-1$
+ out.write(tagName);
+ out.write(">"); //$NON-NLS-1$
+ out.newLine();
+ }
+
+ private static String htmlEncode(String s) {
+ StringBuffer sb = new StringBuffer();
+ char c;
+ for (int i = 0; i < s.length(); i++) {
+ c = s.charAt(i);
+ switch (c) {
+ case '<':
+ sb.append("&lt;"); //$NON-NLS-1$
+ break;
+ case '>':
+ sb.append("&gt;"); //$NON-NLS-1$
+ break;
+ case '&':
+ sb.append("&amp;"); //$NON-NLS-1$
+ break;
+ case '\\':
+ sb.append("&apos;"); //$NON-NLS-1$
+ break;
+ case '"':
+ sb.append("&quot;"); //$NON-NLS-1$
+ break;
+ default:
+ sb.append(c);
+ }
+ }
+ return sb.toString();
+ }
+
+ /***************************************************************************
+ * utilities for Preferences import
+ **************************************************************************/
+ static void importPrefs(InputStream in) throws IOException,
+ InvalidPreferencesFormatException {
+ try {
+ // load XML document
+ Document doc = builder.parse(new InputSource(in));
+
+ // check preferences' export version
+ Element preferences;
+ preferences = doc.getDocumentElement();
+ String version = preferences.getAttribute("EXTERNAL_XML_VERSION"); //$NON-NLS-1$
+ if (version != null && Float.parseFloat(version) > XML_VERSION) {
+ // prefs.2=This preferences exported version is not supported:{0}
+ throw new InvalidPreferencesFormatException(
+ Messages.getString("prefs.2", version)); //$NON-NLS-1$
+ }
+
+ // check preferences root's type
+ Element root = (Element) preferences
+ .getElementsByTagName("root").item(0); //$NON-NLS-1$
+ Preferences prefsRoot = null;
+ String type = root.getAttribute("type"); //$NON-NLS-1$
+ if (type.equals("user")) { //$NON-NLS-1$
+ prefsRoot = Preferences.userRoot();
+ } else {
+ prefsRoot = Preferences.systemRoot();
+ }
+
+ // load node
+ loadNode(prefsRoot, root);
+ } catch (FactoryConfigurationError e) {
+ throw new InvalidPreferencesFormatException(e);
+ } catch (SAXException e) {
+ throw new InvalidPreferencesFormatException(e);
+ }
+ // BEGIN android-removed
+ // catch (TransformerException e) {
+ // throw new InvalidPreferencesFormatException(e);
+ // }
+ // END android-removed
+ }
+
+ private static void loadNode(Preferences prefs, Element node) {
+ // BEGIN android-note
+ // removed throw clause for TransformerException
+ // END android-note
+ // load preferences
+ // BEGIN android-changed
+ NodeList children = selectNodeList(node, "node"); //$NON-NLS-1$
+ NodeList entries = selectNodeList(node, "map/entry"); //$NON-NLS-1$
+ // END android-changed
+ int childNumber = children.getLength();
+ Preferences[] prefChildren = new Preferences[childNumber];
+ int entryNumber = entries.getLength();
+ synchronized (((AbstractPreferences) prefs).lock) {
+ if (((AbstractPreferences) prefs).isRemoved()) {
+ return;
+ }
+ for (int i = 0; i < entryNumber; i++) {
+ Element entry = (Element) entries.item(i);
+ String key = entry.getAttribute("key"); //$NON-NLS-1$
+ String value = entry.getAttribute("value"); //$NON-NLS-1$
+ prefs.put(key, value);
+ }
+ // get children preferences node
+ for (int i = 0; i < childNumber; i++) {
+ Element child = (Element) children.item(i);
+ String name = child.getAttribute("name"); //$NON-NLS-1$
+ prefChildren[i] = prefs.node(name);
+ }
+ }
+
+ // load children nodes after unlock
+ for (int i = 0; i < childNumber; i++) {
+ loadNode(prefChildren[i], (Element) children.item(i));
+ }
+ }
+
+ // BEGIN android-added
+ // TODO dirty implementation of a method from javax.xml.xpath
+ // should be replaced with a call to a good impl of this method
+ private static NodeList selectNodeList(Element documentElement, String string) {
+
+ NodeList result = null;
+
+ ArrayList<Node> input = new ArrayList<Node>();
+
+ String[] path = string.split("/");
+
+ NodeList childNodes = documentElement.getChildNodes();
+
+ if(path[0].equals("entry") || path[0].equals("node")) {
+ for(int i = 0; i < childNodes.getLength(); i++) {
+ Object next = childNodes.item(i);
+ if(next instanceof Element) {
+ if(((Element) next).getNodeName().equals(path[0])
+ && next instanceof Node) {
+ input.add((Node)next);
+ }
+ }
+ }
+ } else if(path[0].equals("map") && path[1].equals("entry")) {
+ for(int i = 0; i < childNodes.getLength(); i++) {
+ Object next = childNodes.item(i);
+ if(next instanceof Element) {
+ if(((Element) next).getNodeName().equals(path[0])
+ && next instanceof Node) {
+ NodeList nextChildNodes = ((Node)next).getChildNodes();
+ for(int j = 0; j < nextChildNodes.getLength(); j++) {
+ Object subnext = nextChildNodes.item(j);
+ if(subnext instanceof Element) {
+ if(((Element)subnext).getNodeName().equals(path[1])) {
+ input.add((Node)subnext);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ result = new NodeSet(input.iterator());
+
+ return result;
+ }
+ // END android-added
+
+ /***************************************************************************
+ * utilities for FilePreferencesImpl, which is default implementation of Linux platform
+ **************************************************************************/
+ /**
+ * load preferences from file, if cannot load, create a new one FIXME: need
+ * lock or not?
+ *
+ * @param file the XML file to be read
+ * @return Properties instance which indicates the preferences key-value pairs
+ */
+ static Properties loadFilePrefs(final File file) {
+ return AccessController.doPrivileged(new PrivilegedAction<Properties>() {
+ public Properties run() {
+ return loadFilePrefsImpl(file);
+ }
+ });
+
+ // try {
+ // //FIXME: lines below can be deleted, because it is not required to
+ // persistent at the very beginning
+ // flushFilePrefs(file, result);
+ // } catch (IOException e) {
+ // e.printStackTrace();
+ // }
+ }
+
+ static Properties loadFilePrefsImpl(final File file) {
+ Properties result = new Properties();
+ if (!file.exists()) {
+ file.getParentFile().mkdirs();
+ } else if (file.canRead()) {
+ InputStream in = null;
+ FileLock lock = null;
+ try {
+
+ FileInputStream istream = new FileInputStream(file);
+ // BEGIN android-modified
+ in = new BufferedInputStream(istream, 8192);
+ // END android-modified
+ FileChannel channel = istream.getChannel();
+ lock = channel.lock(0L, Long.MAX_VALUE, true);
+ Document doc = builder.parse(in);
+ // BEGIN android-modified
+ NodeList entries = selectNodeList(doc
+ .getDocumentElement(), "entry"); //$NON-NLS-1$
+ // END android-modified
+ int length = entries.getLength();
+ for (int i = 0; i < length; i++) {
+ Element node = (Element) entries.item(i);
+ String key = node.getAttribute("key"); //$NON-NLS-1$
+ String value = node.getAttribute("value"); //$NON-NLS-1$
+ result.setProperty(key, value);
+ }
+ return result;
+ } catch (Exception e) {
+ e.printStackTrace();
+ } finally {
+ try {
+ lock.release();
+ } catch (Exception e) {//ignore
+ }
+ try {
+ in.close();
+ } catch (Exception e) {//ignore
+ }
+ }
+ } else {
+ file.delete();
+ }
+ return result;
+ }
+
+ /**
+ *
+ * @param file
+ * @param prefs
+ * @throws PrivilegedActionException
+ */
+ static void flushFilePrefs(final File file, final Properties prefs) throws PrivilegedActionException {
+ AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
+ public Object run() throws IOException {
+ flushFilePrefsImpl(file, prefs);
+ return null;
+ }
+ });
+ }
+
+ static void flushFilePrefsImpl(File file, Properties prefs) throws IOException {
+ BufferedWriter out = null;
+ FileLock lock = null;
+ try {
+ FileOutputStream ostream = new FileOutputStream(file);
+ // BEGIN android-modified
+ out = new BufferedWriter(new OutputStreamWriter(ostream, "UTF-8"), 8192); //$NON-NLS-1$
+ // END android-modified
+ FileChannel channel = ostream.getChannel();
+ lock = channel.lock();
+ out.write(HEADER);
+ out.newLine();
+ out.write(FILE_PREFS);
+ out.newLine();
+ if (prefs.size() == 0) {
+ exportEntries(EMPTY_SARRAY, EMPTY_SARRAY, out);
+ } else {
+ String[] keys = prefs.keySet().toArray(new String[prefs.size()]);
+ int length = keys.length;
+ String[] values = new String[length];
+ for (int i = 0; i < length; i++) {
+ values[i] = prefs.getProperty(keys[i]);
+ }
+ exportEntries(keys, values, out);
+ }
+ out.flush();
+ } finally {
+ try {
+ lock.release();
+ } catch (Exception e) {//ignore
+ }
+ try {
+ if (null != out) {
+ out.close();
+ }
+ } catch (Exception e) {//ignore
+ }
+ }
+ }
+}
+
+
diff --git a/prefs/src/main/java/java/util/prefs/package.html b/prefs/src/main/java/java/util/prefs/package.html
new file mode 100644
index 0000000..8a3dd33
--- /dev/null
+++ b/prefs/src/main/java/java/util/prefs/package.html
@@ -0,0 +1,14 @@
+<html>
+ <body>
+ <p>
+ This package provides a preferences mechanism, that is, a means of writing
+ configuration data (key/value pairs) to a persistent data store and
+ retrieving it from there. There are two different kinds of stores
+ available: one for storing user data and one for storing system
+ configuration data. Since the underlying implementation is dependent
+ on the operating system, this package is designed to allow the installation
+ of a custom service provider implementation.
+ </p>
+ @since Android 1.0
+ </body>
+</html>
diff --git a/prefs/src/main/java/org/apache/harmony/prefs/internal/nls/Messages.java b/prefs/src/main/java/org/apache/harmony/prefs/internal/nls/Messages.java
new file mode 100644
index 0000000..cfc7236
--- /dev/null
+++ b/prefs/src/main/java/org/apache/harmony/prefs/internal/nls/Messages.java
@@ -0,0 +1,140 @@
+/*
+ * 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.
+ */
+
+/*
+ * THE FILE HAS BEEN AUTOGENERATED BY MSGTOOL TOOL.
+ * All changes made to this file manually will be overwritten
+ * if this tool runs again. Better make changes in the template file.
+ */
+
+// BEGIN android-note
+// Redundant code has been removed and is now called from MsgHelp.
+// END android-note
+
+package org.apache.harmony.prefs.internal.nls;
+
+// BEGIN android-added
+import org.apache.harmony.luni.util.MsgHelp;
+// END android-added
+
+/**
+ * This class retrieves strings from a resource bundle and returns them,
+ * formatting them with MessageFormat when required.
+ * <p>
+ * It is used by the system classes to provide national language support, by
+ * looking up messages in the <code>
+ * org.apache.harmony.prefs.internal.nls.messages
+ * </code>
+ * resource bundle. Note that if this file is not available, or an invalid key
+ * is looked up, or resource bundle support is not available, the key itself
+ * will be returned as the associated message. This means that the <em>KEY</em>
+ * should a reasonable human-readable (english) string.
+ *
+ */
+public class Messages {
+
+ // BEGIN android-changed
+ private static final String sResource =
+ "org.apache.harmony.prefs.internal.nls.messages";
+ // END android-changed
+
+ /**
+ * Retrieves a message which has no arguments.
+ *
+ * @param msg
+ * String the key to look up.
+ * @return String the message for that key in the system message bundle.
+ */
+ static public String getString(String msg) {
+ // BEGIN android-changed
+ return MsgHelp.getString(sResource, msg);
+ // END android-changed
+ }
+
+ /**
+ * Retrieves a message which takes 1 argument.
+ *
+ * @param msg
+ * String the key to look up.
+ * @param arg
+ * Object the object to insert in the formatted output.
+ * @return String the message for that key in the system message bundle.
+ */
+ static public String getString(String msg, Object arg) {
+ return getString(msg, new Object[] { arg });
+ }
+
+ /**
+ * Retrieves a message which takes 1 integer argument.
+ *
+ * @param msg
+ * String the key to look up.
+ * @param arg
+ * int the integer to insert in the formatted output.
+ * @return String the message for that key in the system message bundle.
+ */
+ static public String getString(String msg, int arg) {
+ return getString(msg, new Object[] { Integer.toString(arg) });
+ }
+
+ /**
+ * Retrieves a message which takes 1 character argument.
+ *
+ * @param msg
+ * String the key to look up.
+ * @param arg
+ * char the character to insert in the formatted output.
+ * @return String the message for that key in the system message bundle.
+ */
+ static public String getString(String msg, char arg) {
+ return getString(msg, new Object[] { String.valueOf(arg) });
+ }
+
+ /**
+ * Retrieves a message which takes 2 arguments.
+ *
+ * @param msg
+ * String the key to look up.
+ * @param arg1
+ * Object an object to insert in the formatted output.
+ * @param arg2
+ * Object another object to insert in the formatted output.
+ * @return String the message for that key in the system message bundle.
+ */
+ static public String getString(String msg, Object arg1, Object arg2) {
+ return getString(msg, new Object[] { arg1, arg2 });
+ }
+
+ /**
+ * Retrieves a message which takes several arguments.
+ *
+ * @param msg
+ * String the key to look up.
+ * @param args
+ * Object[] the objects to insert in the formatted output.
+ * @return String the message for that key in the system message bundle.
+ */
+ static public String getString(String msg, Object[] args) {
+ // BEGIN android-changed
+ return MsgHelp.getString(sResource, msg, args);
+ // END android-changed
+ }
+
+ // BEGIN android-note
+ // Duplicate code was dropped in favor of using MsgHelp.
+ // END android-note
+}
diff --git a/prefs/src/main/java/org/apache/harmony/prefs/internal/nls/messages.properties b/prefs/src/main/java/org/apache/harmony/prefs/internal/nls/messages.properties
new file mode 100644
index 0000000..8940685
--- /dev/null
+++ b/prefs/src/main/java/org/apache/harmony/prefs/internal/nls/messages.properties
@@ -0,0 +1,33 @@
+# 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.
+
+# messages for EN locale
+prefs.0=Inputstream cannot be null\!
+prefs.1=Invalid DOCTYPE declaration: {0}
+prefs.10=Cannot initiate PreferencesFactory: {0}. Caused by {1}
+prefs.2=This preferences exported version is not supported:{0}
+prefs.3=Cannot get children names for {0}!
+prefs.4=Cannot remove {0}!
+prefs.5=Stream is null
+prefs.6=Name cannot end with '/'\!
+prefs.7=Name cannot contains consecutive '/'\!
+prefs.8=Name length is too long: {0}
+prefs.9=This node has been removed\!
+prefs.A=Cannot remove root node\!
+prefs.B=Enumerate child nodes error\!
+prefs.C=Flush error\!
+prefs.D=Enumerate keys error\!
+prefs.E=Access denied\!
+prefs.F=Remove node error\!
diff --git a/prefs/src/main/resources/META-INF/services/java.util.prefs.PreferencesFactory b/prefs/src/main/resources/META-INF/services/java.util.prefs.PreferencesFactory
new file mode 100644
index 0000000..ebb514c
--- /dev/null
+++ b/prefs/src/main/resources/META-INF/services/java.util.prefs.PreferencesFactory
@@ -0,0 +1 @@
+java.util.prefs.FilePreferencesFactoryImpl
diff --git a/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/AbstractPreferencesTest.java b/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/AbstractPreferencesTest.java
new file mode 100644
index 0000000..f53a579
--- /dev/null
+++ b/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/AbstractPreferencesTest.java
@@ -0,0 +1,1468 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed 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 org.apache.harmony.prefs.tests.java.util.prefs;
+
+import dalvik.annotation.TestTargets;
+import dalvik.annotation.TestLevel;
+import dalvik.annotation.TestTargetNew;
+import dalvik.annotation.TestTargetClass;
+
+import junit.framework.TestCase;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.prefs.AbstractPreferences;
+import java.util.prefs.BackingStoreException;
+import java.util.prefs.InvalidPreferencesFormatException;
+import java.util.prefs.NodeChangeEvent;
+import java.util.prefs.NodeChangeListener;
+import java.util.prefs.PreferenceChangeEvent;
+import java.util.prefs.PreferenceChangeListener;
+import java.util.prefs.Preferences;
+
+@TestTargetClass(AbstractPreferences.class)
+public class AbstractPreferencesTest extends TestCase {
+
+ AbstractPreferences pref;
+
+ static AbstractPreferences root = (AbstractPreferences) Preferences.userRoot();
+
+ static final String nodeName = "mock";
+
+ static AbstractPreferences parent = null;
+
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ parent = (AbstractPreferences) Preferences.userNodeForPackage(this.getClass());
+/*
+ String str[] = parent.childrenNames();
+ for (int i = 0; i < str.length; i++) {
+ System.out.print(str[i] + " ");
+ }
+ System.out.println();
+/**/
+ pref = (AbstractPreferences) parent.node(nodeName);
+ }
+
+ protected void tearDown() throws Exception {
+/* String str[] = parent.childrenNames();
+ for (int i = 0; i < str.length; i++) {
+ System.out.print(str[i] + " ");
+ }
+ System.out.println();/**/
+ parent.removeNode();
+ super.tearDown();
+ }
+
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "toString",
+ args = {}
+ )
+ public void testToString() {
+ assertTrue(pref.toString().contains(nodeName));
+ }
+
+ @TestTargets({
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "Tests putSpi indirectly",
+ method = "put",
+ args = {java.lang.String.class, java.lang.String.class}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "Tests putSpi indirectly",
+ method = "putSpi",
+ args = {java.lang.String.class, java.lang.String.class}
+ )
+ })
+ public void testPut() throws BackingStoreException {
+ pref.put("Value", "String");
+ pref.flush();
+
+ assertEquals("String", pref.get("Value", ":"));
+
+ try {
+ pref.put(null, "Exception");
+ fail("NullPointerException expected");
+ } catch (NullPointerException e) {
+ //expected
+ }
+
+ int i;
+ StringBuffer sb = new StringBuffer();
+
+ for (i = 0; i < Preferences.MAX_KEY_LENGTH + 1; i++) {
+ sb.append('c');
+ }
+
+ try {
+ pref.put(new String(sb), "Exception");
+ fail("IllegalArgumentException expected");
+ } catch (IllegalArgumentException e) {
+ //expected
+ }
+
+ sb = new StringBuffer();
+
+ for (i = 0; i < Preferences.MAX_VALUE_LENGTH + 1; i++) {
+ sb.append('c');
+ }
+
+ try {
+ pref.put("DoubleValue", new String(sb));
+ fail("IllegalArgumentException expected");
+ } catch (IllegalArgumentException e) {
+ //expected
+ }
+
+ pref.removeNode();
+
+ try {
+ pref.put("DoubleValue", "Exception");
+ fail("IllegalStateException expected");
+ } catch (IllegalStateException e) {
+ //expected
+ }
+ }
+
+ @TestTargets({
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "getSpi tested indirectly.",
+ method = "get",
+ args = {java.lang.String.class, java.lang.String.class}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "getSpi tested indirectly.",
+ method = "getSpi",
+ args = {java.lang.String.class}
+ )
+ })
+ public void testGet() throws BackingStoreException {
+ pref.put("Value", "String");
+ pref.putDouble("DoubleValue", new Double(9.10938188e-31));
+ pref.putBoolean("BoolValue", true);
+ pref.flush();
+
+ assertEquals("String", pref.get("Value", ":"));
+ assertEquals("true", pref.get("BoolValue", ":"));
+ assertEquals("9.10938188E-31", pref.get("DoubleValue", null));
+
+ try {
+ pref.get(null, "Exception");
+ fail("NullPointerException expected");
+ } catch (NullPointerException e) {
+ //expected
+ }
+
+ pref.removeNode();
+
+ try {
+ pref.get("DoubleValue", "Exception");
+ fail("IllegalStateException expected");
+ } catch (IllegalStateException e) {
+ //expected
+ }
+ }
+
+ @TestTargets({
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "Indirectly checks removeSpi",
+ method = "remove",
+ args = {java.lang.String.class}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "Indirectly checks removeSpi",
+ method = "removeSpi",
+ args = {java.lang.String.class}
+ )
+ })
+ public void testRemove() throws BackingStoreException {
+ String[] keyArray = new String[]{"Value", "DoubleValue", "LongValue", "IntValue"};
+ pref.put(keyArray[0], "String");
+ pref.putDouble(keyArray[1], new Double(9.10938188e-31));
+ pref.putLong(keyArray[2], new Long(Long.MIN_VALUE));
+ pref.putInt(keyArray[3], 299792458);
+ pref.node("New node");
+ pref.flush();
+
+ String[] str = pref.keys();
+ assertEquals(keyArray.length, str.length);
+ for(int i = 0; i < keyArray.length; i++) {
+ pref.remove(keyArray[i]);
+ str = pref.keys();
+ assertEquals(keyArray.length - i - 1, str.length);
+ }
+ assertEquals(1, pref.childrenNames().length);
+ pref.remove("New node");
+ assertEquals(1, pref.childrenNames().length);
+
+ pref.removeNode();
+
+ try {
+ pref.remove("New node");
+ fail("IllegalStateException expected");
+ } catch (IllegalStateException e) {
+ //expected
+ }
+ }
+
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "clear",
+ args = {}
+ )
+ public void testClear() throws BackingStoreException {
+ AbstractPreferences ap = (AbstractPreferences) pref.node("New node");
+ pref.putInt("IntValue", 33);
+ pref.putBoolean("BoolValue", true);
+ pref.flush();
+ assertTrue(pref.getBoolean("BoolValue", false));
+ assertEquals(33, pref.getInt("IntValue", 22));
+ assertEquals(1, pref.childrenNames().length);
+ pref.clear();
+ assertFalse(pref.getBoolean("BoolValue", false));
+ assertEquals(22, pref.getInt("IntValue", 22));
+ assertEquals(1, pref.childrenNames().length);
+
+ pref.removeNode();
+
+ try {
+ pref.clear();
+ fail("IllegalStateException expected");
+ } catch (IllegalStateException e) {
+ //expected
+ }
+
+ try {
+ ap.clear();
+ fail("IllegalStateException expected");
+ } catch (IllegalStateException e) {
+ //expected
+ }
+ }
+
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "putInt",
+ args = {java.lang.String.class, int.class}
+ )
+ public void testPutInt() throws BackingStoreException {
+ pref.putInt("IntValue", 299792458);
+ pref.flush();
+
+ assertEquals(299792458, pref.getInt("IntValue", new Integer(1)));
+
+ try {
+ pref.putInt(null, new Integer(1));
+ fail("NullPointerException expected");
+ } catch (NullPointerException e) {
+ //expected
+ }
+
+ int i;
+ StringBuffer sb = new StringBuffer();
+
+ for (i = 0; i < Preferences.MAX_KEY_LENGTH + 1; i++) {
+ sb.append('c');
+ }
+
+ try {
+ pref.putInt(new String(sb), new Integer(1));
+ fail("IllegalArgumentException expected");
+ } catch (IllegalArgumentException e) {
+ //expected
+ }
+
+ pref.removeNode();
+
+ try {
+ pref.putInt("IntValue", new Integer(1));
+ fail("IllegalStateException expected");
+ } catch (IllegalStateException e) {
+ //expected
+ }
+ }
+
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "getInt",
+ args = {java.lang.String.class, int.class}
+ )
+ public void testGetInt() throws BackingStoreException {
+ pref.put("Value", "String");
+ pref.putDouble("DoubleValue", new Double(9.10938188e-31));
+ pref.putLong("LongValue", new Long(Long.MIN_VALUE));
+ pref.putInt("IntValue", 299792458);
+ pref.flush();
+
+ assertEquals(1, pref.getInt("Value", new Integer(1)));
+ assertEquals(1, pref.getInt("LongValue", new Integer(1)));
+ assertEquals(1, pref.getInt("DoubleValue", new Integer(1)));
+ assertEquals(299792458, pref.getInt("IntValue", new Integer(1)));
+
+ try {
+ pref.getInt(null, new Integer(1));
+ fail("NullPointerException expected");
+ } catch (NullPointerException e) {
+ //expected
+ }
+
+ pref.removeNode();
+
+ try {
+ pref.getInt("IntValue", new Integer(1));
+ fail("IllegalStateException expected");
+ } catch (IllegalStateException e) {
+ //expected
+ }
+ }
+
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "putLong",
+ args = {java.lang.String.class, long.class}
+ )
+ public void testPutLong() throws BackingStoreException {
+ pref.putLong("LongValue", new Long(299792458));
+ pref.flush();
+
+ assertEquals(299792458L, pref.getLong("LongValue", new Long(1)));
+
+ try {
+ pref.putLong(null, new Long(1));
+ fail("NullPointerException expected");
+ } catch (NullPointerException e) {
+ //expected
+ }
+
+ int i;
+ StringBuffer sb = new StringBuffer();
+
+ for (i = 0; i < Preferences.MAX_KEY_LENGTH + 1; i++) {
+ sb.append('c');
+ }
+
+ try {
+ pref.putLong(new String(sb), new Long(1));
+ fail("IllegalArgumentException expected");
+ } catch (IllegalArgumentException e) {
+ //expected
+ }
+
+ pref.removeNode();
+
+ try {
+ pref.putLong("LongValue", new Long(1));
+ fail("IllegalStateException expected");
+ } catch (IllegalStateException e) {
+ //expected
+ }
+ }
+
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "getLong",
+ args = {java.lang.String.class, long.class}
+ )
+ public void testGetLong() throws BackingStoreException {
+ pref.put("Value", "String");
+ pref.putDouble("DoubleValue", new Double(9.10938188e-31));
+ pref.putLong("LongValue", new Long(Long.MIN_VALUE));
+ pref.putInt("IntValue", 299792458);
+ pref.flush();
+
+ assertEquals(1L, pref.getLong("Value", new Long(1)));
+ assertEquals(Long.MIN_VALUE, pref.getLong("LongValue", new Long(1)));
+ assertEquals(1L, pref.getLong("DoubleValue", new Long(1)));
+ assertEquals(299792458L, pref.getLong("IntValue", new Long(1)));
+
+ try {
+ pref.getLong(null, new Long(1));
+ fail("NullPointerException expected");
+ } catch (NullPointerException e) {
+ //expected
+ }
+
+ pref.removeNode();
+
+ try {
+ pref.getLong("LongValue", new Long(1));
+ fail("IllegalStateException expected");
+ } catch (IllegalStateException e) {
+ //expected
+ }
+ }
+
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "putBoolean",
+ args = {java.lang.String.class, boolean.class}
+ )
+ public void testPutBoolean() throws BackingStoreException {
+ pref.putBoolean("BoolValue", true);
+ pref.flush();
+
+ assertTrue(pref.getBoolean("BoolValue", false));
+
+ try {
+ pref.putBoolean(null, true);
+ fail("NullPointerException expected");
+ } catch (NullPointerException e) {
+ //expected
+ }
+
+ int i;
+ StringBuffer sb = new StringBuffer();
+
+ for (i = 0; i < Preferences.MAX_KEY_LENGTH + 1; i++) {
+ sb.append('c');
+ }
+
+ try {
+ pref.putBoolean(new String(sb), true);
+ fail("IllegalArgumentException expected");
+ } catch (IllegalArgumentException e) {
+ //expected
+ }
+
+ pref.removeNode();
+
+ try {
+ pref.putBoolean("DoubleValue", true);
+ fail("IllegalStateException expected");
+ } catch (IllegalStateException e) {
+ //expected
+ }
+ }
+
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "getBoolean",
+ args = {java.lang.String.class, boolean.class}
+ )
+ public void testGetBoolean() throws BackingStoreException {
+ pref.put("Value", "String");
+ pref.putDouble("DoubleValue", new Double(9.10938188e-31));
+ pref.putBoolean("BoolValue", true);
+ pref.flush();
+
+ assertFalse(pref.getBoolean("Value", false));
+ assertTrue(pref.getBoolean("BoolValue", false));
+ assertFalse(pref.getBoolean("DoubleValue", false));
+
+ try {
+ pref.getBoolean(null, true);
+ fail("NullPointerException expected");
+ } catch (NullPointerException e) {
+ //expected
+ }
+
+ pref.removeNode();
+
+ try {
+ pref.getBoolean("DoubleValue", true);
+ fail("IllegalStateException expected");
+ } catch (IllegalStateException e) {
+ //expected
+ }
+ }
+
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "putFloat",
+ args = {java.lang.String.class, float.class}
+ )
+ public void testPutFloat() throws BackingStoreException {
+ pref.putFloat("FloatValue", new Float(1.602e-19));
+ pref.flush();
+
+ assertEquals(new Float(1.602e-19), pref.getFloat("FloatValue", new Float(0.2)));
+
+ try {
+ pref.putFloat(null, new Float(0.1));
+ fail("NullPointerException expected");
+ } catch (NullPointerException e) {
+ //expected
+ }
+
+ int i;
+ StringBuffer sb = new StringBuffer();
+
+ for (i = 0; i < Preferences.MAX_KEY_LENGTH + 1; i++) {
+ sb.append('c');
+ }
+
+ try {
+ pref.putFloat(new String(sb), new Float(0.1));
+ fail("IllegalArgumentException expected");
+ } catch (IllegalArgumentException e) {
+ //expected
+ }
+
+ pref.removeNode();
+
+ try {
+ pref.putFloat("FloatValue", new Float(0.1));
+ fail("IllegalStateException expected");
+ } catch (IllegalStateException e) {
+ //expected
+ }
+ }
+
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "getFloat",
+ args = {java.lang.String.class, float.class}
+ )
+ public void testGetFloat() throws BackingStoreException {
+ pref.put("Value", "String");
+ pref.putDouble("DoubleValue", new Double(9.10938188e-31));
+ pref.putFloat("FloatValue", new Float(-0.123));
+ pref.putInt("IntValue", 299792458);
+ pref.flush();
+
+ assertEquals(new Float(0.1), pref.getFloat("Value", new Float(0.1)));
+ assertEquals(new Float(-0.123), pref.getFloat("FloatValue", new Float(0.2)));
+ assertEquals(new Float(9.109382e-31), pref.getFloat("DoubleValue", new Float(2.14)));
+ assertEquals(new Float(2.99792448e8), pref.getFloat("IntValue", new Float(5)));
+
+ try {
+ pref.getFloat(null, new Float(0.1));
+ fail("NullPointerException expected");
+ } catch (NullPointerException e) {
+ //expected
+ }
+
+ pref.removeNode();
+
+ try {
+ pref.getFloat("FloatValue", new Float(0.1));
+ fail("IllegalStateException expected");
+ } catch (IllegalStateException e) {
+ //expected
+ }
+ }
+
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "putDouble",
+ args = {java.lang.String.class, double.class}
+ )
+ public void testPutDouble() throws BackingStoreException {
+ pref.putDouble("DoubleValue", new Double(9.10938188e-31));
+ pref.flush();
+
+ assertEquals(new Double(9.10938188e-31), pref.getDouble("DoubleValue", new Double(2.14)));
+
+ try {
+ pref.putDouble(null, new Double(0.1));
+ fail("NullPointerException expected");
+ } catch (NullPointerException e) {
+ //expected
+ }
+
+ int i;
+ StringBuffer sb = new StringBuffer();
+
+ for (i = 0; i < Preferences.MAX_KEY_LENGTH + 1; i++) {
+ sb.append('c');
+ }
+
+ try {
+ pref.putDouble(new String(sb), new Double(0.1));
+ fail("IllegalArgumentException expected");
+ } catch (IllegalArgumentException e) {
+ //expected
+ }
+
+ pref.removeNode();
+
+ try {
+ pref.putDouble("DoubleValue", new Double(0.1));
+ fail("IllegalStateException expected");
+ } catch (IllegalStateException e) {
+ //expected
+ }
+ }
+
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "getDouble",
+ args = {java.lang.String.class, double.class}
+ )
+ public void testGetDouble() throws BackingStoreException {
+ pref.put("Value", "String");
+ pref.putDouble("DoubleValue", new Double(9.10938188e-31));
+ pref.putBoolean("BoolValue", true);
+ pref.putInt("IntValue", 299792458);
+ pref.flush();
+
+ assertEquals(new Double(0.1), pref.getDouble("Value", new Double(0.1)));
+ assertEquals(new Double(0.2), pref.getDouble("BoolValue", new Double(0.2)));
+ assertEquals(new Double(9.10938188e-31), pref.getDouble("DoubleValue", new Double(2.14)));
+ assertEquals(new Double(2.99792458e8), pref.getDouble("IntValue", new Double(5)));
+
+ try {
+ pref.getDouble(null, new Double(0.1));
+ fail("NullPointerException expected");
+ } catch (NullPointerException e) {
+ //expected
+ }
+
+ pref.removeNode();
+
+ try {
+ pref.getDouble("DoubleValue", new Double(0.1));
+ fail("IllegalStateException expected");
+ } catch (IllegalStateException e) {
+ //expected
+ }
+ }
+
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "putByteArray",
+ args = {java.lang.String.class, byte[].class}
+ )
+ public void testPutByteArray() throws BackingStoreException {
+ byte[] bArray = new byte[]{1, 2, 3, 4, 5};
+ byte[] array = null;
+ int i;
+ pref.putByteArray("Array", bArray);
+ pref.flush();
+
+ array = pref.getByteArray("Array", null);
+ assertEquals(bArray.length, array.length);
+ for(i = 0; i < bArray.length; i++) {
+ assertEquals(bArray[i], array[i]);
+ }
+
+ try {
+ pref.putByteArray(null, bArray);
+ fail("NullPointerException expected");
+ } catch (NullPointerException e) {
+ //expected
+ }
+
+ StringBuffer sb = new StringBuffer();
+
+ for (i = 0; i < Preferences.MAX_KEY_LENGTH + 1; i++) {
+ sb.append('c');
+ }
+
+ try {
+ pref.putByteArray(new String(sb), bArray);
+ fail("IllegalArgumentException expected");
+ } catch (IllegalArgumentException e) {
+ //expected
+ }
+
+ bArray = new byte[Preferences.MAX_VALUE_LENGTH * 3 / 4 + 1];
+
+ try {
+ pref.putByteArray("Big array", bArray);
+ fail("IllegalArgumentException expected");
+ } catch (IllegalArgumentException e) {
+ //expected
+ }
+
+ pref.removeNode();
+
+ try {
+ pref.putByteArray("Array", new byte[10]);
+ fail("IllegalStateException expected");
+ } catch (IllegalStateException e) {
+ //expected
+ }
+ }
+
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "getByteArray",
+ args = {java.lang.String.class, byte[].class}
+ )
+ public void testGetByteArray() throws BackingStoreException {
+ byte[] bArray = new byte[]{1, 2, 3, 4, 5};
+ byte[] tmp = new byte[]{5};
+ byte[] array = null;
+ int i;
+ pref.put("Value", "String");
+ pref.putDouble("DoubleValue", new Double(9.10938188e-31));
+ pref.putByteArray("Array", bArray);
+ pref.flush();
+
+ array = pref.getByteArray("Value", tmp);
+ assertEquals(tmp.length, array.length);
+ for(i = 0; i < tmp.length; i++) {
+ assertEquals(tmp[i], array[i]);
+ }
+
+ array = pref.getByteArray("DoubleValue", tmp);
+ assertEquals(tmp.length, array.length);
+ for(i = 0; i < tmp.length; i++) {
+ assertEquals(tmp[i], array[i]);
+ }
+
+ array = pref.getByteArray("Array", tmp);
+ assertEquals(bArray.length, array.length);
+ for(i = 0; i < bArray.length; i++) {
+ assertEquals(bArray[i], array[i]);
+ }
+
+ try {
+ pref.getByteArray(null, tmp);
+ fail("NullPointerException expected");
+ } catch (NullPointerException e) {
+ //expected
+ }
+
+ pref.removeNode();
+
+ try {
+ pref.getByteArray("Array", tmp);
+ fail("IllegalStateException expected");
+ } catch (IllegalStateException e) {
+ //expected
+ }
+ }
+
+ @TestTargets({
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "keysSpi tested indirectly",
+ method = "keys",
+ args = {}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "keysSpi tested indirectly",
+ method = "keysSpi",
+ args = {}
+ )
+ })
+ public void testKeys() throws BackingStoreException {
+ String[] keyArray = new String[]{"Value", "DoubleValue", "BoolValue", "IntValue"};
+ String nodeStr = "New node";
+ pref.node(nodeStr);
+ pref.put(keyArray[0], "String");
+ pref.putDouble(keyArray[1], new Double(9.10938188e-31));
+ pref.putBoolean(keyArray[2], true);
+ pref.putInt(keyArray[3], 299792458);
+ pref.flush();
+
+ String[] str = pref.keys();
+ assertEquals(keyArray.length, str.length);
+ for(int i = 0; i < str.length; i++) {
+ boolean flag = false;
+ for(int j = 0; j < keyArray.length; j++) {
+ if (str[i].compareTo(keyArray[j]) == 0) {
+ flag = true;
+ break;
+ }
+ }
+ assertTrue(str[i].compareTo(nodeStr) != 0);
+ assertTrue(flag);
+ }
+
+ pref.removeNode();
+
+ try {
+ pref.keys();
+ fail("IllegalStateException expected");
+ } catch(IllegalStateException e) {
+ //expected
+ }
+ }
+
+ @TestTargets({
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "BackingStoreException can not be checked. childrenNamesSpi checked indirectly.",
+ method = "childrenNames",
+ args = {}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "BackingStoreException can not be checked. childrenNamesSpi checked indirectly.",
+ method = "childrenNamesSpi",
+ args = {}
+ )
+ })
+ public void testChildrenNames() throws BackingStoreException {
+ AbstractPreferences first = (AbstractPreferences) pref.node("First node");
+ AbstractPreferences second = (AbstractPreferences) pref.node("Second node");
+
+ assertEquals(2, pref.childrenNames().length);
+ assertEquals(0, first.childrenNames().length);
+ assertEquals(0, second.childrenNames().length);
+
+ second.removeNode();
+
+ try {
+ second.childrenNames();
+ fail("IllegalStateException expected");
+ } catch (IllegalStateException e) {
+ //expected
+ }
+
+ pref.removeNode();
+
+ try {
+ first.childrenNames();
+ fail("IllegalStateException expected");
+ } catch (IllegalStateException e) {
+ //expected
+ }
+ }
+
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "parent",
+ args = {}
+ )
+ public void testParent() throws BackingStoreException {
+ AbstractPreferences node = (AbstractPreferences) pref.node("First node/sub node");
+
+ assertTrue(node.parent().name().compareTo("First node") == 0);
+
+ pref.removeNode();
+
+ try {
+ node.parent();
+ fail("IllegalStateException expected");
+ } catch (IllegalStateException e) {
+ //expected
+ }
+ }
+
+ @TestTargets({
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "Indirecly checks childSpi",
+ method = "node",
+ args = {java.lang.String.class}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "Indirecly checks childSpi",
+ method = "childSpi",
+ args = {java.lang.String.class}
+ )
+ })
+ public void testNode() throws BackingStoreException {
+ AbstractPreferences first = (AbstractPreferences) pref.node("First node");
+ AbstractPreferences second = (AbstractPreferences) pref.node("Second node");
+
+ try {
+ first.node("blabla/");
+ fail("IllegalArgumentException expected");
+ } catch (IllegalArgumentException e) {
+ //expected
+ }
+
+ try {
+ first.node("///invalid");
+ fail("IllegalArgumentException expected");
+ } catch (IllegalArgumentException e) {
+ //expected
+ }
+
+ StringBuffer sb = new StringBuffer();
+
+ for (int i = 0; i < Preferences.MAX_NAME_LENGTH; i++) {
+ sb.append('c');
+ }
+ first.node(new String(sb));
+ sb.append('c');
+
+ try {
+ first.node(new String(sb));
+ fail("IllegalArgumentException expected");
+ } catch (IllegalArgumentException e) {
+ //expected
+ }
+
+ second.removeNode();
+
+ try {
+ second.node("");
+ fail("IllegalStateException expected");
+ } catch (IllegalStateException e) {
+ //expected
+ }
+ pref.removeNode();
+ try {
+ first.node("");
+ fail("IllegalStateException expected");
+ } catch (IllegalStateException e) {
+ //expected
+ }
+ }
+
+ @TestTargets({
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "getChild tested indirectly",
+ method = "nodeExists",
+ args = {java.lang.String.class}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "getChild tested indirectly",
+ method = "getChild",
+ args = {java.lang.String.class}
+ )
+ })
+ public void testNodeExists() throws BackingStoreException {
+ AbstractPreferences ap1 = (AbstractPreferences) pref.node("First node");
+ AbstractPreferences ap2 = (AbstractPreferences) pref.node("Second node");
+ pref.putInt("IntegerValue", 33);
+ pref.putBoolean("BoolValue", true);
+ pref.flush();
+
+ assertTrue(pref.nodeExists("First node"));
+ assertTrue(pref.nodeExists("Second node"));
+ assertFalse(pref.nodeExists("IntegerValue"));
+ assertFalse(pref.nodeExists("BoolValue"));
+ assertFalse(pref.nodeExists("Value"));
+ assertFalse(pref.nodeExists(nodeName));
+
+ try {
+ pref.nodeExists("///invalid");
+ fail("IllegalArgumentException expected");
+ } catch (IllegalArgumentException e) {
+ //expected
+ }
+
+ pref.removeNode();
+
+ try {
+ pref.nodeExists("Exception");
+ fail("IllegalStateException expected");
+ } catch (IllegalStateException e) {
+ //expected
+ }
+ }
+
+ @TestTargets({
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "removeNode",
+ args = {}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "removeNodeSpi",
+ args = {}
+ )
+ })
+ public void testRemoveNode() throws BackingStoreException {
+ String[] nodeArray = new String[]{"First node", "Second node", "Last node"};
+ int i;
+ pref.put("Key", "String");
+ for (i = 0; i < nodeArray.length; i++) {
+ pref.node(nodeArray[i]);
+ }
+ pref.flush();
+
+ String[] str = pref.childrenNames();
+ assertEquals(nodeArray.length, str.length);
+ for(i = 0; i < nodeArray.length; i++) {
+ pref.node(nodeArray[i]).removeNode();
+ str = pref.childrenNames();
+ assertEquals(nodeArray.length - i - 1, str.length);
+ }
+ assertEquals(1, pref.keys().length);
+ pref.node("Key").removeNode();
+ assertEquals(1, pref.keys().length);
+
+ pref.removeNode();
+
+ try {
+ pref.removeNode();
+ fail("IllegalStateException expected");
+ } catch (IllegalStateException e) {
+ //expected
+ }
+
+ try {
+ root.removeNode();
+ fail("UnsupportedOperationException expected");
+ } catch (UnsupportedOperationException e) {
+ //expected
+ }
+ }
+
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "name",
+ args = {}
+ )
+ public void testName() {
+ AbstractPreferences first = (AbstractPreferences) pref.node("First node");
+ AbstractPreferences second = (AbstractPreferences) pref.node("Second node/sub node");
+
+ assertTrue(first.name().compareTo("First node") == 0);
+ assertFalse(first.name().compareTo("Second node") == 0);
+ assertTrue(second.name().compareTo("sub node") == 0);
+ }
+
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "absolutePath",
+ args = {}
+ )
+ public void testAbsolutePath() {
+ assertEquals(parent.absolutePath() + "/" + nodeName, pref.absolutePath());
+ assertEquals(parent.absolutePath() + "/" + "new node", parent.node("new node").absolutePath());
+ }
+
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "isUserNode",
+ args = {}
+ )
+ public void testIsUserNode() {
+ assertTrue(parent.isUserNode());
+ assertFalse(Preferences.systemRoot().isUserNode());
+ }
+
+ @TestTargets({
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "Indirectly checks syncSpi",
+ method = "sync",
+ args = {}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "Indirectly checks syncSpi",
+ method = "syncSpi",
+ args = {}
+ )
+ })
+ public void testSync() throws BackingStoreException {
+ pref.node("new node/sub node");
+ pref.sync();
+
+ pref.removeNode();
+
+ try {
+ pref.sync();
+ fail("IllegalStateException expected");
+ } catch (IllegalStateException e) {
+ //expected
+ }
+ }
+
+ class MockPreferenceChangeListener implements PreferenceChangeListener {
+ private boolean flagChange = false;
+
+ public void preferenceChange(PreferenceChangeEvent arg0) {
+ flagChange = true;
+ }
+
+ public boolean isChanged () {
+ boolean retVal = flagChange;
+ flagChange = false;
+ return retVal;
+ }
+ }
+
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "addPreferenceChangeListener",
+ args = {java.util.prefs.PreferenceChangeListener.class}
+ )
+ public void testAddPreferenceChangeListener() throws BackingStoreException {
+ MockPreferenceChangeListener mpcl = new MockPreferenceChangeListener();
+ parent.addPreferenceChangeListener(mpcl);
+ assertFalse(mpcl.isChanged());
+ pref.node("new node");
+ pref.flush();
+ parent.flush();
+ assertFalse(mpcl.isChanged());
+ parent.node("new node");
+ parent.flush();
+ assertFalse(mpcl.isChanged());
+ parent.putInt("IntValue", 33);
+ parent.flush();
+ parent.flush();
+ assertTrue(mpcl.isChanged());
+ assertEquals(33, parent.getInt("IntValue", 22));
+ parent.flush();
+ assertFalse(mpcl.isChanged());
+ assertEquals(22, parent.getInt("Missed Value", 22));
+ parent.flush();
+ assertFalse(mpcl.isChanged());
+ }
+
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "removePreferenceChangeListener",
+ args = {java.util.prefs.PreferenceChangeListener.class}
+ )
+ public void testRemovePreferenceChangeListener() throws BackingStoreException {
+ MockPreferenceChangeListener mpcl = new MockPreferenceChangeListener();
+ parent.addPreferenceChangeListener(mpcl);
+ assertFalse(mpcl.isChanged());
+ parent.putInt("IntValue", 33);
+ parent.flush();
+ assertTrue(mpcl.isChanged());
+ parent.removePreferenceChangeListener(mpcl);
+ parent.putInt("IntValue", 33);
+ parent.flush();
+ assertFalse(mpcl.isChanged());
+ }
+
+ class MockNodeChangeListener implements NodeChangeListener {
+ private boolean flagAdded = false;
+ private boolean flagRemoved = false;
+
+ public void childAdded(NodeChangeEvent arg0) {
+ flagAdded = true;
+ }
+
+ public void childRemoved(NodeChangeEvent arg0) {
+ flagRemoved = true;
+ }
+
+ public boolean isAdded() {
+ return flagAdded;
+ }
+
+ public boolean isRemoved() {
+ return flagRemoved;
+ }
+ }
+
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "addNodeChangeListener",
+ args = {java.util.prefs.NodeChangeListener.class}
+ )
+ public void testAddNodeChangeListener() throws BackingStoreException {
+ MockNodeChangeListener mncl = new MockNodeChangeListener();
+ parent.addNodeChangeListener(mncl);
+ pref.node("test");
+ pref.flush();
+ parent.flush();
+ assertFalse(mncl.isAdded());
+ assertFalse(mncl.isRemoved());
+ pref.removeNode();
+ parent.flush();
+ assertFalse(mncl.isAdded());
+ assertTrue(mncl.isRemoved());
+ parent.node("new node");
+ parent.flush();
+ assertTrue(mncl.isAdded());
+ assertTrue(mncl.isRemoved());
+ }
+
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "removeNodeChangeListener",
+ args = {java.util.prefs.NodeChangeListener.class}
+ )
+ public void testRemoveNodeChangeListener() throws BackingStoreException {
+ MockNodeChangeListener mncl = new MockNodeChangeListener();
+ parent.addNodeChangeListener(mncl);
+ pref.node("test");
+ pref.flush();
+ parent.flush();
+ assertFalse(mncl.isAdded());
+ assertFalse(mncl.isRemoved());
+ parent.removeNodeChangeListener(mncl);
+ pref.removeNode();
+ parent.flush();
+ assertFalse(mncl.isAdded());
+ assertFalse(mncl.isRemoved());
+ parent.node("new node");
+ parent.flush();
+ assertFalse(mncl.isAdded());
+ assertFalse(mncl.isRemoved());
+ }
+
+ @TestTargets({
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "BackingStoreException, IOException can not be checked.",
+ method = "exportNode",
+ args = {java.io.OutputStream.class}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "BackingStoreException, IOException can not be checked.",
+ method = "flush",
+ args = {}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "BackingStoreException, IOException can not be checked.",
+ method = "flushSpi",
+ args = {}
+ )
+ })
+ public void testExportNode() throws BackingStoreException, IOException, InvalidPreferencesFormatException {
+ AbstractPreferences ap = (AbstractPreferences) pref.node("New node");
+ pref.putInt("IntValue", 33);
+ pref.putBoolean("BoolValue", true);
+ pref.flush();
+
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+
+ pref.exportNode(baos);
+ ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
+
+ assertTrue(pref.getBoolean("BoolValue", false));
+ assertEquals(33, pref.getInt("IntValue", 22));
+ assertEquals(1, pref.childrenNames().length);
+
+ String xmlData = new String(baos.toByteArray());
+
+ assertTrue(xmlData.contains("IntValue"));
+ assertTrue(xmlData.contains("BoolValue"));
+ assertTrue(xmlData.contains("33"));
+ assertTrue(xmlData.contains("true"));
+
+ pref.removeNode();
+
+ try {
+ pref.exportNode(new ByteArrayOutputStream());
+ fail("IllegalStateException expected");
+ } catch (IllegalStateException e) {
+ //expected
+ }
+
+ try {
+ pref.getBoolean("BoolValue", false);
+ fail("IllegalStateException expected");
+ } catch (IllegalStateException e) {
+ //expected
+ }
+ pref = (AbstractPreferences) parent.node(nodeName);
+
+ pref.importPreferences(bais);
+
+ assertTrue(pref.getBoolean("BoolValue", false));
+ assertEquals(33, pref.getInt("IntValue", 22));
+ assertEquals(0, pref.childrenNames().length);
+ }
+
+ @TestTargets({
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "BackingStoreException, IOException can not be checked.",
+ method = "exportSubtree",
+ args = {java.io.OutputStream.class}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "BackingStoreException, IOException can not be checked.",
+ method = "flush",
+ args = {}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "BackingStoreException, IOException can not be checked.",
+ method = "flushSpi",
+ args = {}
+ )
+ })
+ public void testExportSubtree() throws BackingStoreException, IOException, InvalidPreferencesFormatException {
+ AbstractPreferences ap1 = (AbstractPreferences) pref.node("First node");
+ AbstractPreferences ap2 = (AbstractPreferences) pref.node("Second node");
+ pref.putInt("IntegerValue", 33);
+ pref.putBoolean("BoolValue", true);
+ pref.flush();
+
+ ap1.putInt("FirstIntValue", 11);
+ ap2.putDouble("DoubleValue", new Double(6.626e-34));
+
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+
+ pref.exportSubtree(baos);
+ ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
+
+ assertTrue(pref.getBoolean("BoolValue", false));
+ assertEquals(33, pref.getInt("IntegerValue", 22));
+ assertEquals(2, pref.childrenNames().length);
+ assertEquals(11, ap1.getInt("FirstIntValue", 22));
+ assertEquals(new Double(6.626e-34), ap2.getDouble("DoubleValue", new Double (3.14)));
+
+ String xmlData = new String(baos.toByteArray());
+
+ assertTrue(xmlData.contains("IntegerValue"));
+ assertTrue(xmlData.contains("BoolValue"));
+ assertTrue(xmlData.contains("FirstIntValue"));
+ assertTrue(xmlData.contains("DoubleValue"));
+ assertTrue(xmlData.contains("33"));
+ assertTrue(xmlData.contains("true"));
+ assertTrue(xmlData.contains("11"));
+ assertTrue(xmlData.contains("6.626E-34"));
+
+ pref.removeNode();
+
+ try {
+ pref.exportSubtree(new ByteArrayOutputStream());
+ fail("IllegalStateException expected");
+ } catch (IllegalStateException e) {
+ //expected
+ }
+
+ try {
+ pref.getBoolean("BoolValue", false);
+ fail("IllegalStateException expected");
+ } catch (IllegalStateException e) {
+ //expected
+ }
+ pref = (AbstractPreferences) parent.node(nodeName);
+ pref.importPreferences(bais);
+
+ ap1 = (AbstractPreferences) pref.node("First node");
+ ap2 = (AbstractPreferences) pref.node("Second node");
+
+ assertTrue(pref.getBoolean("BoolValue", false));
+ assertEquals(33, pref.getInt("IntegerValue", 22));
+ assertEquals(2, pref.childrenNames().length);
+ assertEquals(11, ap1.getInt("FirstIntValue", 22));
+ assertEquals(new Double(6.626e-34), ap2.getDouble("DoubleValue", new Double (3.14)));
+ }
+
+ class MockAbstractPreferences extends AbstractPreferences {
+ protected MockAbstractPreferences(AbstractPreferences parent, String name) {
+ super(parent, name);
+ }
+
+ @Override
+ protected AbstractPreferences childSpi(String name) {
+ return null;
+ }
+
+ @Override
+ protected String[] childrenNamesSpi() throws BackingStoreException {
+ return null;
+ }
+
+ @Override
+ protected void flushSpi() throws BackingStoreException {
+ }
+
+ @Override
+ protected String getSpi(String key) {
+ return null;
+ }
+
+ @Override
+ protected String[] keysSpi() throws BackingStoreException {
+ return null;
+ }
+
+ @Override
+ protected void putSpi(String key, String value) {
+ }
+
+ @Override
+ protected void removeNodeSpi() throws BackingStoreException {
+ }
+
+ @Override
+ protected void removeSpi(String key) {
+ }
+
+ @Override
+ protected void syncSpi() throws BackingStoreException {
+ }
+ }
+
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "AbstractPreferences",
+ args = {java.util.prefs.AbstractPreferences.class, java.lang.String.class}
+ )
+ public void testAbstractPreferences() {
+ assertNotNull(new MockAbstractPreferences(pref, "node name"));
+ try {
+ new MockAbstractPreferences(pref, "node/name");
+ fail("IllegalArgumentException expected");
+ } catch (IllegalArgumentException e) {
+ //expected
+ }
+
+ try {
+ new MockAbstractPreferences(null, "node");
+ fail("IllegalArgumentException expected");
+ } catch (IllegalArgumentException e) {
+ //expected
+ }
+ }
+
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "Tested indirectly",
+ method = "cachedChildren",
+ args = {}
+ )
+ public void testCachedChildren() throws BackingStoreException {
+ pref.node("First node");
+ pref.node("Second node");
+
+ assertEquals(2, pref.childrenNames().length);
+ }
+
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "No reason to check dummy implementation",
+ method = "isRemoved",
+ args = {}
+ )
+ public void testIsRemoved() {
+ }
+}
diff --git a/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/AllTests.java b/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/AllTests.java
new file mode 100644
index 0000000..29ff362
--- /dev/null
+++ b/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/AllTests.java
@@ -0,0 +1,48 @@
+/* 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 org.apache.harmony.prefs.tests.java.util.prefs;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+/**
+ * Suite for package org.apache.harmony.prefs.tests.java.util.prefs
+ *
+ */
+public class AllTests {
+
+ public static void main(String[] args) {
+ junit.textui.TestRunner.run(AllTests.suite());
+ }
+
+ public static Test suite() {
+ TestSuite suite = tests.TestSuiteFactory.createTestSuite("Suite for org.apache.harmony.prefs.tests.java.util.prefs");
+ // $JUnit-BEGIN$
+ suite.addTestSuite(NodeChangeListenerTest.class);
+ suite.addTestSuite(PreferenceChangeListenerTest.class);
+ suite.addTestSuite(PreferencesFactoryTest.class);
+ suite.addTestSuite(BackingStoreExceptionTest.class);
+ suite.addTestSuite(InvalidPreferencesFormatExceptionTest.class);
+ suite.addTestSuite(PreferenceChangeEventTest.class);
+ suite.addTestSuite(NodeChangeEventTest.class);
+ suite.addTestSuite(PreferencesTest.class);
+ suite.addTestSuite(AbstractPreferencesTest.class);
+ suite.addTestSuite(FilePreferencesImplTest.class);
+ // $JUnit-END$
+ return suite;
+ }
+}
diff --git a/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/BackingStoreExceptionTest.java b/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/BackingStoreExceptionTest.java
new file mode 100644
index 0000000..a98c3b4
--- /dev/null
+++ b/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/BackingStoreExceptionTest.java
@@ -0,0 +1,96 @@
+/* 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 org.apache.harmony.prefs.tests.java.util.prefs;
+
+import dalvik.annotation.TestTargetClass;
+import dalvik.annotation.TestTargets;
+import dalvik.annotation.TestLevel;
+import dalvik.annotation.TestTargetNew;
+
+import java.util.prefs.BackingStoreException;
+
+import junit.framework.TestCase;
+
+import org.apache.harmony.testframework.serialization.SerializationTest;
+
+/**
+ *
+ *
+ */
+@TestTargetClass(BackingStoreException.class)
+public class BackingStoreExceptionTest extends TestCase {
+
+ /*
+ * Class under test for void BackingStoreException(String)
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "BackingStoreException",
+ args = {java.lang.String.class}
+ )
+ public void testBackingStoreExceptionString() {
+ BackingStoreException e = new BackingStoreException("msg");
+ assertNull(e.getCause());
+ assertEquals("msg", e.getMessage());
+ }
+
+ /*
+ * Class under test for void BackingStoreException(Throwable)
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "BackingStoreException",
+ args = {java.lang.Throwable.class}
+ )
+ public void testBackingStoreExceptionThrowable() {
+ Throwable t = new Throwable("msg");
+ BackingStoreException e = new BackingStoreException(t);
+ assertTrue(e.getMessage().indexOf(t.getClass().getName()) >= 0);
+ assertTrue(e.getMessage().indexOf("msg") >= 0);
+ assertEquals(t, e.getCause());
+ }
+
+ /**
+ * @tests serialization/deserialization.
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "Verifies serialization",
+ method = "!SerializationSelf",
+ args = {}
+ )
+ public void testSerializationSelf() throws Exception {
+
+ SerializationTest.verifySelf(new BackingStoreException("msg"));
+ }
+
+ /**
+ * @tests serialization/deserialization compatibility with RI.
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "Verifies serialization",
+ method = "!SerializationGolden",
+ args = {}
+ )
+ public void testSerializationCompatibility() throws Exception {
+
+ SerializationTest.verifyGolden(this, new BackingStoreException("msg"));
+ }
+}
diff --git a/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/FilePreferencesImplTest.java b/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/FilePreferencesImplTest.java
new file mode 100644
index 0000000..a5deaed
--- /dev/null
+++ b/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/FilePreferencesImplTest.java
@@ -0,0 +1,286 @@
+/* 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 org.apache.harmony.prefs.tests.java.util.prefs;
+
+import dalvik.annotation.AndroidOnly;
+import dalvik.annotation.BrokenTest;
+import dalvik.annotation.KnownFailure;
+import dalvik.annotation.TestTargetClass;
+import dalvik.annotation.TestTargets;
+import dalvik.annotation.TestLevel;
+import dalvik.annotation.TestTargetNew;
+
+import java.io.FilePermission;
+import java.io.IOException;
+import java.security.Permission;
+import java.util.prefs.AbstractPreferences;
+import java.util.prefs.BackingStoreException;
+import java.util.prefs.Preferences;
+
+import junit.framework.TestCase;
+
+@TestTargetClass(java.util.prefs.Preferences.class)
+public class FilePreferencesImplTest extends TestCase {
+
+ private String prevFactory;
+ private Preferences uroot;
+ private Preferences sroot;
+
+ public FilePreferencesImplTest() {
+ super();
+ }
+
+ protected void setUp() throws Exception {
+ // prevFactory = System.getProperty("java.util.prefs.PreferencesFactory");
+ // System.setProperty("java.util.prefs.PreferencesFactory", "java.util.prefs.FilePreferencesFactoryImpl");
+
+ // uroot = (AbstractPreferences) Preferences.userRoot();
+ uroot = Preferences.userRoot();
+ sroot = Preferences.systemRoot();
+ }
+
+ protected void tearDown() throws Exception {
+ // if (prevFactory != null)
+ // System.setProperty("java.util.prefs.PreferencesFactory", prevFactory);
+ uroot = null;
+ sroot = null;
+ }
+
+ @TestTargets({
+ @TestTargetNew(
+ level = TestLevel.PARTIAL,
+ notes = "Exceptions checking missed, but method is abstract, probably it is OK",
+ method = "put",
+ args = {java.lang.String.class, java.lang.String.class}
+ ),
+ @TestTargetNew(
+ level = TestLevel.PARTIAL,
+ notes = "Exceptions checking missed, but method is abstract, probably it is OK",
+ method = "get",
+ args = {java.lang.String.class, java.lang.String.class}
+ ),
+ @TestTargetNew(
+ level = TestLevel.PARTIAL,
+ notes = "Exceptions checking missed, but method is abstract, probably it is OK",
+ method = "keys",
+ args = {}
+ )
+ })
+ public void testPutGet() throws IOException, BackingStoreException {
+ uroot.put("ukey1", "value1");
+ assertEquals("value1", uroot.get("ukey1", null));
+ String[] names = uroot.keys();
+ assertTrue(names.length >= 1);
+
+ uroot.put("ukey2", "value3");
+ assertEquals("value3", uroot.get("ukey2", null));
+ uroot.put("\u4e2d key1", "\u4e2d value1");
+ assertEquals("\u4e2d value1", uroot.get("\u4e2d key1", null));
+ names = uroot.keys();
+ assertEquals(3, names.length);
+
+ uroot.clear();
+ names = uroot.keys();
+ assertEquals(0, names.length);
+
+ sroot.put("skey1", "value1");
+ assertEquals("value1", sroot.get("skey1", null));
+ sroot.put("\u4e2d key1", "\u4e2d value1");
+ assertEquals("\u4e2d value1", sroot.get("\u4e2d key1", null));
+ }
+
+ @TestTargetNew(
+ level = TestLevel.PARTIAL,
+ notes = "Exceptions checking missed, but method is abstract, probably it is OK",
+ method = "childrenNames",
+ args = {}
+ )
+ @AndroidOnly("Checking of childNames.length doesn't pass on RI because of " +
+ "it depends on .userPrefs properties.")
+ @KnownFailure("This test fails on emulator. " +
+ "java.util.prefs.BackingStoreException is thrown during calling of" +
+ "childrenNames() method.")
+ public void testChildNodes() throws Exception {
+
+ Preferences child1 = uroot.node("child1");
+ Preferences child2 = uroot.node("\u4e2d child2");
+ Preferences grandchild = child1.node("grand");
+ assertNotNull(grandchild);
+
+ String[] childNames = uroot.childrenNames();
+ for (int i = 0; i < childNames.length; i++) {
+ System.out.println("test:" + childNames[i]);
+ }
+ assertEquals(4, childNames.length);
+
+ childNames = child1.childrenNames();
+ assertEquals(1, childNames.length);
+ for (int i = 0; i < childNames.length; i++) {
+ System.out.println(childNames[i]);
+ }
+
+ childNames = child2.childrenNames();
+ assertEquals(0, childNames.length);
+ for (int i = 0; i < childNames.length; i++) {
+ System.out.println(childNames[i]);
+ }
+
+ child1.removeNode();
+ childNames = uroot.childrenNames();
+ assertEquals(3, childNames.length);
+ for (int i = 0; i < childNames.length; i++) {
+ System.out.println(childNames[i]);
+ }
+ // child2.removeNode();
+ // childNames = uroot.childrenNames();
+ // assertEquals(0, childNames.length);
+
+ child1 = sroot.node("child1");
+ child2 = sroot.node("child2");
+ grandchild = child1.node("grand");
+
+ childNames = sroot.childrenNames();
+
+ for (int i = 0; i < childNames.length; i++) {
+ System.out.println(childNames[i]);
+ }
+ // assertEquals(2, childNames.length);
+
+ childNames = child1.childrenNames();
+ assertEquals(1, childNames.length);
+ for (int i = 0; i < childNames.length; i++) {
+ System.out.println(childNames[i]);
+ }
+
+ childNames = child2.childrenNames();
+ assertEquals(0, childNames.length);
+ for (int i = 0; i < childNames.length; i++) {
+ System.out.println(childNames[i]);
+ }
+ }
+
+ @TestTargets({
+ @TestTargetNew(
+ level = TestLevel.PARTIAL,
+ notes = "SecurityException checking only, but methods are abstract, probably it is OK",
+ method = "node",
+ args = {java.lang.String.class}
+ ),
+ @TestTargetNew(
+ level = TestLevel.PARTIAL,
+ notes = "SecurityException checking only, but methods are abstract, probably it is OK",
+ method = "removeNode",
+ args = {}
+ ),
+ @TestTargetNew(
+ level = TestLevel.PARTIAL,
+ notes = "SecurityException checking only, but methods are abstract, probably it is OK",
+ method = "childrenNames",
+ args = {}
+ ),
+ @TestTargetNew(
+ level = TestLevel.PARTIAL,
+ notes = "SecurityException checking only, but methods are abstract, probably it is OK",
+ method = "flush",
+ args = {}
+ ),
+ @TestTargetNew(
+ level = TestLevel.PARTIAL,
+ notes = "SecurityException checking only, but methods are abstract, probably it is OK",
+ method = "sync",
+ args = {}
+ )
+ })
+ public void testSecurityException() throws BackingStoreException {
+ Preferences child1 = uroot.node("child1");
+ MockFileSecurityManager manager = new MockFileSecurityManager();
+ manager.install();
+ try {
+ try {
+ uroot.node("securityNode");
+ fail("should throw security exception");
+ } catch (SecurityException e) {
+ }
+ try {
+ // need FilePermission(delete);
+ child1.removeNode();
+ fail("should throw security exception");
+ } catch (SecurityException e) {
+ }
+ try {
+ uroot.childrenNames();
+ fail("should throw security exception");
+ } catch (SecurityException e) {
+ }
+ uroot.keys();
+ uroot.put("securitykey", "value1");
+ uroot.remove("securitykey");
+ try {
+ uroot.flush();
+ fail("should throw security exception");
+ } catch (SecurityException e) {
+ } catch (BackingStoreException e) {
+ assertTrue(e.getCause() instanceof SecurityException);
+ }
+ try {
+ uroot.sync();
+ fail("should throw security exception");
+ } catch (SecurityException e) {
+ } catch (BackingStoreException e) {
+ assertTrue(e.getCause() instanceof SecurityException);
+ }
+ } finally {
+ manager.restoreDefault();
+ }
+ }
+
+ static class MockFileSecurityManager extends SecurityManager {
+
+ SecurityManager dflt;
+
+ public MockFileSecurityManager() {
+ super();
+ dflt = System.getSecurityManager();
+ }
+
+ public void install() {
+ System.setSecurityManager(this);
+ }
+
+ public void restoreDefault() {
+ System.setSecurityManager(dflt);
+ }
+
+ public void checkPermission(Permission perm) {
+ if (perm instanceof FilePermission) {
+ throw new SecurityException();
+ } else if (dflt != null) {
+ dflt.checkPermission(perm);
+ }
+ }
+
+ public void checkPermission(Permission perm, Object ctx) {
+ if (perm instanceof FilePermission) {
+ System.out.println(perm.getActions());
+ throw new SecurityException();
+ } else if (dflt != null) {
+ dflt.checkPermission(perm, ctx);
+ }
+ }
+
+ }
+}
diff --git a/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/InvalidPreferencesFormatExceptionTest.java b/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/InvalidPreferencesFormatExceptionTest.java
new file mode 100644
index 0000000..28c953e
--- /dev/null
+++ b/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/InvalidPreferencesFormatExceptionTest.java
@@ -0,0 +1,119 @@
+/* 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 org.apache.harmony.prefs.tests.java.util.prefs;
+
+import dalvik.annotation.TestTargetClass;
+import dalvik.annotation.TestTargets;
+import dalvik.annotation.TestLevel;
+import dalvik.annotation.TestTargetNew;
+
+import java.util.prefs.InvalidPreferencesFormatException;
+
+import junit.framework.TestCase;
+
+import org.apache.harmony.testframework.serialization.SerializationTest;
+
+/**
+ *
+ */
+@TestTargetClass(InvalidPreferencesFormatException.class)
+public class InvalidPreferencesFormatExceptionTest extends TestCase {
+
+ /*
+ * Class under test for void InvalidPreferencesFormatException(String)
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "InvalidPreferencesFormatException",
+ args = {java.lang.String.class}
+ )
+ public void testInvalidPreferencesFormatExceptionString() {
+ InvalidPreferencesFormatException e = new InvalidPreferencesFormatException(
+ "msg");
+ assertNull(e.getCause());
+ assertEquals("msg", e.getMessage());
+ }
+
+ /*
+ * Class under test for void InvalidPreferencesFormatException(String,
+ * Throwable)
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "InvalidPreferencesFormatException",
+ args = {java.lang.String.class, java.lang.Throwable.class}
+ )
+ public void testInvalidPreferencesFormatExceptionStringThrowable() {
+ Throwable t = new Throwable("root");
+ InvalidPreferencesFormatException e = new InvalidPreferencesFormatException(
+ "msg", t);
+ assertSame(t, e.getCause());
+ assertTrue(e.getMessage().indexOf("root") < 0);
+ assertTrue(e.getMessage().indexOf(t.getClass().getName()) < 0);
+ assertTrue(e.getMessage().indexOf("msg") >= 0);
+ }
+
+ /*
+ * Class under test for void InvalidPreferencesFormatException(Throwable)
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "InvalidPreferencesFormatException",
+ args = {java.lang.Throwable.class}
+ )
+ public void testInvalidPreferencesFormatExceptionThrowable() {
+ Throwable t = new Throwable("root");
+ InvalidPreferencesFormatException e = new InvalidPreferencesFormatException(
+ t);
+ assertSame(t, e.getCause());
+ assertTrue(e.getMessage().indexOf("root") >= 0);
+ assertTrue(e.getMessage().indexOf(t.getClass().getName()) >= 0);
+ }
+
+ /**
+ * @tests serialization/deserialization.
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "Verifies serialization",
+ method = "!SerializationSelf",
+ args = {}
+ )
+ public void testSerializationSelf() throws Exception {
+
+ SerializationTest.verifySelf(new InvalidPreferencesFormatException(
+ "msg"));
+ }
+
+ /**
+ * @tests serialization/deserialization compatibility with RI.
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "Verifies serialization",
+ method = "!SerializationGolden",
+ args = {}
+ )
+ public void testSerializationCompatibility() throws Exception {
+
+ SerializationTest.verifyGolden(this,
+ new InvalidPreferencesFormatException("msg"));
+ }
+}
diff --git a/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/MockAbstractPreferences.java b/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/MockAbstractPreferences.java
new file mode 100644
index 0000000..1820954
--- /dev/null
+++ b/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/MockAbstractPreferences.java
@@ -0,0 +1,245 @@
+/* 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 org.apache.harmony.prefs.tests.java.util.prefs;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+import java.util.prefs.AbstractPreferences;
+import java.util.prefs.BackingStoreException;
+
+public class MockAbstractPreferences extends AbstractPreferences {
+ static final int NORMAL = 0;
+
+ static final int backingException = 1;
+
+ static final int runtimeException = 2;
+
+ static final int returnNull = 3;
+
+ int result = NORMAL;
+
+ Properties attr = new Properties();
+
+ Map<String, MockAbstractPreferences> childs = new HashMap<String, MockAbstractPreferences>();
+
+ private int flushedTimes;
+
+ private int syncTimes;
+
+ protected MockAbstractPreferences(AbstractPreferences parent, String name) {
+ this(parent, name, false);
+
+ }
+
+ protected MockAbstractPreferences(AbstractPreferences parent, String name,
+ boolean newNode) {
+ super(parent, name);
+ super.newNode = newNode;
+ if (parent instanceof MockAbstractPreferences) {
+ ((MockAbstractPreferences) parent).addChild(this);
+ }
+ }
+
+ public int getFlushedTimes() {
+ return flushedTimes;
+ }
+
+ public void resetFlushedTimes() {
+ flushedTimes = 0;
+ }
+
+ public int getSyncTimes() {
+ return syncTimes;
+ }
+
+ public void resetSyncTimes() {
+ syncTimes = 0;
+ }
+
+ private void addChild(MockAbstractPreferences c) {
+ childs.put(c.name(), c);
+ }
+
+ public void setResult(int r) {
+ result = r;
+ }
+
+ public Object lock() {
+ return lock;
+ }
+
+ public String[] childrenNamesSpi() throws BackingStoreException {
+ checkException();
+ if (result == returnNull)
+ return null;
+ String[] r = new String[childs.size()];
+ childs.keySet().toArray(r);
+ return r;
+ }
+
+ private void checkException() throws BackingStoreException {
+ switch (result) {
+ case NORMAL:
+ return;
+ case backingException:
+ throw new BackingStoreException("test");
+ case runtimeException:
+ throw new MockRuntimeException("test");
+ }
+ }
+
+ public AbstractPreferences publicChildSpi(String name) {
+ return childSpi(name);
+ }
+
+ public AbstractPreferences childSpi(String name) {
+ try {
+ checkException();
+ } catch (BackingStoreException e) {
+ }
+ if (result == returnNull)
+ return null;
+ AbstractPreferences r = childs.get(name);
+ if (r == null) {
+ r = new MockAbstractPreferences(this, name, true);
+
+ }
+ return r;
+ }
+
+ public void flushSpi() throws BackingStoreException {
+ checkException();
+ flushedTimes++;
+ }
+
+ public String getSpi(String key) {
+ try {
+ checkException();
+ } catch (BackingStoreException e) {
+ }
+ if (null == key) {
+ return null;
+ }
+ return result == returnNull ? null : attr.getProperty(key);
+ }
+
+ public String[] keysSpi() throws BackingStoreException {
+ checkException();
+ Set<Object> keys = attr.keySet();
+ String[] results = new String[keys.size()];
+ keys.toArray(results);
+ return result == returnNull ? null : results;
+ }
+
+ public void putSpi(String name, String value) {
+ try {
+ checkException();
+ } catch (BackingStoreException e) {
+ }
+ if (name == null || value == null) {
+ return;
+ }
+ attr.put(name, value);
+ }
+
+ protected void removeNodeSpi() throws BackingStoreException {
+ checkException();
+ ((MockAbstractPreferences) parent()).childs.remove(name());
+ }
+
+ public void removeSpi(String key) {
+ try {
+ checkException();
+ } catch (BackingStoreException e) {
+ }
+ if (null == key) {
+ return;
+ }
+ attr.remove(key);
+ }
+
+ public void syncSpi() throws BackingStoreException {
+ checkException();
+ syncTimes++;
+ }
+
+ public boolean getNewNode() {
+ return newNode;
+ }
+
+ public Object getLock() {
+ return lock;
+ }
+
+ public void protectedAbstractMethod() {
+ try {
+ childrenNamesSpi();
+ } catch (BackingStoreException e) {
+ }
+ childSpi("mock");
+ try {
+ flushSpi();
+ } catch (BackingStoreException e1) {
+ }
+ getSpi(null);
+ isRemoved();
+ try {
+ keysSpi();
+ } catch (BackingStoreException e2) {
+ }
+ putSpi(null, null);
+ try {
+ removeNodeSpi();
+ } catch (BackingStoreException e3) {
+ }
+ removeSpi(null);
+ try {
+ syncSpi();
+ } catch (BackingStoreException e4) {
+ }
+ }
+
+ public boolean isRemovedImpl() {
+ return super.isRemoved();
+ }
+
+ public AbstractPreferences getChildImpl(String name)
+ throws BackingStoreException {
+ return super.getChild(name);
+ }
+
+ public AbstractPreferences[] cachedChildrenImpl() {
+ return super.cachedChildren();
+ }
+
+}
+
+class MockRuntimeException extends RuntimeException {
+
+ private static final long serialVersionUID = 1L;
+
+ public MockRuntimeException(String s) {
+ super(s);
+ }
+
+ public MockRuntimeException() {
+ super();
+ }
+}
+
diff --git a/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/MockNodeChangeListener.java b/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/MockNodeChangeListener.java
new file mode 100644
index 0000000..6e042fa
--- /dev/null
+++ b/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/MockNodeChangeListener.java
@@ -0,0 +1,132 @@
+package org.apache.harmony.prefs.tests.java.util.prefs;
+
+import java.util.prefs.NodeChangeEvent;
+import java.util.prefs.NodeChangeListener;
+import java.util.prefs.Preferences;
+
+public class MockNodeChangeListener implements NodeChangeListener {
+ private Object addLock = new Object();
+
+ private Object removeLock = new Object();
+
+ private int added = 0;
+
+ private int removed = 0;
+
+ private int testNum = 0;
+
+ public static final int TEST_GET_CHILD = 1;
+
+ public static final int TEST_GET_PARENT = 2;
+
+ boolean addResult = false;
+
+ boolean removeResult = false;
+
+ public MockNodeChangeListener(int test) {
+ testNum = test;
+ }
+
+ public MockNodeChangeListener() {
+
+ }
+
+ public void waitForEvent() {
+ try {
+ synchronized (addLock) {
+ addLock.wait(500);
+ }
+ } catch (InterruptedException e) {
+ }
+ }
+
+ public void childAdded(NodeChangeEvent e) {
+
+ synchronized (addLock) {
+ switch (testNum) {
+ case TEST_GET_CHILD:
+ Preferences child = e.getChild();
+ if (child == null) {
+ addResult = false;
+ } else {
+ if (child.name() == "mock1") {
+ addResult = true;
+ }
+ }
+ break;
+ case TEST_GET_PARENT:
+ Preferences parent = e.getParent();
+ if (parent == null) {
+ addResult = false;
+ } else {
+ if (parent.name() == "mock") {
+ addResult = true;
+ }
+ }
+
+ break;
+ }
+ ++added;
+ addLock.notifyAll();
+ }
+ }
+
+ public void childRemoved(NodeChangeEvent e) {
+ synchronized (removeLock) {
+ switch (testNum) {
+ case TEST_GET_CHILD:
+ Preferences child = e.getChild();
+ if (child == null) {
+ removeResult = false;
+ } else {
+ if (child.name() == "mock1") {
+ removeResult = true;
+ }
+ }
+ break;
+ case TEST_GET_PARENT:
+ Preferences parent = e.getParent();
+ if (parent == null) {
+ addResult = false;
+ } else {
+ if (parent.name() == "mock") {
+ addResult = true;
+ }
+ }
+
+ break;
+ }
+ removed++;
+ removeLock.notifyAll();
+ }
+ }
+
+ public boolean getAddResult() {
+ synchronized (addLock) {
+ return addResult;
+ }
+ }
+
+ public boolean getRemoveResult() {
+ synchronized (removeLock) {
+ return removeResult;
+ }
+ }
+
+ public int getAdded() {
+ synchronized (addLock) {
+ return added;
+ }
+ }
+
+ public int getRemoved() {
+ synchronized (removeLock) {
+ return removed;
+ }
+ }
+
+ public void reset() {
+ added = 0;
+ removed = 0;
+ }
+}
diff --git a/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/MockPreferenceChangeListener.java b/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/MockPreferenceChangeListener.java
new file mode 100644
index 0000000..9d628a2
--- /dev/null
+++ b/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/MockPreferenceChangeListener.java
@@ -0,0 +1,118 @@
+package org.apache.harmony.prefs.tests.java.util.prefs;
+
+import java.util.prefs.PreferenceChangeEvent;
+import java.util.prefs.PreferenceChangeListener;
+
+public class MockPreferenceChangeListener implements PreferenceChangeListener {
+ private Object lock = new Object();
+
+ private int changed = 0;
+
+ private boolean addDispatched = false;
+
+ public static final int TEST_GET_KEY = 1;
+
+ public static final int TEST_GET_NEW_VALUE = 2;
+
+ public static final int TEST_GET_NODE = 3;
+
+ boolean result = false;
+
+ int testNum = 0;
+
+
+ public MockPreferenceChangeListener() {
+
+ }
+
+ public MockPreferenceChangeListener(int test) {
+ testNum = test;
+ }
+
+ public void waitForEvent() {
+ waitForEvent(1);
+ }
+
+
+ public void waitForEvent(int count) {
+ for (int i = 0; i < count; i++) {
+ try {
+ synchronized (lock) {
+ lock.wait(500);
+ }
+ } catch (InterruptedException e) {
+ }
+ }
+ }
+
+ // private Object lock = new Object();
+
+ public void preferenceChange(PreferenceChangeEvent pce) {
+ synchronized (lock) {
+ switch(testNum) {
+ case TEST_GET_KEY:
+ if(pce != null) {
+ if(pce.getKey().equals("key_int")) {
+ result = true;
+ }
+ }
+ break;
+ case TEST_GET_NEW_VALUE:
+ if(pce != null) {
+ if(pce.getNewValue().equals(new Integer(Integer.MAX_VALUE).toString())) {
+ result = true;
+ }
+ }
+ break;
+ case TEST_GET_NODE:
+ if(pce != null) {
+ if("mock".equals(pce.getNode().name())) {
+ result = true;
+ }
+ }
+
+ break;
+ }
+ changed++;
+ addDispatched = true;
+ lock.notifyAll();
+ }
+ }
+
+ public boolean getResult() {
+ synchronized (lock) {
+
+ if (!addDispatched) {
+ try {
+ // TODO: don't know why must add limitation
+ lock.wait(100);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+ addDispatched = false;
+ return result;
+ }
+ }
+
+ public int getChanged() {
+ synchronized (lock) {
+
+ if (!addDispatched) {
+ try {
+ // TODO: don't know why must add limitation
+ lock.wait(1000);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+ addDispatched = false;
+ return changed;
+ }
+ }
+
+ public void reset() {
+ changed = 0;
+ result = false;
+ }
+}
diff --git a/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/MockSecurityManager.java b/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/MockSecurityManager.java
new file mode 100644
index 0000000..e5a0bfd
--- /dev/null
+++ b/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/MockSecurityManager.java
@@ -0,0 +1,60 @@
+/* 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 org.apache.harmony.prefs.tests.java.util.prefs;
+
+import java.security.Permission;
+
+/**
+ * utility class for java.util.prefs test
+ *
+ */
+class MockSecurityManager extends SecurityManager {
+
+ SecurityManager dflt;
+
+ public MockSecurityManager() {
+ super();
+ dflt = System.getSecurityManager();
+ }
+
+ public void install() {
+ System.setSecurityManager(this);
+ }
+
+ public void restoreDefault() {
+ System.setSecurityManager(dflt);
+ }
+
+ public void checkPermission(Permission perm) {
+ if (perm instanceof RuntimePermission
+ && perm.getName().equals("preferences")) {
+ throw new SecurityException();
+ } else if (dflt != null) {
+ dflt.checkPermission(perm);
+ }
+ }
+
+ public void checkPermission(Permission perm, Object ctx) {
+ if (perm instanceof RuntimePermission
+ && perm.getName().equals("preferences")) {
+ throw new SecurityException();
+ } else if (dflt != null) {
+ dflt.checkPermission(perm, ctx);
+ }
+ }
+
+}
diff --git a/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/NodeChangeEventTest.java b/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/NodeChangeEventTest.java
new file mode 100644
index 0000000..3260a04
--- /dev/null
+++ b/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/NodeChangeEventTest.java
@@ -0,0 +1,155 @@
+/* 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 org.apache.harmony.prefs.tests.java.util.prefs;
+
+import dalvik.annotation.TestTargetClass;
+import dalvik.annotation.TestTargets;
+import dalvik.annotation.TestLevel;
+import dalvik.annotation.TestTargetNew;
+
+import java.io.NotSerializableException;
+import java.util.prefs.AbstractPreferences;
+import java.util.prefs.BackingStoreException;
+import java.util.prefs.NodeChangeEvent;
+import java.util.prefs.Preferences;
+
+import junit.framework.TestCase;
+
+import org.apache.harmony.testframework.serialization.SerializationTest;
+
+/**
+ *
+ */
+@TestTargetClass(NodeChangeEvent.class)
+public class NodeChangeEventTest extends TestCase {
+
+ NodeChangeEvent event;
+
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "NodeChangeEvent",
+ args = {java.util.prefs.Preferences.class, java.util.prefs.Preferences.class}
+ )
+ public void testConstructor() {
+ event = new NodeChangeEvent(Preferences.systemRoot(), Preferences
+ .userRoot());
+ assertSame(Preferences.systemRoot(), event.getParent());
+ assertSame(Preferences.userRoot(), event.getChild());
+ assertSame(Preferences.systemRoot(), event.getSource());
+ }
+
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "NodeChangeEvent",
+ args = {java.util.prefs.Preferences.class, java.util.prefs.Preferences.class}
+ )
+ public void testConstructorNullParam() {
+ try {
+ event = new NodeChangeEvent(null, Preferences.userRoot());
+ fail();
+ } catch (IllegalArgumentException e) {
+ }
+
+ event = new NodeChangeEvent(Preferences.systemRoot(), null);
+ assertSame(Preferences.systemRoot(), event.getParent());
+ assertNull(event.getChild());
+ assertSame(Preferences.systemRoot(), event.getSource());
+ }
+
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "Verifies serialization",
+ method = "!Serialization",
+ args = {}
+ )
+ public void testSerialization() throws Exception {
+
+ event = new NodeChangeEvent(Preferences.systemRoot(), null);
+
+ try {
+ SerializationTest.copySerializable(event);
+ fail("No expected NotSerializableException");
+ } catch (NotSerializableException e) {
+ }
+ }
+
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "Test is correct, functionality checked in separate Mock class.",
+ method = "getChild",
+ args = {}
+ )
+ public void testGetChild() throws BackingStoreException {
+
+ AbstractPreferences parent = (AbstractPreferences) Preferences
+ .userNodeForPackage(Preferences.class);
+
+ AbstractPreferences pref = (AbstractPreferences) parent.node("mock");
+
+ MockNodeChangeListener nl = new MockNodeChangeListener(
+ MockNodeChangeListener.TEST_GET_CHILD);
+ try {
+ pref.addNodeChangeListener(nl);
+ Preferences child1 = pref.node("mock1");
+ nl.waitForEvent();
+ assertEquals(1, nl.getAdded());
+ assertTrue(nl.getAddResult());
+ nl.reset();
+ child1.removeNode();
+ nl.waitForEvent();
+ assertEquals(1, nl.getRemoved());
+ assertTrue(nl.getRemoveResult());
+ nl.reset();
+ } finally {
+ pref.removeNodeChangeListener(nl);
+ }
+ }
+
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "Test is correct, functionality checked in separate Mock class.",
+ method = "getParent",
+ args = {}
+ )
+ public void testGetParent() throws BackingStoreException {
+
+ AbstractPreferences parent = (AbstractPreferences) Preferences
+ .userNodeForPackage(Preferences.class);
+
+ AbstractPreferences pref = (AbstractPreferences) parent.node("mock");
+
+ MockNodeChangeListener nl = new MockNodeChangeListener(
+ MockNodeChangeListener.TEST_GET_CHILD);
+ try {
+ pref.addNodeChangeListener(nl);
+ Preferences child1 = pref.node("mock1");
+ nl.waitForEvent();
+ assertEquals(1, nl.getAdded());
+ assertTrue(nl.getAddResult());
+ nl.reset();
+ child1.removeNode();
+ nl.waitForEvent();
+ assertEquals(1, nl.getRemoved());
+ assertTrue(nl.getRemoveResult());
+ nl.reset();
+ } finally {
+ pref.removeNodeChangeListener(nl);
+ }
+ }
+}
diff --git a/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/NodeChangeListenerTest.java b/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/NodeChangeListenerTest.java
new file mode 100644
index 0000000..c5e3252
--- /dev/null
+++ b/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/NodeChangeListenerTest.java
@@ -0,0 +1,85 @@
+/* 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 org.apache.harmony.prefs.tests.java.util.prefs;
+
+import dalvik.annotation.TestTargetClass;
+import dalvik.annotation.TestTargets;
+import dalvik.annotation.TestLevel;
+import dalvik.annotation.TestTargetNew;
+
+import java.util.prefs.NodeChangeEvent;
+import java.util.prefs.NodeChangeListener;
+import java.util.prefs.Preferences;
+
+import junit.framework.TestCase;
+
+/**
+ *
+ */
+@TestTargetClass(NodeChangeListener.class)
+public class NodeChangeListenerTest extends TestCase {
+
+ NodeChangeListener l;
+
+ /*
+ * @see TestCase#setUp()
+ */
+ protected void setUp() throws Exception {
+ super.setUp();
+ l = new NodeChangeListenerImpl();
+ }
+
+ /*
+ * @see TestCase#tearDown()
+ */
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ }
+
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "Testing Interface",
+ method = "childAdded",
+ args = {java.util.prefs.NodeChangeEvent.class}
+ )
+ public void testChildAdded() {
+ l.childAdded(new NodeChangeEvent(Preferences.userRoot(), Preferences
+ .userRoot()));
+ }
+
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "Testing Interface",
+ method = "childRemoved",
+ args = {java.util.prefs.NodeChangeEvent.class}
+ )
+ public void testChildRemoved() {
+ l.childRemoved(new NodeChangeEvent(Preferences.userRoot(), Preferences
+ .userRoot()));
+ }
+
+ public static class NodeChangeListenerImpl implements NodeChangeListener {
+
+ public void childAdded(NodeChangeEvent e) {
+ }
+
+ public void childRemoved(NodeChangeEvent e) {
+ }
+
+ }
+
+}
diff --git a/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/PreferenceChangeEventTest.java b/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/PreferenceChangeEventTest.java
new file mode 100644
index 0000000..4030b89
--- /dev/null
+++ b/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/PreferenceChangeEventTest.java
@@ -0,0 +1,199 @@
+/* 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 org.apache.harmony.prefs.tests.java.util.prefs;
+
+import dalvik.annotation.TestTargetClass;
+import dalvik.annotation.TestTargets;
+import dalvik.annotation.TestLevel;
+import dalvik.annotation.TestTargetNew;
+
+import java.io.NotSerializableException;
+import java.util.prefs.AbstractPreferences;
+import java.util.prefs.PreferenceChangeEvent;
+import java.util.prefs.Preferences;
+
+import junit.framework.TestCase;
+
+import org.apache.harmony.testframework.serialization.SerializationTest;
+
+/**
+ *
+ */
+@TestTargetClass(PreferenceChangeEvent.class)
+public class PreferenceChangeEventTest extends TestCase {
+
+ PreferenceChangeEvent event;
+
+ @TestTargetNew(
+ level = TestLevel.PARTIAL,
+ notes = "Checks exception.",
+ method = "PreferenceChangeEvent",
+ args = {java.util.prefs.Preferences.class, java.lang.String.class, java.lang.String.class}
+ )
+ public void testPreferenceChangeEventException() {
+ try {
+ event = new PreferenceChangeEvent(null, "key", "value");
+ fail();
+ } catch (IllegalArgumentException e) {
+ }
+ }
+
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "PreferenceChangeEvent",
+ args = {java.util.prefs.Preferences.class, java.lang.String.class, java.lang.String.class}
+ )
+ public void testConstructorNullValue() {
+ event = new PreferenceChangeEvent(Preferences.userRoot(), "key", null);
+ assertEquals("key", event.getKey());
+ assertNull(event.getNewValue());
+ assertSame(Preferences.userRoot(), event.getNode());
+ assertSame(Preferences.userRoot(), event.getSource());
+
+ event = new PreferenceChangeEvent(Preferences.userRoot(), "", null);
+ assertEquals("", event.getKey());
+ assertNull(event.getNewValue());
+ assertSame(Preferences.userRoot(), event.getNode());
+ assertSame(Preferences.userRoot(), event.getSource());
+
+ event = new PreferenceChangeEvent(Preferences.userRoot(), null, "value");
+ assertNull(event.getKey());
+ assertEquals("value", event.getNewValue());
+ assertSame(Preferences.userRoot(), event.getNode());
+ assertSame(Preferences.userRoot(), event.getSource());
+
+ event = new PreferenceChangeEvent(Preferences.userRoot(), null, "");
+ assertNull(event.getKey());
+ assertEquals("", event.getNewValue());
+ assertSame(Preferences.userRoot(), event.getNode());
+ assertSame(Preferences.userRoot(), event.getSource());
+ }
+
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "PreferenceChangeEvent",
+ args = {java.util.prefs.Preferences.class, java.lang.String.class, java.lang.String.class}
+ )
+ public void testConstructor() {
+ event = new PreferenceChangeEvent(Preferences.userRoot(), "key",
+ "value");
+ assertEquals("key", event.getKey());
+ assertEquals("value", event.getNewValue());
+ assertSame(Preferences.userRoot(), event.getNode());
+ assertSame(Preferences.userRoot(), event.getSource());
+ }
+
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "Verifies serialization",
+ method = "!Serialization",
+ args = {}
+ )
+ public void testSerialization() throws Exception {
+ event = new PreferenceChangeEvent(Preferences.userRoot(), "key",
+ "value");
+ try {
+ SerializationTest.copySerializable(event);
+ fail("No expected NotSerializableException");
+ } catch (NotSerializableException e) {
+ }
+ }
+
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "Test is correct, functionality checked in separate Mock class.",
+ method = "getKey",
+ args = {}
+ )
+ public void testGetKey() {
+ AbstractPreferences parent = (AbstractPreferences) Preferences
+ .userNodeForPackage(Preferences.class);
+
+ AbstractPreferences pref = (AbstractPreferences) parent.node("mock");
+
+ MockPreferenceChangeListener pl = new MockPreferenceChangeListener(
+ MockPreferenceChangeListener.TEST_GET_KEY);
+ pref.addPreferenceChangeListener(pl);
+ try {
+ pref.putInt("key_int", Integer.MAX_VALUE);
+ assertEquals(1, pl.getChanged());
+ assertTrue(pl.getResult());
+ pl.reset();
+ } finally {
+ pref.removePreferenceChangeListener(pl);
+ }
+ }
+
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "Test is correct, functionality checked in separate Mock class.",
+ method = "getNewValue",
+ args = {}
+ )
+ public void testGetNewValue() {
+ AbstractPreferences parent = (AbstractPreferences) Preferences
+ .userNodeForPackage(Preferences.class);
+
+ AbstractPreferences pref = (AbstractPreferences) parent.node("mock");
+
+ MockPreferenceChangeListener pl = new MockPreferenceChangeListener(
+ MockPreferenceChangeListener.TEST_GET_NEW_VALUE);
+ pref.addPreferenceChangeListener(pl);
+ try {
+ pref.putInt("key_int", Integer.MAX_VALUE);
+ assertEquals(1, pl.getChanged());
+ assertTrue(pl.getResult());
+ pl.reset();
+
+ pref.putInt("key_int", Integer.MAX_VALUE);
+ assertEquals(1, pl.getChanged());
+ assertTrue(pl.getResult());
+ pl.reset();
+ } finally {
+ pref.removePreferenceChangeListener(pl);
+ }
+ }
+
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "Test is correct, functionality checked in separate Mock class.",
+ method = "getNode",
+ args = {}
+ )
+ public void testGetNode() {
+ AbstractPreferences parent = (AbstractPreferences) Preferences
+ .userNodeForPackage(Preferences.class);
+
+ AbstractPreferences pref = (AbstractPreferences) parent.node("mock");
+
+ MockPreferenceChangeListener pl = new MockPreferenceChangeListener(
+ MockPreferenceChangeListener.TEST_GET_NODE);
+ pref.addPreferenceChangeListener(pl);
+ try {
+ pref.putInt("key_int", Integer.MAX_VALUE);
+ assertEquals(1, pl.getChanged());
+ assertTrue(pl.getResult());
+ pl.reset();
+
+ } finally {
+ pref.removePreferenceChangeListener(pl);
+ }
+ }
+
+}
diff --git a/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/PreferenceChangeListenerTest.java b/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/PreferenceChangeListenerTest.java
new file mode 100644
index 0000000..e4df9c4
--- /dev/null
+++ b/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/PreferenceChangeListenerTest.java
@@ -0,0 +1,64 @@
+/* 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 org.apache.harmony.prefs.tests.java.util.prefs;
+
+import dalvik.annotation.TestTargetClass;
+import dalvik.annotation.TestTargets;
+import dalvik.annotation.TestLevel;
+import dalvik.annotation.TestTargetNew;
+
+import java.util.prefs.PreferenceChangeEvent;
+import java.util.prefs.PreferenceChangeListener;
+import java.util.prefs.Preferences;
+
+import junit.framework.TestCase;
+
+/**
+ *
+ */
+@TestTargetClass(PreferenceChangeListener.class)
+public class PreferenceChangeListenerTest extends TestCase {
+
+ PreferenceChangeListener l;
+
+ /*
+ * @see TestCase#setUp()
+ */
+ protected void setUp() throws Exception {
+ super.setUp();
+ l = new PreferenceChangeListenerImpl();
+ }
+
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "Testing Interface",
+ method = "preferenceChange",
+ args = {java.util.prefs.PreferenceChangeEvent.class}
+ )
+ public void testPreferenceChange() {
+ l.preferenceChange(new PreferenceChangeEvent(Preferences.userRoot(),
+ "", ""));
+ }
+
+ public static class PreferenceChangeListenerImpl implements
+ PreferenceChangeListener {
+ public void preferenceChange(PreferenceChangeEvent pce) {
+ }
+
+ }
+
+}
diff --git a/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/PreferencesFactoryTest.java b/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/PreferencesFactoryTest.java
new file mode 100644
index 0000000..818d5ad
--- /dev/null
+++ b/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/PreferencesFactoryTest.java
@@ -0,0 +1,77 @@
+/* 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 org.apache.harmony.prefs.tests.java.util.prefs;
+
+import dalvik.annotation.TestTargetClass;
+import dalvik.annotation.TestTargets;
+import dalvik.annotation.TestLevel;
+import dalvik.annotation.TestTargetNew;
+
+import java.util.prefs.Preferences;
+import java.util.prefs.PreferencesFactory;
+
+import junit.framework.TestCase;
+
+/**
+ *
+ */
+@TestTargetClass(PreferencesFactory.class)
+public class PreferencesFactoryTest extends TestCase {
+
+ PreferencesFactory f;
+
+ /*
+ * @see TestCase#setUp()
+ */
+ protected void setUp() throws Exception {
+ super.setUp();
+ f = new PreferencesFactoryImpl();
+ }
+
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "Testing Interface",
+ method = "userRoot",
+ args = {}
+ )
+ public void testUserRoot() {
+ f.userRoot();
+ }
+
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "Testing Interface",
+ method = "systemRoot",
+ args = {}
+ )
+ public void testSystemRoot() {
+ f.systemRoot();
+ }
+
+ public static class PreferencesFactoryImpl implements PreferencesFactory {
+
+ public Preferences userRoot() {
+ return null;
+ }
+
+ public Preferences systemRoot() {
+ return null;
+ }
+
+ }
+
+}
diff --git a/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/PreferencesTest.java b/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/PreferencesTest.java
new file mode 100644
index 0000000..2221cc5
--- /dev/null
+++ b/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/PreferencesTest.java
@@ -0,0 +1,1980 @@
+/* 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 org.apache.harmony.prefs.tests.java.util.prefs;
+
+import dalvik.annotation.KnownFailure;
+import dalvik.annotation.TestLevel;
+import dalvik.annotation.TestTargetClass;
+import dalvik.annotation.TestTargetNew;
+import dalvik.annotation.TestTargets;
+
+import junit.framework.TestCase;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.UnsupportedEncodingException;
+import java.net.MalformedURLException;
+import java.util.Arrays;
+import java.util.prefs.AbstractPreferences;
+import java.util.prefs.BackingStoreException;
+import java.util.prefs.InvalidPreferencesFormatException;
+import java.util.prefs.NodeChangeListener;
+import java.util.prefs.PreferenceChangeListener;
+import java.util.prefs.Preferences;
+
+/**
+ *
+ */
+@TestTargetClass(Preferences.class)
+public class PreferencesTest extends TestCase {
+
+ MockSecurityManager manager = new MockSecurityManager();
+
+ MockInputStream stream = null;
+
+ final static String longKey;
+
+ final static String longValue;
+
+ InputStream in;
+ static {
+ StringBuffer key = new StringBuffer(Preferences.MAX_KEY_LENGTH);
+ for (int i = 0; i < Preferences.MAX_KEY_LENGTH; i++) {
+ key.append('a');
+ }
+ longKey = key.toString();
+
+ StringBuffer value = new StringBuffer(Preferences.MAX_VALUE_LENGTH);
+ for (int i = 0; i < Preferences.MAX_VALUE_LENGTH; i++) {
+ value.append('a');
+ }
+ longValue = value.toString();
+ }
+
+ /*
+ * @see TestCase#setUp()
+ */
+ protected void setUp() throws Exception {
+ super.setUp();
+ in = new ByteArrayInputStream(
+ "<!DOCTYPE preferences SYSTEM \"http://java.sun.com/dtd/preferences.dtd\"><preferences><root type=\"user\"><map></map></root></preferences>"
+ .getBytes("UTF-8"));
+ stream = new MockInputStream(in);
+
+ String userHome = System.getProperty("user.home");
+ if (userHome != null) {
+ File userHomeDir = new File(userHome);
+ if (!userHomeDir.isDirectory() || !userHomeDir.canWrite()) {
+ userHome = null;
+ }
+ }
+ if (userHome == null) {
+ System.setProperty("user.home", System.getProperty("java.io.tmpdir"));
+ }
+
+ Preferences p = Preferences.userNodeForPackage(Preferences.class);
+ p.clear();
+ try {
+ p.removeNode();
+ } catch (BackingStoreException e) {
+ }
+ }
+
+ /*
+ * @see TestCase#tearDown()
+ */
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ stream.close();
+ Preferences p = Preferences.userNodeForPackage(Preferences.class);
+ p.clear();
+ try {
+ p.removeNode();
+ } catch (BackingStoreException e) {
+ }
+ }
+
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "systemNodeForPackage",
+ args = {java.lang.Class.class}
+ )
+ public void testSystemNodeForPackage() {
+ Preferences p = null;
+ try {
+ p = Preferences.systemNodeForPackage(Object.class);
+ } catch (SecurityException e) {
+ // may be caused by absence of privileges on the underlying OS
+ return;
+ }
+ assertEquals("/java/lang", p.absolutePath());
+ assertTrue(p instanceof AbstractPreferences);
+ Preferences root = Preferences.systemRoot();
+ Preferences parent = root.node("java");
+ assertSame(parent, p.parent());
+ assertFalse(p.isUserNode());
+ assertEquals("lang", p.name());
+ assertEquals("System Preference Node: " + p.absolutePath(), p
+ .toString());
+ try {
+ assertEquals(0, p.childrenNames().length);
+ } catch (BackingStoreException e) {
+ // could be thrown according to specification
+ }
+ try {
+ assertEquals(0, p.keys().length);
+ } catch (BackingStoreException e) {
+ // could be thrown according to specification
+ }
+
+ try {
+ p = Preferences.userNodeForPackage(null);
+ fail("NullPointerException has not been thrown");
+ } catch (NullPointerException e) {
+ // expected
+ }
+ }
+
+ @TestTargetNew(
+ level = TestLevel.PARTIAL_COMPLETE,
+ notes = "SecurityException checking missed.",
+ method = "systemRoot",
+ args = {}
+ )
+ public void testSystemRoot() {
+ Preferences p = Preferences.systemRoot();
+ assertTrue(p instanceof AbstractPreferences);
+ assertEquals("/", p.absolutePath());
+ assertSame(null, p.parent());
+ assertFalse(p.isUserNode());
+ assertEquals("", p.name());
+ assertEquals("System Preference Node: " + p.absolutePath(), p
+ .toString());
+ // assertEquals(0, p.childrenNames().length);
+ // assertEquals(0, p.keys().length);
+ }
+
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "Checks constant values",
+ method = "!Constants",
+ args = {}
+ )
+ public void testConsts() {
+ assertEquals(80, Preferences.MAX_KEY_LENGTH);
+ assertEquals(80, Preferences.MAX_NAME_LENGTH);
+ assertEquals(8192, Preferences.MAX_VALUE_LENGTH);
+ }
+
+ @TestTargetNew(
+ level = TestLevel.PARTIAL_COMPLETE,
+ notes = "SecurityException checking missed.",
+ method = "userNodeForPackage",
+ args = {java.lang.Class.class}
+ )
+ public void testUserNodeForPackage() throws BackingStoreException {
+ Preferences p = Preferences.userNodeForPackage(Object.class);
+ assertEquals("/java/lang", p.absolutePath());
+ assertTrue(p instanceof AbstractPreferences);
+ Preferences root = Preferences.userRoot();
+ Preferences parent = root.node("java");
+ assertSame(parent, p.parent());
+ assertTrue(p.isUserNode());
+ assertEquals("lang", p.name());
+ assertEquals("User Preference Node: " + p.absolutePath(), p.toString());
+ assertEquals(0, p.childrenNames().length);
+ assertEquals(0, p.keys().length);
+
+ try {
+ p = Preferences.userNodeForPackage(null);
+ fail();
+ } catch (NullPointerException e) {
+ }
+ }
+
+ @TestTargetNew(
+ level = TestLevel.PARTIAL_COMPLETE,
+ notes = "SecurityException checking missed.",
+ method = "userRoot",
+ args = {}
+ )
+ public void testUserRoot() {
+ Preferences p = Preferences.userRoot();
+ assertTrue(p instanceof AbstractPreferences);
+ assertEquals("/", p.absolutePath());
+ assertSame(null, p.parent());
+ assertTrue(p.isUserNode());
+ assertEquals("", p.name());
+ assertEquals("User Preference Node: " + p.absolutePath(), p.toString());
+ // assertEquals(0, p.childrenNames().length);
+ // assertEquals(p.keys().length, 0);
+ }
+
+
+ @TestTargetNew(
+ level = TestLevel.PARTIAL_COMPLETE,
+ notes = "SecurityException & IOException checking missed.",
+ method = "importPreferences",
+ args = {java.io.InputStream.class}
+ )
+ @KnownFailure("xml validation does not work")
+ public void testImportPreferences2() throws Exception {
+ InputStream in = PreferencesTest.class
+ .getResourceAsStream("/prefs/java/util/prefs/userprefs-badtype.xml");
+ try {
+ Preferences.importPreferences(in);
+ fail();
+ } catch (InvalidPreferencesFormatException e) {
+ }
+
+ in = PreferencesTest.class
+ .getResourceAsStream("/prefs/java/util/prefs/userprefs-badencoding.xml");
+ try {
+ Preferences.importPreferences(in);
+ fail();
+ } catch (InvalidPreferencesFormatException e) {
+ } catch (UnsupportedEncodingException e) {
+ }
+
+ }
+ @TestTargetNew(
+ level = TestLevel.PARTIAL_COMPLETE,
+ notes = "SecurityException & IOException checking missed.",
+ method = "importPreferences",
+ args = {java.io.InputStream.class}
+ )
+ public void testImportPreferences() throws Exception {
+ Preferences prefs = null;
+ try {
+ prefs = Preferences.userNodeForPackage(PreferencesTest.class);
+ // assertEquals(0, prefs.childrenNames().length);
+ // assertFalse(prefs.nodeExists("mock/child/grandson"));
+
+ prefs.put("prefskey", "oldvalue");
+ prefs.put("prefskey2", "oldvalue2");
+ in = getClass().getResourceAsStream("/prefs/java/util/prefs/userprefs.xml");
+ Preferences.importPreferences(in);
+
+ prefs = Preferences.userNodeForPackage(PreferencesTest.class);
+ assertEquals(1, prefs.childrenNames().length);
+ assertTrue(prefs.nodeExists("mock/child/grandson"));
+ assertEquals("newvalue", prefs.get("prefskey", null));
+ assertEquals("oldvalue2", prefs.get("prefskey2", null));
+ assertEquals("newvalue3", prefs.get("prefskey3", null));
+
+ in = PreferencesTest.class
+ .getResourceAsStream("/prefs/java/util/prefs/userprefs-badform.xml");
+ try {
+ Preferences.importPreferences(in);
+ fail();
+ } catch (InvalidPreferencesFormatException e) {
+ }
+
+ in = PreferencesTest.class
+ .getResourceAsStream("/prefs/java/util/prefs/userprefs-higherversion.xml");
+ try {
+ Preferences.importPreferences(in);
+ fail();
+ } catch (InvalidPreferencesFormatException e) {
+ }
+
+ in = PreferencesTest.class
+ .getResourceAsStream("/prefs/java/util/prefs/userprefs-ascii.xml");
+ Preferences.importPreferences(in);
+ prefs = Preferences.userNodeForPackage(PreferencesTest.class);
+ } finally {
+ try {
+ prefs = Preferences.userRoot().node("tests");
+ prefs.removeNode();
+ } catch (Exception e) {
+ }
+ }
+ }
+
+ @TestTargetNew(
+ level = TestLevel.PARTIAL_COMPLETE,
+ notes = "Test for Exceptions only.",
+ method = "importPreferences",
+ args = {java.io.InputStream.class}
+ )
+ public void testImportPreferencesException() throws Exception {
+ try {
+ Preferences.importPreferences(null);
+ fail();
+ } catch (MalformedURLException e) {
+ }
+
+ byte[] source = new byte[0];
+ InputStream in = new ByteArrayInputStream(source);
+ try {
+ Preferences.importPreferences(in);
+ fail();
+ } catch (InvalidPreferencesFormatException e) {
+ }
+
+ stream.setResult(MockInputStream.exception);
+ try {
+ Preferences.importPreferences(stream);
+ fail();
+ } catch (IOException e) {
+ }
+
+ stream.setResult(MockInputStream.runtimeException);
+ try {
+ Preferences.importPreferences(stream);
+ fail();
+ } catch (RuntimeException e) {
+ }
+ }
+
+ @TestTargets({
+ @TestTargetNew(
+ level = TestLevel.PARTIAL_COMPLETE,
+ notes = "SecurityException checking.",
+ method = "userRoot",
+ args = {}
+ ),
+ @TestTargetNew(
+ level = TestLevel.PARTIAL_COMPLETE,
+ notes = "SecurityException checking.",
+ method = "systemRoot",
+ args = {}
+ ),
+ @TestTargetNew(
+ level = TestLevel.PARTIAL_COMPLETE,
+ notes = "SecurityException checking.",
+ method = "userNodeForPackage",
+ args = {java.lang.Class.class}
+ ),
+ @TestTargetNew(
+ level = TestLevel.PARTIAL_COMPLETE,
+ notes = "SecurityException checking.",
+ method = "systemNodeForPackage",
+ args = {java.lang.Class.class}
+ ),
+ @TestTargetNew(
+ level = TestLevel.PARTIAL_COMPLETE,
+ notes = "SecurityException checking.",
+ method = "importPreferences",
+ args = {java.io.InputStream.class}
+ )
+ })
+ public void testSecurity() throws InvalidPreferencesFormatException,
+ IOException {
+ try {
+ manager.install();
+ try {
+ Preferences.userRoot();
+ fail();
+ } catch (SecurityException e) {
+ }
+ try {
+ Preferences.systemRoot();
+ fail();
+ } catch (SecurityException e) {
+ }
+ try {
+ Preferences.userNodeForPackage(null);
+ fail();
+ } catch (SecurityException e) {
+ }
+
+ try {
+ Preferences.systemNodeForPackage(null);
+ fail();
+ } catch (SecurityException e) {
+ }
+
+ try {
+ Preferences.importPreferences(stream);
+ fail();
+ } catch (SecurityException e) {
+ }
+ } finally {
+ manager.restoreDefault();
+ }
+ }
+
+ @TestTargets({
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "Test for abstract methods.",
+ method = "absolutePath",
+ args = {}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "Test for abstract methods.",
+ method = "childrenNames",
+ args = {}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "Test for abstract methods.",
+ method = "clear",
+ args = {}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "Test for abstract methods.",
+ method = "exportNode",
+ args = {java.io.OutputStream.class}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "Test for abstract methods.",
+ method = "exportSubtree",
+ args = {java.io.OutputStream.class}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "Test for abstract methods.",
+ method = "flush",
+ args = {}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "Test for abstract methods.",
+ method = "get",
+ args = {java.lang.String.class, java.lang.String.class}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "Test for abstract methods.",
+ method = "getBoolean",
+ args = {java.lang.String.class, boolean.class}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "Test for abstract methods.",
+ method = "getByteArray",
+ args = {java.lang.String.class, byte[].class}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "Test for abstract methods.",
+ method = "getFloat",
+ args = {java.lang.String.class, float.class}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "Test for abstract methods.",
+ method = "getDouble",
+ args = {java.lang.String.class, double.class}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "Test for abstract methods.",
+ method = "getInt",
+ args = {java.lang.String.class, int.class}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "Test for abstract methods.",
+ method = "getLong",
+ args = {java.lang.String.class, long.class}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "Test for abstract methods.",
+ method = "isUserNode",
+ args = {}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "Test for abstract methods.",
+ method = "keys",
+ args = {}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "Test for abstract methods.",
+ method = "name",
+ args = {}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "Test for abstract methods.",
+ method = "node",
+ args = {java.lang.String.class}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "Test for abstract methods.",
+ method = "nodeExists",
+ args = {java.lang.String.class}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "Test for abstract methods.",
+ method = "parent",
+ args = {}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "Test for abstract methods.",
+ method = "put",
+ args = {java.lang.String.class, java.lang.String.class}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "Test for abstract methods.",
+ method = "putBoolean",
+ args = {java.lang.String.class, boolean.class}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "Test for abstract methods.",
+ method = "putByteArray",
+ args = {java.lang.String.class, byte[].class}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "Test for abstract methods.",
+ method = "putDouble",
+ args = {java.lang.String.class, double.class}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "Test for abstract methods.",
+ method = "putFloat",
+ args = {java.lang.String.class, float.class}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "Test for abstract methods.",
+ method = "putInt",
+ args = {java.lang.String.class, int.class}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "Test for abstract methods.",
+ method = "putLong",
+ args = {java.lang.String.class, long.class}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "Test for abstract methods.",
+ method = "remove",
+ args = {java.lang.String.class}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "Test for abstract methods.",
+ method = "removeNode",
+ args = {}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "Test for abstract methods.",
+ method = "addNodeChangeListener",
+ args = {java.util.prefs.NodeChangeListener.class}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "Test for abstract methods.",
+ method = "addPreferenceChangeListener",
+ args = {java.util.prefs.PreferenceChangeListener.class}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "Test for abstract methods.",
+ method = "removeNodeChangeListener",
+ args = {java.util.prefs.NodeChangeListener.class}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "Test for abstract methods.",
+ method = "removePreferenceChangeListener",
+ args = {java.util.prefs.PreferenceChangeListener.class}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "Test for abstract methods.",
+ method = "sync",
+ args = {}
+ ),
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "Test for abstract methods.",
+ method = "toString",
+ args = {}
+ )
+ })
+ public void testAbstractMethods() {
+ Preferences p = new MockPreferences();
+ p.absolutePath();
+ try {
+ p.childrenNames();
+ } catch (BackingStoreException e4) {
+ }
+ try {
+ p.clear();
+ } catch (BackingStoreException e5) {
+ }
+ try {
+ p.exportNode(null);
+ } catch (IOException e6) {
+ } catch (BackingStoreException e6) {
+ }
+ try {
+ p.exportSubtree(null);
+ } catch (IOException e7) {
+ } catch (BackingStoreException e7) {
+ }
+ try {
+ p.flush();
+ } catch (BackingStoreException e8) {
+ }
+ p.get(null, null);
+ p.getBoolean(null, false);
+ p.getByteArray(null, null);
+ p.getFloat(null, 0.1f);
+ p.getDouble(null, 0.1);
+ p.getInt(null, 1);
+ p.getLong(null, 1l);
+ p.isUserNode();
+ try {
+ p.keys();
+ } catch (BackingStoreException e) {
+ }
+ p.name();
+ p.node(null);
+ try {
+ p.nodeExists(null);
+ } catch (BackingStoreException e1) {
+ }
+ p.parent();
+ p.put(null, null);
+ p.putBoolean(null, false);
+ p.putByteArray(null, null);
+ p.putDouble(null, 1);
+ p.putFloat(null, 1f);
+ p.putInt(null, 1);
+ p.putLong(null, 1l);
+ p.remove(null);
+ try {
+ p.removeNode();
+ } catch (BackingStoreException e2) {
+ }
+ p.addNodeChangeListener(null);
+ p.addPreferenceChangeListener(null);
+ p.removeNodeChangeListener(null);
+ p.removePreferenceChangeListener(null);
+ try {
+ p.sync();
+ } catch (BackingStoreException e3) {
+ }
+ p.toString();
+ }
+
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "Preferences",
+ args = {}
+ )
+ public void testConstructor() {
+ MockPreferences mp = new MockPreferences();
+ assertEquals(mp.getClass(), MockPreferences.class);
+ }
+
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "Check existed implementation",
+ method = "toString",
+ args = {}
+ )
+ public void testToString() {
+ Preferences p1 = Preferences.userNodeForPackage(Preferences.class);
+ assertNotNull(p1.toString());
+
+ Preferences p2 = Preferences.systemRoot();
+ assertNotNull(p2.toString());
+
+ Preferences p3 = Preferences.userRoot();
+ assertNotNull(p3.toString());
+ }
+ /**
+ * @test java.util.prefs.Preferences#absolutePath()
+ *
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "absolutePath",
+ args = {}
+ )
+ public void testAbsolutePath() {
+ Preferences p = Preferences.userNodeForPackage(Preferences.class);
+ assertEquals("/java/util/prefs", p.absolutePath());
+
+ }
+
+ /**
+ * @test java.util.prefs.Preferences#childrenNames()
+ *
+ */
+ @TestTargetNew(
+ level = TestLevel.PARTIAL,
+ notes = "IllegalStateException checking missed, but method is abstract, probably it is OK",
+ method = "childrenNames",
+ args = {}
+ )
+ public void testChildrenNames() throws BackingStoreException {
+ Preferences pref = Preferences.userNodeForPackage(Preferences.class);
+
+ Preferences child1 = pref.node("child1");
+
+ pref.node("child2");
+ pref.node("child3");
+ child1.node("subchild1");
+
+ assertSame(pref, child1.parent());
+ assertEquals(3, pref.childrenNames().length);
+ assertEquals("child1", pref.childrenNames()[0]);
+ assertEquals(1, child1.childrenNames().length);
+ assertEquals("subchild1", child1.childrenNames()[0]);
+ }
+
+ /**
+ * @test java.util.prefs.Preferences#clear()
+ *
+ */
+ @TestTargetNew(
+ level = TestLevel.PARTIAL,
+ notes = "IllegalStateException checking missed, but method is abstract, probably it is OK",
+ method = "clear",
+ args = {}
+ )
+ public void testClear() throws BackingStoreException {
+ Preferences pref = Preferences.userNodeForPackage(Preferences.class);
+ pref.put("testClearKey", "testClearValue");
+ pref.put("testClearKey1", "testClearValue1");
+ assertEquals("testClearValue", pref.get("testClearKey", null));
+ assertEquals("testClearValue1", pref.get("testClearKey1", null));
+ pref.clear();
+ assertNull(pref.get("testClearKey", null));
+ assertNull(pref.get("testClearKey1", null));
+ }
+
+ /**
+ * @test java.util.prefs.Preferences#get(String key, String def)
+ *
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "get",
+ args = {java.lang.String.class, java.lang.String.class}
+ )
+ public void testGet() throws BackingStoreException {
+ Preferences root = Preferences.userNodeForPackage(Preferences.class);
+ Preferences pref = root.node("mock");
+ assertNull(pref.get("", null));
+ assertEquals("default", pref.get("key", "default"));
+ assertNull(pref.get("key", null));
+ pref.put("testGetkey", "value");
+ assertNull(pref.get("testGetKey", null));
+ assertEquals("value", pref.get("testGetkey", null));
+
+ try {
+ pref.get(null, "abc");
+ fail();
+ } catch (NullPointerException e) {
+ }
+ pref.get("", "abc");
+ pref.get("key", null);
+ pref.get("key", "");
+ pref.putFloat("floatKey", 1.0f);
+ assertEquals("1.0", pref.get("floatKey", null));
+
+ pref.removeNode();
+ try {
+ pref.get("key", "abc");
+ fail();
+ } catch (IllegalStateException e) {
+ }
+ try {
+ pref.get(null, "abc");
+ fail();
+ } catch (NullPointerException e) {
+ }
+ }
+
+ /**
+ * @test java.util.prefs.Preferences#getBoolean(String key, boolean def)
+ *
+ */
+ @TestTargetNew(
+ level = TestLevel.PARTIAL,
+ notes = "IllegalStateException checking missed, but method is abstract, probably it is OK",
+ method = "getBoolean",
+ args = {java.lang.String.class, boolean.class}
+ )
+ public void testGetBoolean() {
+ Preferences pref = Preferences.userNodeForPackage(Preferences.class);
+ try {
+ pref.getBoolean(null, false);
+ fail();
+ } catch (NullPointerException e) {
+ }
+
+ pref.put("testGetBooleanKey", "false");
+ pref.put("testGetBooleanKey2", "value");
+ assertFalse(pref.getBoolean("testGetBooleanKey", true));
+ assertTrue(pref.getBoolean("testGetBooleanKey2", true));
+ }
+
+ /**
+ * @test java.util.prefs.Preferences#getByteArray(String key, byte[] def)
+ *
+ */
+ @TestTargetNew(
+ level = TestLevel.PARTIAL,
+ notes = "IllegalStateException checking missed, but method is abstract, probably it is OK",
+ method = "getByteArray",
+ args = {java.lang.String.class, byte[].class}
+ )
+ public void testGetByteArray() {
+ Preferences pref = Preferences.userNodeForPackage(Preferences.class);
+ try {
+ pref.getByteArray(null, new byte[0]);
+ fail();
+ } catch (NullPointerException e) {
+ }
+ byte[] b64Array = new byte[] { 0x59, 0x57, 0x4a, 0x6a };// BASE64
+
+ pref.put("testGetByteArrayKey", "abc=");
+ pref.put("testGetByteArrayKey2", new String(b64Array));
+ pref.put("invalidKey", "<>?");
+ assertTrue(Arrays.equals(new byte[] { 105, -73 }, pref.getByteArray(
+ "testGetByteArrayKey", new byte[0])));
+ assertTrue(Arrays.equals(new byte[] { 'a', 'b', 'c' }, pref
+ .getByteArray("testGetByteArrayKey2", new byte[0])));
+ assertTrue(Arrays.equals(new byte[0], pref.getByteArray("invalidKey",
+ new byte[0])));
+
+ pref.putByteArray("testGetByteArrayKey3", b64Array);
+ pref.putByteArray("testGetByteArrayKey4", "abc".getBytes());
+ assertTrue(Arrays.equals(b64Array, pref.getByteArray(
+ "testGetByteArrayKey3", new byte[0])));
+ assertTrue(Arrays.equals("abc".getBytes(), pref.getByteArray(
+ "testGetByteArrayKey4", new byte[0])));
+ }
+
+ /**
+ * @test java.util.prefs.Preferences#getDouble(String key, double def)
+ *
+ */
+ @TestTargetNew(
+ level = TestLevel.PARTIAL,
+ notes = "IllegalStateException checking missed, but method is abstract, probably it is OK",
+ method = "getDouble",
+ args = {java.lang.String.class, double.class}
+ )
+ public void testGetDouble() {
+ Preferences pref = Preferences.userNodeForPackage(Preferences.class);
+ try {
+ pref.getDouble(null, 0);
+ fail();
+ } catch (NullPointerException e) {
+ }
+
+ pref.put("testGetDoubleKey", "1");
+ pref.put("testGetDoubleKey2", "value");
+ pref.putDouble("testGetDoubleKey3", 1);
+ pref.putInt("testGetDoubleKey4", 1);
+ assertEquals(1.0, pref.getDouble("testGetDoubleKey", 0.0), 0);
+ assertEquals(0.0, pref.getDouble("testGetDoubleKey2", 0.0), 0);
+ assertEquals(1.0, pref.getDouble("testGetDoubleKey3", 0.0), 0);
+ assertEquals(1.0, pref.getDouble("testGetDoubleKey4", 0.0), 0);
+ }
+
+ /**
+ * @test java.util.prefs.Preferences#getFloat(String key, float def)
+ *
+ */
+ @TestTargetNew(
+ level = TestLevel.PARTIAL,
+ notes = "IllegalStateException checking missed, but method is abstract, probably it is OK",
+ method = "getFloat",
+ args = {java.lang.String.class, float.class}
+ )
+ public void testGetFloat() {
+ Preferences pref = Preferences.userNodeForPackage(Preferences.class);
+ try {
+ pref.getFloat(null, 0f);
+ fail();
+ } catch (NullPointerException e) {
+ }
+ pref.put("testGetFloatKey", "1");
+ pref.put("testGetFloatKey2", "value");
+ assertEquals(1f, pref.getFloat("testGetFloatKey", 0f), 0); //$NON-NLS-1$
+ assertEquals(0f, pref.getFloat("testGetFloatKey2", 0f), 0);
+ }
+
+ /**
+ * @test java.util.prefs.Preferences#getInt(String key, int def)
+ *
+ */
+ @TestTargetNew(
+ level = TestLevel.PARTIAL,
+ notes = "IllegalStateException checking missed, but method is abstract, probably it is OK",
+ method = "getInt",
+ args = {java.lang.String.class, int.class}
+ )
+ public void testGetInt() {
+ Preferences pref = Preferences.userNodeForPackage(Preferences.class);
+ try {
+ pref.getInt(null, 0);
+ fail();
+ } catch (NullPointerException e) {
+ }
+
+ pref.put("testGetIntKey", "1");
+ pref.put("testGetIntKey2", "value");
+ assertEquals(1, pref.getInt("testGetIntKey", 0));
+ assertEquals(0, pref.getInt("testGetIntKey2", 0));
+ }
+
+ /**
+ * @test java.util.prefs.Preferences#getLong(String key, long def)
+ *
+ */
+ @TestTargetNew(
+ level = TestLevel.PARTIAL,
+ notes = "IllegalStateException checking missed, but method is abstract, probably it is OK",
+ method = "getLong",
+ args = {java.lang.String.class, long.class}
+ )
+ public void testGetLong() {
+ Preferences pref = Preferences.userNodeForPackage(Preferences.class);
+ try {
+ pref.getLong(null, 0);
+ fail();
+ } catch (NullPointerException e) {
+ }
+
+ pref.put("testGetLongKey", "1");
+ pref.put("testGetLongKey2", "value");
+ assertEquals(1, pref.getInt("testGetLongKey", 0));
+ assertEquals(0, pref.getInt("testGetLongKey2", 0));
+ }
+
+ /**
+ * @test java.util.prefs.Preferences#isUserNode()
+ *
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "isUserNode",
+ args = {}
+ )
+ public void testIsUserNode() {
+ Preferences pref1 = Preferences.userNodeForPackage(Preferences.class);
+ assertTrue(pref1.isUserNode());
+
+ Preferences pref2 = Preferences.systemNodeForPackage(Preferences.class);
+ assertFalse(pref2.isUserNode());
+ }
+
+ /**
+ * @test java.util.prefs.Preferences#keys()
+ *
+ */
+ @TestTargetNew(
+ level = TestLevel.PARTIAL,
+ notes = "Exceptions checking missed, but method is abstract, probably it is OK",
+ method = "keys",
+ args = {}
+ )
+ public void testKeys() throws BackingStoreException {
+ Preferences pref = Preferences.userNodeForPackage(Preferences.class);
+ pref.clear();
+
+ pref.put("key0", "value");
+ pref.put("key1", "value1");
+ pref.put("key2", "value2");
+ pref.put("key3", "value3");
+
+ String[] keys = pref.keys();
+ assertEquals(4, keys.length);
+ for (int i = 0; i < keys.length; i++) {
+ assertEquals(0, keys[i].indexOf("key"));
+ assertEquals(4, keys[i].length());
+ }
+ }
+
+ /**
+ * @test java.util.prefs.Preferences#name()
+ *
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "name",
+ args = {}
+ )
+ public void testName() {
+ Preferences pref = Preferences.userNodeForPackage(Preferences.class);
+ Preferences child = pref.node("mock");
+ assertEquals("mock", child.name());
+ }
+
+ /**
+ * @test java.util.prefs.Preferences#node(String pathName)
+ *
+ */
+ @TestTargetNew(
+ level = TestLevel.PARTIAL,
+ notes = "IllegalStateException checking missed, but method is abstract, probably it is OK",
+ method = "node",
+ args = {java.lang.String.class}
+ )
+ public void testNode() throws BackingStoreException {
+ StringBuffer name = new StringBuffer(Preferences.MAX_NAME_LENGTH);
+ for (int i = 0; i < Preferences.MAX_NAME_LENGTH; i++) {
+ name.append('a');
+ }
+ String longName = name.toString();
+
+ Preferences root = Preferences.userRoot();
+ Preferences parent = Preferences
+ .userNodeForPackage(Preferences.class);
+ Preferences pref = parent.node("mock");
+
+ try {
+ pref.node(null);
+ fail();
+ } catch (NullPointerException e) {
+ }
+ try {
+ pref.node("/java/util/prefs/");
+ fail();
+ } catch (IllegalArgumentException e) {
+ }
+ try {
+ pref.node("/java//util/prefs");
+ fail();
+ } catch (IllegalArgumentException e) {
+ }
+ try {
+ pref.node(longName + "a");
+ fail();
+ } catch (IllegalArgumentException e) {
+ }
+ assertNotNull(pref.node(longName));
+
+ assertSame(root, pref.node("/"));
+
+ Preferences prefs = pref.node("/java/util/prefs");
+ assertSame(prefs, parent);
+
+ assertSame(pref, pref.node(""));
+
+ if (!(pref instanceof MockAbstractPreferences)) {
+ return;
+ }
+ MockAbstractPreferences child = (MockAbstractPreferences) ((MockAbstractPreferences) pref)
+ .publicChildSpi("child");
+ assertSame(child, pref.node("child"));
+
+ Preferences child2 = pref.node("child2");
+ assertSame(child2, ((MockAbstractPreferences) pref)
+ .publicChildSpi("child2"));
+
+ Preferences grandchild = pref.node("child/grandchild");
+ assertSame(grandchild, child.childSpi("grandchild"));
+ assertSame(grandchild, child.cachedChildrenImpl()[0]);
+ grandchild.removeNode();
+ assertNotSame(grandchild, pref.node("child/grandchild"));
+
+ grandchild = pref.node("child3/grandchild");
+ AbstractPreferences[] childs = ((MockAbstractPreferences) pref)
+ .cachedChildrenImpl();
+ Preferences child3 = child;
+ for (int i = 0; i < childs.length; i++) {
+ if (childs[i].name().equals("child3")) {
+ child3 = childs[i];
+ break;
+ }
+ }
+ assertSame(child3, grandchild.parent());
+ }
+
+ /**
+ * @test java.util.prefs.Preferences#nodeExists(String pathName)
+ *
+ */
+ @TestTargetNew(
+ level = TestLevel.PARTIAL,
+ notes = "IllegalStateException & BackingStoreException checking missed, but method is abstract, probably it is OK",
+ method = "nodeExists",
+ args = {java.lang.String.class}
+ )
+ public void testNodeExists() throws BackingStoreException {
+
+ Preferences parent = Preferences
+ .userNodeForPackage(Preferences.class);
+ Preferences pref = parent.node("mock");
+
+ try {
+ pref.nodeExists(null);
+ fail();
+ } catch (NullPointerException e) {
+ }
+ try {
+ pref.nodeExists("/java/util/prefs/");
+ fail();
+ } catch (IllegalArgumentException e) {
+ }
+ try {
+ pref.nodeExists("/java//util/prefs");
+ fail();
+ } catch (IllegalArgumentException e) {
+ }
+
+ assertTrue(pref.nodeExists("/"));
+
+ assertTrue(pref.nodeExists("/java/util/prefs"));
+
+ assertTrue(pref.nodeExists(""));
+
+ assertFalse(pref.nodeExists("child"));
+ Preferences grandchild = pref.node("child/grandchild");
+ assertTrue(pref.nodeExists("child"));
+ assertTrue(pref.nodeExists("child/grandchild"));
+ grandchild.removeNode();
+ assertTrue(pref.nodeExists("child"));
+ assertFalse(pref.nodeExists("child/grandchild"));
+ assertFalse(grandchild.nodeExists(""));
+
+ assertFalse(pref.nodeExists("child2/grandchild"));
+ pref.node("child2/grandchild");
+ assertTrue(pref.nodeExists("child2/grandchild"));
+ }
+
+ /**
+ * @test java.util.prefs.Preferences#parent()
+ *
+ */
+ @TestTargetNew(
+ level = TestLevel.PARTIAL,
+ notes = "IllegalStateException checking missed, but method is abstract, probably it is OK",
+ method = "parent",
+ args = {}
+ )
+ public void testParent() {
+ Preferences parent = Preferences
+ .userNodeForPackage(Preferences.class);
+ Preferences pref = parent.node("mock");
+
+ assertSame(parent, pref.parent());
+
+ }
+
+ /**
+ * @test java.util.prefs.Preferences#put(String key, String value)
+ *
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "put",
+ args = {java.lang.String.class, java.lang.String.class}
+ )
+ public void testPut() throws BackingStoreException {
+ Preferences pref = Preferences
+ .userNodeForPackage(Preferences.class);
+ pref.put("", "emptyvalue");
+ assertEquals("emptyvalue", pref.get("", null));
+ pref.put("testPutkey", "value1");
+ assertEquals("value1", pref.get("testPutkey", null));
+ pref.put("testPutkey", "value2");
+ assertEquals("value2", pref.get("testPutkey", null));
+
+ pref.put("", "emptyvalue");
+ assertEquals("emptyvalue", pref.get("", null));
+
+ try {
+ pref.put(null, "value");
+ fail();
+ } catch (NullPointerException e) {
+ }
+ try {
+ pref.put("key", null);
+ fail();
+ } catch (NullPointerException e) {
+ }
+ pref.put(longKey, longValue);
+ try {
+ pref.put(longKey + 1, longValue);
+ fail();
+ } catch (IllegalArgumentException e) {
+ }
+ try {
+ pref.put(longKey, longValue + 1);
+ fail();
+ } catch (IllegalArgumentException e) {
+ }
+
+ pref.removeNode();
+ try {
+ pref.put(longKey, longValue + 1);
+ fail();
+ } catch (IllegalArgumentException e) {
+ }
+
+ try {
+ pref.put(longKey, longValue);
+ fail();
+ } catch (IllegalStateException e) {
+ }
+ }
+
+ /**
+ * @test java.util.prefs.Preferences#putBoolean(String key, boolean value)
+ *
+ */
+ @TestTargetNew(
+ level = TestLevel.PARTIAL,
+ notes = "IllegalStateException checking missed, but method is abstract, probably it is OK",
+ method = "putBoolean",
+ args = {java.lang.String.class, boolean.class}
+ )
+ public void testPutBoolean() {
+ Preferences pref = Preferences
+ .userNodeForPackage(Preferences.class);
+ try {
+ pref.putBoolean(null, false);
+ fail();
+ } catch (NullPointerException e) {
+ }
+ pref.putBoolean(longKey, false);
+ try {
+ pref.putBoolean(longKey + "a", false);
+ fail();
+ } catch (IllegalArgumentException e) {
+ }
+ pref.putBoolean("testPutBooleanKey", false);
+ assertEquals("false", pref.get("testPutBooleanKey", null));
+ assertFalse(pref.getBoolean("testPutBooleanKey", true));
+ }
+
+ /**
+ * @test java.util.prefs.Preferences#putDouble(String key, double value)
+ *
+ */
+ @TestTargetNew(
+ level = TestLevel.PARTIAL,
+ notes = "IllegalStateException checking missed, but method is abstract, probably it is OK",
+ method = "putDouble",
+ args = {java.lang.String.class, double.class}
+ )
+ public void testPutDouble() {
+ Preferences pref = Preferences
+ .userNodeForPackage(Preferences.class);
+ try {
+ pref.putDouble(null, 3);
+ fail();
+ } catch (NullPointerException e) {
+ }
+ pref.putDouble(longKey, 3);
+ try {
+ pref.putDouble(longKey + "a", 3);
+ fail();
+ } catch (IllegalArgumentException e) {
+ }
+ pref.putDouble("testPutDoubleKey", 3);
+ assertEquals("3.0", pref.get("testPutDoubleKey", null));
+ assertEquals(3, pref.getDouble("testPutDoubleKey", 0), 0);
+ }
+
+ /**
+ * @test java.util.prefs.Preferences#putFloat(String key, float value)
+ *
+ */
+ @TestTargetNew(
+ level = TestLevel.PARTIAL,
+ notes = "IllegalStateException checking missed, but method is abstract, probably it is OK",
+ method = "putFloat",
+ args = {java.lang.String.class, float.class}
+ )
+ public void testPutFloat() {
+ Preferences pref = Preferences
+ .userNodeForPackage(Preferences.class);
+ try {
+ pref.putFloat(null, 3f);
+ fail();
+ } catch (NullPointerException e) {
+ }
+ pref.putFloat(longKey, 3f);
+ try {
+ pref.putFloat(longKey + "a", 3f);
+ fail();
+ } catch (IllegalArgumentException e) {
+ }
+ pref.putFloat("testPutFloatKey", 3f);
+ assertEquals("3.0", pref.get("testPutFloatKey", null));
+ assertEquals(3f, pref.getFloat("testPutFloatKey", 0), 0);
+ }
+
+ /**
+ * @test java.util.prefs.Preferences#putInt(String key, int value)
+ *
+ */
+ @TestTargetNew(
+ level = TestLevel.PARTIAL,
+ notes = "IllegalStateException checking missed, but method is abstract, probably it is OK",
+ method = "putInt",
+ args = {java.lang.String.class, int.class}
+ )
+ public void testPutInt() {
+ Preferences pref = Preferences
+ .userNodeForPackage(Preferences.class);
+ try {
+ pref.putInt(null, 3);
+ fail();
+ } catch (NullPointerException e) {
+ }
+ pref.putInt(longKey, 3);
+ try {
+ pref.putInt(longKey + "a", 3);
+ fail();
+ } catch (IllegalArgumentException e) {
+ }
+ pref.putInt("testPutIntKey", 3);
+ assertEquals("3", pref.get("testPutIntKey", null));
+ assertEquals(3, pref.getInt("testPutIntKey", 0));
+ }
+
+ /**
+ * @test java.util.prefs.Preferences#putLong(String key, long value)
+ *
+ */
+ @TestTargetNew(
+ level = TestLevel.PARTIAL,
+ notes = "IllegalStateException checking missed, but method is abstract, probably it is OK",
+ method = "putLong",
+ args = {java.lang.String.class, long.class}
+ )
+ public void testPutLong() {
+ Preferences pref = Preferences
+ .userNodeForPackage(Preferences.class);
+ try {
+ pref.putLong(null, 3L);
+ fail();
+ } catch (NullPointerException e) {
+ }
+ pref.putLong(longKey, 3L);
+ try {
+ pref.putLong(longKey + "a", 3L);
+ fail();
+ } catch (IllegalArgumentException e) {
+ }
+ pref.putLong("testPutLongKey", 3L);
+ assertEquals("3", pref.get("testPutLongKey", null));
+ assertEquals(3L, pref.getLong("testPutLongKey", 0));
+ }
+
+ /**
+ * @test java.util.prefs.Preferences#putByteArray(String key, byte[] value)
+ *
+ */
+ @TestTargetNew(
+ level = TestLevel.PARTIAL,
+ notes = "IllegalStateException checking missed, but method is abstract, probably it is OK",
+ method = "putByteArray",
+ args = {java.lang.String.class, byte[].class}
+ )
+ public void testPutByteArray() {
+ Preferences pref = Preferences
+ .userNodeForPackage(Preferences.class);
+ try {
+ pref.putByteArray(null, new byte[0]);
+ fail();
+ } catch (NullPointerException e) {
+ }
+ try {
+ pref.putByteArray("testPutByteArrayKey4", null);
+ fail();
+ } catch (NullPointerException e) {
+ }
+
+ pref.putByteArray(longKey, new byte[0]);
+ try {
+ pref.putByteArray(longKey + "a", new byte[0]);
+ fail();
+ } catch (IllegalArgumentException e) {
+ }
+ byte[] longArray = new byte[(int) (Preferences.MAX_VALUE_LENGTH * 0.74)];
+ byte[] longerArray = new byte[(int) (Preferences.MAX_VALUE_LENGTH * 0.75) + 1];
+ pref.putByteArray(longKey, longArray);
+ try {
+ pref.putByteArray(longKey, longerArray);
+ fail();
+ } catch (IllegalArgumentException e) {
+ }
+
+ pref.putByteArray("testPutByteArrayKey", new byte[0]);
+ assertEquals("", pref.get("testPutByteArrayKey", null));
+ assertTrue(Arrays.equals(new byte[0], pref.getByteArray(
+ "testPutByteArrayKey", null)));
+
+ pref.putByteArray("testPutByteArrayKey3", new byte[] { 'a', 'b', 'c' });
+ assertEquals("YWJj", pref.get("testPutByteArrayKey3", null));
+ assertTrue(Arrays.equals(new byte[] { 'a', 'b', 'c' }, pref
+ .getByteArray("testPutByteArrayKey3", null)));
+ }
+
+ /**
+ * @test java.util.prefs.Preferences#remove(String key)
+ *
+ */
+ @TestTargetNew(
+ level = TestLevel.COMPLETE,
+ notes = "",
+ method = "remove",
+ args = {java.lang.String.class}
+ )
+ public void testRemove() throws BackingStoreException {
+ Preferences pref = Preferences
+ .userNodeForPackage(Preferences.class);
+ pref.remove("key");
+
+ pref.put("key", "value");
+ assertEquals("value", pref.get("key", null));
+ pref.remove("key");
+ assertNull(pref.get("key", null));
+
+ pref.remove("key");
+
+ try {
+ pref.remove(null);
+ fail();
+ } catch (NullPointerException e) {
+ }
+
+ pref.removeNode();
+ try {
+ pref.remove("key");
+ fail();
+ } catch (IllegalStateException e) {
+ }
+ }
+
+ /**
+ * @test java.util.prefs.Preferences#removeNode()
+ *
+ */
+ @TestTargetNew(
+ level = TestLevel.PARTIAL,
+ notes = "Exceptions checking missed, but method is abstract, probably it is OK",
+ method = "removeNode",
+ args = {}
+ )
+ public void testRemoveNode() throws BackingStoreException {
+ Preferences pref = Preferences
+ .userNodeForPackage(Preferences.class);
+ Preferences child = pref.node("child");
+ Preferences child1 = pref.node("child1");
+ Preferences grandchild = child.node("grandchild");
+
+ pref.removeNode();
+
+ assertFalse(child.nodeExists(""));
+ assertFalse(child1.nodeExists(""));
+ assertFalse(grandchild.nodeExists(""));
+ assertFalse(pref.nodeExists(""));
+ }
+
+
+ /**
+ * @test java.util.prefs.Preferences#addNodeChangeListener(NodeChangeListener ncl)
+ *
+ */
+ @TestTargetNew(
+ level = TestLevel.PARTIAL,
+ notes = "Only NullPointerException checked, but method is abstract, probably it is OK",
+ method = "addNodeChangeListener",
+ args = {java.util.prefs.NodeChangeListener.class}
+ )
+ public void testAddNodeChangeListener() throws BackingStoreException {
+ Preferences pref = Preferences.userNodeForPackage(Preferences.class);
+ try {
+ pref.addNodeChangeListener(null);
+ fail();
+ } catch (NullPointerException e) {
+ }
+
+ Preferences child1 = null;
+ Preferences child2 = null;
+ Preferences child3 = null;
+
+ MockNodeChangeListener nl = null;
+ // To get existed node doesn't create the change event
+ try {
+ nl = new MockNodeChangeListener();
+ pref.addNodeChangeListener(nl);
+ child1 = pref.node("mock1");
+ nl.waitForEvent();
+ assertEquals(1, nl.getAdded());
+ nl.reset();
+ child2 = pref.node("mock1");
+ nl.waitForEvent();
+ assertEquals(0, nl.getAdded());
+ nl.reset();
+ } finally {
+ pref.removeNodeChangeListener(nl);
+ child1.removeNode();
+ }
+ // same listener can be added twice, and must be removed twice
+ try {
+ nl = new MockNodeChangeListener();
+ pref.addNodeChangeListener(nl);
+ pref.addNodeChangeListener(nl);
+ child1 = pref.node("mock2");
+ nl.waitForEvent();
+ assertEquals(2, nl.getAdded());
+ nl.reset();
+ } finally {
+ pref.removeNodeChangeListener(nl);
+ pref.removeNodeChangeListener(nl);
+ child1.removeNode();
+ }
+ // test remove event
+ try {
+ nl = new MockNodeChangeListener();
+ pref.addNodeChangeListener(nl);
+ child1 = pref.node("mock3");
+ child1.removeNode();
+ nl.waitForEvent();
+ assertEquals(1, nl.getRemoved());
+ nl.reset();
+ } finally {
+ pref.removeNodeChangeListener(nl);
+ }
+ // test remove event with two listeners
+ try {
+ nl = new MockNodeChangeListener();
+ pref.addNodeChangeListener(nl);
+ pref.addNodeChangeListener(nl);
+ child1 = pref.node("mock6");
+ child1.removeNode();
+ nl.waitForEvent();
+ assertEquals(2, nl.getRemoved());
+ nl.reset();
+ } finally {
+ pref.removeNodeChangeListener(nl);
+ pref.removeNodeChangeListener(nl);
+ }
+ // test add/remove indirect children, or remove several children at the
+ // same time
+ try {
+ nl = new MockNodeChangeListener();
+ child1 = pref.node("mock4");
+ child1.addNodeChangeListener(nl);
+ child2 = pref.node("mock4/mock5");
+ nl.waitForEvent();
+ assertEquals(1, nl.getAdded());
+ nl.reset();
+ child3 = pref.node("mock4/mock5/mock6");
+ nl.waitForEvent();
+ assertEquals(0, nl.getAdded());
+ nl.reset();
+
+ child3.removeNode();
+ nl.waitForEvent();
+ assertEquals(0, nl.getRemoved());
+ nl.reset();
+
+ child3 = pref.node("mock4/mock7");
+ nl.waitForEvent();
+ assertEquals(1, nl.getAdded());
+ nl.reset();
+
+ child1.removeNode();
+ nl.waitForEvent();
+ assertEquals(2, nl.getRemoved()); // fail 1
+ nl.reset();
+ } finally {
+ try {
+ child1.removeNode();
+ } catch (Exception e) {
+ }
+ }
+
+ }
+
+ /**
+ * @test java.util.prefs.Preferences#addPreferenceChangeListener(PreferenceChangeListener pcl)
+ *
+ */
+ @TestTargetNew(
+ level = TestLevel.PARTIAL,
+ notes = "Only NullPointerException checked, but method is abstract, probably it is OK",
+ method = "addPreferenceChangeListener",
+ args = {java.util.prefs.PreferenceChangeListener.class}
+ )
+ public void testAddPreferenceChangeListener() {
+
+ Preferences pref = Preferences.userNodeForPackage(Preferences.class);
+ MockPreferenceChangeListener pl = null;
+
+ try {
+ pref.addPreferenceChangeListener(null);
+ fail();
+ } catch (NullPointerException e) {
+ }
+
+ // To get existed node doesn't create the change event
+ try {
+ pl = new MockPreferenceChangeListener();
+ pref.addPreferenceChangeListener(pl);
+ pref.putInt("mock1", 123);
+ pl.waitForEvent();
+ assertEquals(1, pl.getChanged());
+ pref.putLong("long_key", Long.MAX_VALUE);
+ pl.waitForEvent(2);
+ assertEquals(2, pl.getChanged());
+ pl.reset();
+ try {
+ pref.clear();
+ pl.waitForEvent(2);
+ assertEquals(2, pl.getChanged()); // fail 1
+ } catch(BackingStoreException bse) {
+ pl.reset();
+ fail("BackingStoreException is thrown");
+ }
+ pl.reset();
+ } finally {
+ pref.removePreferenceChangeListener(pl);
+ //child1.removeNode();
+ }
+
+ // same listener can be added twice, and must be removed twice
+ try {
+ pl = new MockPreferenceChangeListener();
+ pref.addPreferenceChangeListener(pl);
+ pref.addPreferenceChangeListener(pl);
+ pref.putFloat("float_key", Float.MIN_VALUE);
+ pl.waitForEvent(2);
+ assertEquals(2, pl.getChanged());
+ pl.reset();
+ } finally {
+ pref.removePreferenceChangeListener(pl);
+ pref.removePreferenceChangeListener(pl);
+
+ }
+ // test remove event
+ try {
+ pl = new MockPreferenceChangeListener();
+ pref.addPreferenceChangeListener(pl);
+ pref.putDouble("double_key", Double.MAX_VALUE);
+ pl.waitForEvent();
+ assertEquals(1, pl.getChanged());
+ try {
+ pref.clear();
+ pl.waitForEvent(3);
+ assertEquals(3, pl.getChanged()); // fails
+ } catch(BackingStoreException bse) {
+ fail("BackingStoreException is thrown");
+ }
+ pl.reset();
+ } finally {
+ pref.removePreferenceChangeListener(pl);
+ }
+ // test remove event with two listeners
+ try {
+ pl = new MockPreferenceChangeListener();
+ pref.addPreferenceChangeListener(pl);
+ pref.addPreferenceChangeListener(pl);
+ pref.putByteArray("byte_array_key", new byte [] {1 ,2 , 3});
+ try {
+ pref.clear();
+ pl.waitForEvent(4);
+ assertEquals(4, pl.getChanged());
+ } catch(BackingStoreException bse) {
+ fail("BackingStoreException is thrown");
+ }
+ pl.reset();
+ } finally {
+ pref.removePreferenceChangeListener(pl);
+ pref.removePreferenceChangeListener(pl);
+ }
+
+ }
+
+ /**
+ * @test java.util.prefs.Preferences#removeNodeChangeListener(NodeChangeListener ncl)
+ *
+ */
+ @TestTargetNew(
+ level = TestLevel.PARTIAL,
+ notes = "IllegalStateException checking missed, but method is abstract, probably it is OK",
+ method = "removeNodeChangeListener",
+ args = {java.util.prefs.NodeChangeListener.class}
+ )
+ public void testRemoveNodeChangeListener() {
+ Preferences pref = Preferences.userNodeForPackage(Preferences.class);
+ try {
+ pref.removeNodeChangeListener(null);
+ fail();
+ } catch (IllegalArgumentException e) {
+ }
+ MockNodeChangeListener l1 = new MockNodeChangeListener();
+ MockNodeChangeListener l2 = new MockNodeChangeListener();
+ pref.addNodeChangeListener(l1);
+ pref.addNodeChangeListener(l1);
+
+ pref.removeNodeChangeListener(l1);
+ pref.removeNodeChangeListener(l1);
+ try {
+ pref.removeNodeChangeListener(l1);
+ fail();
+ } catch (IllegalArgumentException e) {
+ }
+ try {
+ pref.removeNodeChangeListener(l2);
+ fail();
+ } catch (IllegalArgumentException e) {
+ }
+ }
+
+ /**
+ * @test java.util.prefs.Preferences#removePreferenceChangeListener(PreferenceChangeListener pcl)
+ *
+ */
+ @TestTargetNew(
+ level = TestLevel.PARTIAL,
+ notes = "IllegalStateException checking missed, but method is abstract, probably it is OK",
+ method = "removePreferenceChangeListener",
+ args = {java.util.prefs.PreferenceChangeListener.class}
+ )
+ public void testRemovePreferenceChangeListener() {
+ Preferences pref = Preferences.userNodeForPackage(Preferences.class);
+ try {
+ pref.removePreferenceChangeListener(null);
+ fail();
+ } catch (IllegalArgumentException e) {
+ }
+ MockPreferenceChangeListener l1 = new MockPreferenceChangeListener();
+ MockPreferenceChangeListener l2 = new MockPreferenceChangeListener();
+ pref.addPreferenceChangeListener(l1);
+ pref.addPreferenceChangeListener(l1);
+ try {
+ pref.removePreferenceChangeListener(l2);
+ fail();
+ } catch (IllegalArgumentException e) {
+ }
+ pref.removePreferenceChangeListener(l1);
+ pref.removePreferenceChangeListener(l1);
+ try {
+ pref.removePreferenceChangeListener(l1);
+ fail();
+ } catch (IllegalArgumentException e) {
+ }
+
+ }
+
+ static class MockInputStream extends InputStream {
+
+ static final int normal = 0;
+
+ static final int exception = 1;
+
+ static final int runtimeException = 2;
+
+ int result = normal;
+
+ InputStream wrapper;
+
+ public void setResult(int i) {
+ result = i;
+ }
+
+ private void checkException() throws IOException {
+ switch (result) {
+ case normal:
+ return;
+ case exception:
+ throw new IOException("test");
+ case runtimeException:
+ throw new RuntimeException("test");
+ }
+ }
+
+ public MockInputStream(InputStream in) {
+ wrapper = in;
+ }
+
+ public int read() throws IOException {
+ checkException();
+ return wrapper.read();
+ }
+ }
+
+ @SuppressWarnings("unused")
+ static class MockPreferences extends Preferences {
+
+ public MockPreferences() {
+ super();
+ }
+
+ public String absolutePath() {
+ return null;
+ }
+
+ public String[] childrenNames() throws BackingStoreException {
+ return null;
+ }
+
+ public void clear() throws BackingStoreException {
+ }
+
+ public void exportNode(OutputStream ostream) throws IOException,
+ BackingStoreException {
+ }
+
+ public void exportSubtree(OutputStream ostream) throws IOException,
+ BackingStoreException {
+ }
+
+ public void flush() throws BackingStoreException {
+ }
+
+ public String get(String key, String deflt) {
+ return null;
+ }
+
+ public boolean getBoolean(String key, boolean deflt) {
+ return false;
+ }
+
+ public byte[] getByteArray(String key, byte[] deflt) {
+ return null;
+ }
+
+ public double getDouble(String key, double deflt) {
+ return 0;
+ }
+
+ public float getFloat(String key, float deflt) {
+ return 0;
+ }
+
+ public int getInt(String key, int deflt) {
+ return 0;
+ }
+
+ public long getLong(String key, long deflt) {
+ return 0;
+ }
+
+ public boolean isUserNode() {
+ return false;
+ }
+
+ public String[] keys() throws BackingStoreException {
+ return null;
+ }
+
+ public String name() {
+ return null;
+ }
+
+ public Preferences node(String name) {
+ return null;
+ }
+
+ public boolean nodeExists(String name) throws BackingStoreException {
+ return false;
+ }
+
+ public Preferences parent() {
+ return null;
+ }
+
+ public void put(String key, String value) {
+
+ }
+
+ public void putBoolean(String key, boolean value) {
+
+ }
+
+ public void putByteArray(String key, byte[] value) {
+
+ }
+
+ public void putDouble(String key, double value) {
+
+ }
+
+ public void putFloat(String key, float value) {
+
+ }
+
+ public void putInt(String key, int value) {
+
+ }
+
+ public void putLong(String key, long value) {
+
+ }
+
+ public void remove(String key) {
+
+ }
+
+ public void removeNode() throws BackingStoreException {
+
+ }
+
+ public void addNodeChangeListener(NodeChangeListener ncl) {
+
+ }
+
+ public void addPreferenceChangeListener(PreferenceChangeListener pcl) {
+
+ }
+
+ public void removeNodeChangeListener(NodeChangeListener ncl) {
+
+ }
+
+ public void removePreferenceChangeListener(PreferenceChangeListener pcl) {
+
+ }
+
+ public void sync() throws BackingStoreException {
+
+ }
+
+ public String toString() {
+ return null;
+ }
+
+ }
+
+}
diff --git a/prefs/src/test/java/tests/prefs/AllTests.java b/prefs/src/test/java/tests/prefs/AllTests.java
new file mode 100644
index 0000000..843d733
--- /dev/null
+++ b/prefs/src/test/java/tests/prefs/AllTests.java
@@ -0,0 +1,38 @@
+/* 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 tests.prefs;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+/**
+ * Test suite that includes all tests for the Math project.
+ */
+public class AllTests {
+
+ public static void main(String[] args) {
+ junit.textui.TestRunner.run(AllTests.suite());
+ }
+
+ public static Test suite() {
+ TestSuite suite = tests.TestSuiteFactory.createTestSuite("All Prefs test suites");
+ // $JUnit-BEGIN$
+ suite.addTest(org.apache.harmony.prefs.tests.java.util.prefs.AllTests.suite());
+ // $JUnit-END$
+ return suite;
+ }
+}
diff --git a/prefs/src/test/resources/prefs/java/util/prefs/preferences.dtd b/prefs/src/test/resources/prefs/java/util/prefs/preferences.dtd
new file mode 100644
index 0000000..a116015
--- /dev/null
+++ b/prefs/src/test/resources/prefs/java/util/prefs/preferences.dtd
@@ -0,0 +1,56 @@
+<!--
+ 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.
+ -->
+
+<!-- DTD for a Preferences tree. -->
+
+<!-- The preferences element is at the root of an XML document
+ representing a Preferences tree. -->
+<!ELEMENT preferences (root)>
+
+<!-- The preferences element contains an optional version attribute,
+ which specifies version of DTD. -->
+<!ATTLIST preferences EXTERNAL_XML_VERSION CDATA "0.0" >
+
+<!-- The root element has a map representing the root's preferences
+ (if any), and one node for each child of the root (if any). -->
+<!ELEMENT root (map, node*) >
+
+<!-- Additionally, the root contains a type attribute, which
+ specifies whether it's the system or user root. -->
+<!ATTLIST root
+ type (system|user) #REQUIRED >
+
+<!-- Each node has a map representing its preferences (if any),
+ and one node for each child (if any). -->
+
+<!ELEMENT node (map, node*) >
+
+<!-- Additionally, each node has a name attribute -->
+<!ATTLIST node
+ name CDATA #REQUIRED >
+
+<!-- A map represents the preferences stored at a node (if any). -->
+<!ELEMENT map (entry*) >
+
+<!-- An entry represents a single preference, which is simply
+ a key-value pair. -->
+<!ELEMENT entry EMPTY >
+<!ATTLIST entry
+ key CDATA #REQUIRED
+ value CDATA #REQUIRED > \ No newline at end of file
diff --git a/prefs/src/test/resources/prefs/java/util/prefs/userprefs-ascii.xml b/prefs/src/test/resources/prefs/java/util/prefs/userprefs-ascii.xml
new file mode 100644
index 0000000..9d066f1
--- /dev/null
+++ b/prefs/src/test/resources/prefs/java/util/prefs/userprefs-ascii.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="ascii"?>
+
+<!--
+ 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.
+-->
+
+<!DOCTYPE preferences SYSTEM 'http://java.sun.com/dtd/preferences.dtd'>
+
+<preferences EXTERNAL_XML_VERSION="1.0">
+ <root type="user">
+ <map />
+ <node name="tests">
+ <map />
+ <node name="api">
+ <map />
+ <node name="java">
+ <map />
+ <node name="util">
+ <map />
+ <node name="prefs">
+ <map>
+ <entry key="prefskey3" value="newvalue3" />
+ </map>
+ <node name="mock">
+ <map />
+ <node name="child">
+ <map>
+ <entry key="key2" value="value2" />
+ </map>
+ <node name="grandson">
+ <map>
+ <entry key="key3" value="value3" />
+ </map>
+ <node name="grandgrandson">
+ <map>
+ <entry key="key4" value="value4" />
+ </map>
+ </node>
+ </node>
+ </node>
+ </node>
+ </node>
+ </node>
+ </node>
+ </node>
+ </node>
+ </root>
+</preferences>
diff --git a/prefs/src/test/resources/prefs/java/util/prefs/userprefs-badencoding.xml b/prefs/src/test/resources/prefs/java/util/prefs/userprefs-badencoding.xml
new file mode 100644
index 0000000..4b99e04
--- /dev/null
+++ b/prefs/src/test/resources/prefs/java/util/prefs/userprefs-badencoding.xml
@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="badencoding"?>
+
+<!--
+ 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.
+-->
+
+<!DOCTYPE preferences SYSTEM 'http://java.sun.com/dtd/preferences.dtd'>
+
+<preferences EXTERNAL_XML_VERSION="1.0">
+ <root type="user">
+ <map />
+ <node name="tests">
+ <map />
+ <node name="api">
+ <map />
+ <node name="java">
+ <map />
+ <node name="util">
+ <map />
+ <node name="prefs">
+ <map>
+ <entry key="prefskey" value="newvalue" />
+ <entry key="prefskey3" value="newvalue3" />
+ </map>
+ <node name="mock">
+ <map />
+ <node name="child">
+ <map>
+ <entry key="key2" value="value2" />
+ </map>
+ <node name="grandson">
+ <map>
+ <entry key="key3" value="value3" />
+ </map>
+ <node name="grandgrandson">
+ <map>
+ <entry key="key4" value="value4" />
+ </map>
+ </node>
+ </node>
+ </node>
+ </node>
+ </node>
+ </node>
+ </node>
+ </node>
+ </node>
+ </root>
+</preferences>
diff --git a/prefs/src/test/resources/prefs/java/util/prefs/userprefs-badform.xml b/prefs/src/test/resources/prefs/java/util/prefs/userprefs-badform.xml
new file mode 100644
index 0000000..2c231b9
--- /dev/null
+++ b/prefs/src/test/resources/prefs/java/util/prefs/userprefs-badform.xml
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+ 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.
+-->
+
+<!DOCTYPE preferences SYSTEM 'http://java.sun.com/dtd/preferences.dtd'>
+
+<preferences EXTERNAL_XML_VERSION="1.0">
+ <root type="user">
+ <map />
+ <node name="java">
+ <map />
+ <node name="util">
+ <map />
+ <node name="prefs">
+ <map />
+ <node name="mock">
+ <map />
+ <node name="child">
+ <map>
+ <entry key="key2" value="value2" />
+ </map>
+ <node name="grandson">
+ <map>
+ <entry key="key3" value="value3" />
+ </map>
+ <node name="grandgrandson">
+ <map>
+ <entry key="key4" value="value4" />
+ </map>
+ </node>
+ </node>
+ </node>
+ </node>
+ </node>
+ </node>
+ </node>
+ </root>
diff --git a/prefs/src/test/resources/prefs/java/util/prefs/userprefs-badtype.xml b/prefs/src/test/resources/prefs/java/util/prefs/userprefs-badtype.xml
new file mode 100644
index 0000000..f974617
--- /dev/null
+++ b/prefs/src/test/resources/prefs/java/util/prefs/userprefs-badtype.xml
@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+ 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.
+-->
+
+<!DOCTYPE preferences SYSTEM 'preferences.dtd'>
+
+<preferences EXTERNAL_XML_VERSION="1.0">
+ <root type="user">
+ <map />
+ <node name="tests">
+ <map />
+ <node name="api">
+ <map />
+ <node name="java">
+ <map />
+ <node name="util">
+ <map />
+ <node name="prefs">
+ <map>
+ <entry key="prefskey" value="newvalue" />
+ <entry key="prefskey3" value="newvalue3" />
+ </map>
+ <node name="mock">
+ <map />
+ <node name="child">
+ <map>
+ <entry key="key2" value="value2" />
+ </map>
+ <node name="grandson">
+ <map>
+ <entry key="key3" value="value3" />
+ </map>
+ <node name="grandgrandson">
+ <map>
+ <entry key="key4" value="value4" />
+ </map>
+ </node>
+ </node>
+ </node>
+ </node>
+ </node>
+ </node>
+ </node>
+ </node>
+ </node>
+ </root>
+</preferences>
diff --git a/prefs/src/test/resources/prefs/java/util/prefs/userprefs-higherversion.xml b/prefs/src/test/resources/prefs/java/util/prefs/userprefs-higherversion.xml
new file mode 100644
index 0000000..a7f6aa8
--- /dev/null
+++ b/prefs/src/test/resources/prefs/java/util/prefs/userprefs-higherversion.xml
@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+ 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.
+-->
+
+<!DOCTYPE preferences SYSTEM 'http://java.sun.com/dtd/preferences.dtd'>
+
+<preferences EXTERNAL_XML_VERSION="1.1">
+ <root type="user">
+ <map />
+ <node name="tests">
+ <map />
+ <node name="api">
+ <map />
+ <node name="java">
+ <map />
+ <node name="util">
+ <map />
+ <node name="prefs">
+ <map>
+ <entry key="prefskey" value="newvalue" />
+ <entry key="prefskey3" value="newvalue3" />
+ </map>
+ <node name="mock">
+ <map />
+ <node name="child">
+ <map>
+ <entry key="key2" value="value2" />
+ </map>
+ <node name="grandson">
+ <map>
+ <entry key="key3" value="value3" />
+ </map>
+ <node name="grandgrandson">
+ <map>
+ <entry key="key4" value="value4" />
+ </map>
+ </node>
+ </node>
+ </node>
+ </node>
+ </node>
+ </node>
+ </node>
+ </node>
+ </node>
+ </root>
+</preferences>
diff --git a/prefs/src/test/resources/prefs/java/util/prefs/userprefs.xml b/prefs/src/test/resources/prefs/java/util/prefs/userprefs.xml
new file mode 100644
index 0000000..f901f5b
--- /dev/null
+++ b/prefs/src/test/resources/prefs/java/util/prefs/userprefs.xml
@@ -0,0 +1,76 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+ 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.
+-->
+
+<!DOCTYPE preferences SYSTEM 'http://java.sun.com/dtd/preferences.dtd'>
+
+<preferences EXTERNAL_XML_VERSION="1.0">
+ <root type="user">
+ <map />
+ <node name="org">
+ <map />
+ <node name="apache">
+ <map />
+ <node name="harmony">
+ <map />
+ <node name="prefs">
+ <map />
+ <node name="tests">
+ <map />
+ <node name="java">
+ <map />
+ <node name="util">
+ <map />
+
+ <node name="prefs">
+ <map>
+ <entry key="prefskey" value="newvalue" />
+ <entry key="prefskey3" value="newvalue3" />
+ </map>
+
+ <node name="mock">
+ <map />
+ <node name="child">
+ <map>
+ <entry key="key2" value="value2" />
+ </map>
+ <node name="grandson">
+ <map>
+ <entry key="key3" value="value3" />
+ </map>
+ <node name="grandgrandson">
+ <map>
+ <entry key="key4" value="value4" />
+ </map>
+ </node> <!--grandgrandson-->
+ </node> <!--grandson-->
+ </node> <!--child-->
+ </node> <!--mock-->
+
+ </node> <!--prefs-->
+ </node> <!--util-->
+ </node> <!--java-->
+ </node> <!--tests-->
+ </node> <!--prefs-->
+ </node> <!--harmony-->
+ </node> <!--apache-->
+ </node> <!--org-->
+ </root>
+</preferences>
diff --git a/prefs/src/test/resources/serialization/org/apache/harmony/prefs/tests/java/util/prefs/BackingStoreExceptionTest.golden.ser b/prefs/src/test/resources/serialization/org/apache/harmony/prefs/tests/java/util/prefs/BackingStoreExceptionTest.golden.ser
new file mode 100644
index 0000000..4d26113
--- /dev/null
+++ b/prefs/src/test/resources/serialization/org/apache/harmony/prefs/tests/java/util/prefs/BackingStoreExceptionTest.golden.ser
Binary files differ
diff --git a/prefs/src/test/resources/serialization/org/apache/harmony/prefs/tests/java/util/prefs/InvalidPreferencesFormatExceptionTest.golden.ser b/prefs/src/test/resources/serialization/org/apache/harmony/prefs/tests/java/util/prefs/InvalidPreferencesFormatExceptionTest.golden.ser
new file mode 100644
index 0000000..a15948d
--- /dev/null
+++ b/prefs/src/test/resources/serialization/org/apache/harmony/prefs/tests/java/util/prefs/InvalidPreferencesFormatExceptionTest.golden.ser
Binary files differ