This is the mail archive of the java-patches@gcc.gnu.org mailing list for the Java project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] java.util.prefs


-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Hi list,


This patch merged java.util.prefs with classpath. Please review and 
comment.


Michael
- -- 
Homepage: http://www.worldforge.org/
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.1 (GNU/Linux)

iD8DBQE+SiZKWSOgCCdjSDsRAl8nAJ438afsnhlA4f9beONdNPGvKarxGgCfZik/
W0US8XZF+K9PYqhZtcYgAKw=
=ETPW
-----END PGP SIGNATURE-----
--- /home/mkoch/src/gcc-cvs/libjava/ChangeLog	2003-02-12 11:16:32.000000000 +0100
+++ /home/mkoch/src/gcc-work/libjava/ChangeLog	2003-02-12 11:30:08.000000000 +0100
@@ -1,5 +1,41 @@
 2003-02-12  Michael Koch  <konqueror@gmx.de>
 
+  * gnu/java/util/prefs/FileBasedFactory.java,
+  gnu/java/util/prefs/MemmoryBasedFactory.java,
+  gnu/java/util/prefs/MemoryBasedPreferences.java,
+  gnu/java/util/prefs/NodeReader.java,
+  gnu/java/util/prefs/NodeWriter.java,
+  java/util/prefs/AbstractPreferences.java,
+  java/util/prefs/BackingStoreException.java,
+  java/util/prefs/InvalidPreferencesFormatException.java,
+  java/util/prefs/NodeChangeEvent.java,
+  java/util/prefs/NodeChangeListener.java,
+  java/util/prefs/PreferenceChangeEvent.java,
+  java/util/prefs/PreferenceChangeListener.java,
+  java/util/prefs/Preferences.java,
+  java/util/prefs/PreferencesFactory.java:
+  New files, all merged from classpath. All not compiled yet.
+  * Makefile.am
+  (ordinary_java_source_files): Added the following files:
+  gnu/java/util/prefs/FileBasedFactory.java,
+  gnu/java/util/prefs/MemmoryBasedFactory.java,
+  gnu/java/util/prefs/MemoryBasedPreferences.java,
+  gnu/java/util/prefs/NodeReader.java,
+  gnu/java/util/prefs/NodeWriter.java,
+  (core_java_source_files): Added the following files:
+  java/util/prefs/AbstractPreferences.java,
+  java/util/prefs/BackingStoreException.java,
+  java/util/prefs/InvalidPreferencesFormatException.java,
+  java/util/prefs/NodeChangeEvent.java,
+  java/util/prefs/NodeChangeListener.java,
+  java/util/prefs/PreferenceChangeEvent.java,
+  java/util/prefs/PreferenceChangeListener.java,
+  java/util/prefs/Preferences.java,
+  java/util/prefs/PreferencesFactory.java
+  * Makefile.in: Regenerated.
+
+2003-02-12  Michael Koch  <konqueror@gmx.de>
+
 	* java/nio/channels/Channels.java: New file.
 	* Makefile.am
 	(ordinary_java_source_files): Added java/nio/channels/Channels.java.
--- /home/mkoch/src/gcc-cvs/libjava/gnu/java/util/prefs/FileBasedFactory.java	1970-01-01 01:00:00.000000000 +0100
+++ /home/mkoch/src/gcc-work/libjava/gnu/java/util/prefs/FileBasedFactory.java	2002-01-22 23:26:58.000000000 +0100
@@ -0,0 +1,57 @@
+/* FileBasedFactory - Default Classpath implementation of a PreferencesFactory
+   Copyright (C) 2001 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+ 
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.java.util.prefs;
+
+import java.util.prefs.*;
+
+/**
+ * Default Classpath implementation of a PreferencesFactory.
+ * Returns system and user root Preferences nodes that are read from files.
+ *
+ * @author Mark Wielaard (mark@klomp.org)
+ */
+public class FileBasedFactory implements PreferencesFactory {
+
+    public Preferences systemRoot() {
+        return null;
+    }
+
+    public Preferences userRoot() {
+        return null;
+    }
+}
--- /home/mkoch/src/gcc-cvs/libjava/gnu/java/util/prefs/MemoryBasedFactory.java	1970-01-01 01:00:00.000000000 +0100
+++ /home/mkoch/src/gcc-work/libjava/gnu/java/util/prefs/MemoryBasedFactory.java	2002-01-22 23:26:58.000000000 +0100
@@ -0,0 +1,64 @@
+/* MemoryBasedFactory - Memory based PreferencesFactory usefull for testing
+   Copyright (C) 2001 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+ 
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.java.util.prefs;
+
+import java.util.prefs.*;
+
+/**
+ * Memory based PreferencesFactory usefull for testing.
+ * Returns completely empty Preferences for system and user roots.
+ * All changes are only backed by the current instances in memory.
+ *
+ * @author Mark Wielaard (mark@klomp.org)
+ */
+public class MemoryBasedFactory implements PreferencesFactory {
+
+    // Static fields containing the preferences root nodes
+    private static final Preferences systemPreferences
+        = new MemoryBasedPreferences(null, "", false);
+    private static final Preferences userPreferences
+        = new MemoryBasedPreferences(null, "", true);
+
+    public Preferences systemRoot() {
+        return systemPreferences;
+    }
+
+    public Preferences userRoot() {
+        return userPreferences;
+    }
+}
--- /home/mkoch/src/gcc-cvs/libjava/gnu/java/util/prefs/MemoryBasedPreferences.java	1970-01-01 01:00:00.000000000 +0100
+++ /home/mkoch/src/gcc-work/libjava/gnu/java/util/prefs/MemoryBasedPreferences.java	2002-01-22 23:26:58.000000000 +0100
@@ -0,0 +1,144 @@
+/* MemoryBasedPreferences - A Preference node which holds all entries in memory
+   Copyright (C) 2001 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+ 
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.java.util.prefs;
+
+import java.util.HashMap;
+
+import java.util.prefs.*;
+
+/**
+ * A Preference node which holds all entries in memory
+ *
+ * @author Mark Wielaard (mark@klomp.org)
+ */
+public class MemoryBasedPreferences extends AbstractPreferences {
+
+    /** True if this is a preference node in the user tree, false otherwise. */
+    private final boolean isUser;
+
+    /** Contains all the preference entries of this node. */
+    private HashMap entries = new HashMap();
+
+    /**
+     * Creates a new preferences node with the given name and parent.
+     * When isUser is true it will be user node otherwise it will be a system
+     * node. It will always set the <code>newNode</code> field to true
+     * since there is no real backing store, so all nodes are new.
+     */
+    public MemoryBasedPreferences(MemoryBasedPreferences parent,
+                                  String name,
+                                  boolean isUser) {
+        super(parent, name);
+        this.isUser = isUser;
+
+        // Since we do not have a real backing store all nodes are new
+        newNode = true;
+    }
+
+    /**
+     * Returns true if this node was created as a user node.
+     */
+    public boolean isUserNode() {
+        return isUser;
+    }
+
+    /**
+     * Returns an empty array since all children names are always already
+     * chached.
+     */
+    protected String[] childrenNamesSpi() throws BackingStoreException {
+        return new String[0];
+    }
+
+    /**
+     * Returns a new node with the given name with as parent this node and
+     * with the <code>isUser</code> flag set to the same value as this node.
+     */
+    protected AbstractPreferences childSpi(String childName) {
+       return new MemoryBasedPreferences(this, childName, isUser);
+    }
+
+    /**
+     * Returns a (possibly empty) array of keys of the preferences entries of
+     * this node.
+     */
+    protected String[] keysSpi() throws BackingStoreException {
+        return (String[]) entries.keySet().toArray(new String[entries.size()]);
+    }
+
+    /**
+     * Returns the associated value from this nodes preferences entries or
+     * null when the key has not been set.
+     */
+    protected String getSpi(String key) {
+        return (String) entries.get(key);
+    }
+
+    /**
+     * Sets the value for the given key.
+     */
+    protected void putSpi(String key, String value) {
+        entries.put(key, value);
+    }
+
+    /**
+     * Removes the entry with the given key.
+     */
+    protected void removeSpi(String key) {
+        entries.remove(key);
+    }
+
+    /**
+     * Does nothing since we do not have any backing store.
+     */
+    protected void flushSpi() {
+    }
+
+    /**
+     * Does nothing since we do not have any backing store.
+     */
+    protected void syncSpi() {
+    }
+
+    /**
+     * Just removes the entries map of this node.
+     */
+    protected void removeNodeSpi() {
+        entries = null;
+    }
+}
--- /home/mkoch/src/gcc-cvs/libjava/gnu/java/util/prefs/NodeReader.java	1970-01-01 01:00:00.000000000 +0100
+++ /home/mkoch/src/gcc-work/libjava/gnu/java/util/prefs/NodeReader.java	2002-09-12 15:36:47.000000000 +0200
@@ -0,0 +1,223 @@
+/* NodeReader - Reads and imports preferences nodes from files
+   Copyright (C) 2001 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+ 
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.java.util.prefs;
+
+import java.io.BufferedReader;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.Reader;
+
+import java.util.prefs.*;
+
+/**
+ * Reads and imports preferences nodes from files.
+ *
+ * @author Mark Wielaard (mark@klomp.org)
+ */
+public class NodeReader {
+
+    private final BufferedReader br;
+    private String line = "";
+
+    private final PreferencesFactory factory;
+
+    public NodeReader(Reader r, PreferencesFactory factory) {
+        if(r instanceof BufferedReader) {
+            br = (BufferedReader) r;
+        } else {
+            br = new BufferedReader(r);
+        }
+        this.factory = factory;
+    }
+
+    public NodeReader(InputStream is, PreferencesFactory factory) {
+        this(new InputStreamReader(is), factory);
+    }
+
+    public void importPreferences()
+                    throws InvalidPreferencesFormatException, IOException
+    {
+        readPreferences();
+    }
+
+    private void readPreferences()
+                    throws InvalidPreferencesFormatException, IOException
+    {
+        // Begin starting tag
+        skipTill("<preferences");
+
+        readRoot();
+
+        // Ending tag
+        skipTill("</preferences>");
+    }
+
+    private void readRoot()
+                    throws InvalidPreferencesFormatException, IOException
+    {
+        // Begin starting tag
+        skipTill("<root");
+
+        // type attribute
+        skipTill("type=\"");
+        String type = readTill("\"");
+        Preferences root;
+        if ("user".equals(type)) {
+            root = factory.userRoot();
+        } else if ("system".equals(type)) {
+            root = factory.systemRoot();
+        } else {
+            throw new InvalidPreferencesFormatException("Unknown type: "
+                                                        + type);
+        }
+
+        // Read root map and subnodes
+        readMap(root);
+        readNodes(root);
+
+        // Ending tag
+        skipTill("</root>");
+    }
+
+    private void readNodes(Preferences node)
+                    throws InvalidPreferencesFormatException, IOException
+    {
+        while ("node".equals(nextTag())) {
+            skipTill("<node");
+            skipTill("name=\"");
+            String name = readTill("\"");
+            Preferences subnode = node.node(name);
+            System.out.println("Found subnode: " + subnode.absolutePath());
+            readMap(subnode);
+            readNodes(subnode);
+            skipTill("</node>");
+        }
+        
+    }
+
+    private void readMap(Preferences node)
+                    throws InvalidPreferencesFormatException, IOException
+    {
+        // Begin map tag
+        skipTill("<map");
+
+        // Empty map?
+        if (line.startsWith("/>")) {
+            line = line.substring(2);
+            return;
+        }
+
+        // Map entries
+        readEntries(node);
+
+        // Ending tag
+        skipTill("</map>");
+    }
+
+    private void readEntries(Preferences node)
+                    throws InvalidPreferencesFormatException, IOException
+    {
+        while ("entry".equals(nextTag())) {
+            skipTill("<entry");
+            skipTill("key=\"");
+            String key = readTill("\"");
+            skipTill("value=\"");
+            String value = readTill("\"");
+            System.out.println("Key: " + key + " Value: " + value);
+            node.put(key, value);
+        }
+    }
+
+    private void skipTill(String s)
+                    throws InvalidPreferencesFormatException, IOException
+    {
+        while(true) {
+            if (line == null)
+                throw new InvalidPreferencesFormatException(s + " not found");
+            
+            int index = line.indexOf(s);
+            if (index == -1)  {
+                line = br.readLine();
+            } else {
+                line = line.substring(index+s.length());
+                return;
+            }
+        }
+    }
+
+    private String readTill(String s)
+                    throws InvalidPreferencesFormatException
+    {
+        int index = line.indexOf(s);
+        if (index == -1)
+                throw new InvalidPreferencesFormatException(s + " not found");
+
+        String read = line.substring(0, index);
+        line = line.substring(index+s.length());
+
+        return read;
+    }
+
+    private String nextTag()
+                    throws InvalidPreferencesFormatException, IOException
+    {
+        while(true) {
+            if (line == null)
+                throw new InvalidPreferencesFormatException("unexpected EOF");
+            
+            int start = line.indexOf("<");
+            if (start == -1)  {
+                line = br.readLine();
+            } else {
+                // Find end of tag
+                int end = start+1;
+                while (end != line.length()
+                       && " \t\r\n".indexOf(line.charAt(end)) == -1) {
+                    end++;
+                }
+                // Line now starts at the found tag
+                String tag = line.substring(start+1,end);
+                line = line.substring(start);
+                return tag;
+            }
+        }
+    }
+
+}
--- /home/mkoch/src/gcc-cvs/libjava/gnu/java/util/prefs/NodeWriter.java	1970-01-01 01:00:00.000000000 +0100
+++ /home/mkoch/src/gcc-work/libjava/gnu/java/util/prefs/NodeWriter.java	2002-01-22 23:26:58.000000000 +0100
@@ -0,0 +1,315 @@
+/* NodeWriter - Writes and exports preferences nodes to files
+   Copyright (C) 2001 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+ 
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.java.util.prefs;
+
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
+
+import java.util.StringTokenizer;
+
+import java.util.prefs.*;
+
+/**
+ * Writes and exports preferences nodes to files
+ *
+ * @author Mark Wielaard (mark@klomp.org)
+ */
+public class NodeWriter {
+
+    /** The Preferences node to write. */
+    private final Preferences prefs;
+
+    /** The bufferedWriter to write the node to. */
+    private final BufferedWriter bw;
+
+    /**
+     * True if the complete sub tree should be written,
+     * false if only the node should be written.
+     */
+    private boolean subtree;
+
+    /**
+     * Creates a new NodeWriter for the given preferences node and writer.
+     */
+    public NodeWriter(Preferences prefs, Writer w) {
+        this.prefs = prefs;
+        if (w instanceof BufferedWriter) {
+            this.bw = (BufferedWriter) w;
+        } else {
+            this.bw = new BufferedWriter(w);
+        }
+    }
+
+    /**
+     * Creates a new NodeWriter for the given preferences node and
+     * outputstream. Creates a new OutputStreamWriter.
+     */
+    public NodeWriter(Preferences prefs, OutputStream os) {
+        this(prefs, new OutputStreamWriter(os));
+    }
+
+    /**
+     * Writes the preference node plus the complete subtree.
+     */
+    public void writePrefsTree() throws BackingStoreException, IOException {
+        subtree = true;
+        writeHeader();
+        writePreferences();
+        bw.flush();
+    }
+
+    /**
+     * Writes only the preference node.
+     */
+    public void writePrefs() throws BackingStoreException, IOException {
+        subtree = false;
+        writeHeader();
+        writePreferences();
+        bw.flush();
+    }
+
+    /**
+     * Writes the standard header.
+     */
+    private void writeHeader() throws BackingStoreException, IOException {
+        bw.write("<?xml version=\"1.0\"?>");
+        bw.newLine();
+        bw.newLine();
+        bw.write("<!-- GNU Classpath java.util.prefs Preferences ");
+
+        if (prefs.isUserNode()) {
+            bw.write("user");
+        } else {
+            bw.write("system");
+        }
+
+        // root node?
+        if (prefs.parent() == null) {
+            bw.write(" root");
+        }
+
+        if (subtree) {
+            bw.write(" tree");
+        } else {
+            bw.write(" node");
+        }
+
+        // no root?
+        if (prefs.parent() != null) {
+            bw.newLine();
+            bw.write("     '");
+            bw.write(prefs.absolutePath());
+            bw.write('\'');
+            bw.newLine();
+        }
+        bw.write(" -->");
+        bw.newLine();
+        bw.newLine();
+    }
+
+    /**
+     * Write the preferences tag and the root.
+     */
+    private void writePreferences() throws BackingStoreException, IOException {
+        bw.write("<preferences>");
+        bw.newLine();
+        writeRoot();
+        bw.write("</preferences>");
+        bw.newLine();
+    }
+
+    private void writeRoot() throws BackingStoreException, IOException {
+        bw.write("  <root type=\"");
+        if (prefs.isUserNode()) {
+            bw.write("user");
+        } else {
+            bw.write("system");
+        }
+        bw.write("\"/>");
+
+        writeRootMap();
+        writeNode();
+
+        bw.write("  </root>");
+        bw.newLine();
+    }
+
+    private void writeRootMap() throws BackingStoreException, IOException {
+        // Is it a root node?
+        if(prefs.parent() == null && prefs.keys().length > 0) {
+            bw.newLine();
+            writeMap(prefs, 2);
+        } else {
+            bw.write("<map/>");
+            bw.newLine();
+        }
+    }
+
+    /**
+     * Writes all the parents of the preferences node without any entries.
+     * Returns the number of parents written, which has to be used as
+     * argument to <code>writeCloseParents()</code> after writing the node
+     * itself.
+     */
+    private int writeParents() throws IOException {
+        int parents;
+        String path = prefs.absolutePath();
+        int lastslash = path.lastIndexOf("/");
+        if (lastslash > 0) {
+            path = path.substring(1, lastslash);
+            StringTokenizer st = new StringTokenizer(path);
+            parents = st.countTokens();
+
+            System.out.println("path: " + path);
+            System.out.println("parents: " + parents);
+
+            for (int i=0; i<parents; i++) {
+                String name = st.nextToken();
+                indent(i+2);
+                bw.write("<node name=\"" + name + "\">");
+                bw.write("<map/>");
+                bw.write("</node>");
+                bw.newLine();
+            }
+        } else {
+            parents = 0;
+        }
+
+        return parents;
+    }
+
+    private void writeCloseParents(int parents) throws IOException {
+        while(parents > 0) {
+            indent(parents+1);
+            bw.write("</node>");
+            bw.newLine();
+            parents--;
+        }
+    }
+
+    private void writeNode() throws BackingStoreException, IOException {
+        int parents = writeParents();
+        // root?
+        int indent;
+        if (prefs.parent() == null) {
+            indent = parents+1;
+        } else {
+            indent = parents+2;
+        }
+        writeNode(prefs, indent);
+        writeCloseParents(parents);
+    }
+
+    private void writeNode(Preferences node, int indent)
+                                    throws BackingStoreException, IOException
+    {
+        // not root?
+        if (node.parent() != null) {
+            indent(indent);
+            bw.write("<node name=\"" + node.name() + "\">");
+            if (node.keys().length > 0) {
+                bw.newLine();
+            }
+            writeMap(node, indent+1);
+        }
+
+        if (subtree) {
+            String[] children = node.childrenNames();
+            for (int i=0; i<children.length; i++) {
+                Preferences child = node.node(children[i]);
+                writeNode(child, indent+1);
+            }
+        }
+
+        // not root?
+        if (node.parent() != null) {
+            indent(indent);
+            bw.write("</node>");
+            bw.newLine();
+        }
+    }
+
+    private void writeMap(Preferences node, int indent) 
+                                    throws BackingStoreException, IOException
+    {
+        // construct String used for indentation
+        StringBuffer indentBuffer = new StringBuffer(2*indent);
+        for (int i=0; i < indent; i++)
+            indentBuffer.append("  ");
+        String indentString = indentBuffer.toString();
+
+        if (node.keys().length > 0) {
+            bw.write(indentString);
+            bw.write("<map>");
+            bw.newLine();
+            writeEntries(node, indentString + "  ");
+            bw.write(indentString);
+            bw.write("</map>");
+        } else {
+            bw.write("<map/>");
+        }
+        bw.newLine();
+    }
+
+    private void writeEntries(Preferences node, String indent)
+                                    throws BackingStoreException, IOException
+    {
+        String[] keys = node.keys();
+        for(int i = 0; i < keys.length; i++) {
+            String value = node.get(keys[i], null);
+            if (value == null) {
+                throw new BackingStoreException("null value for key '"
+                                                + keys[i] + "'");
+            }
+
+            bw.write(indent);
+            bw.write("<entry key=\"" + keys[i] + "\""
+                    + " value=\"" + value + "\"/>");
+            bw.newLine();
+        }
+    }
+
+    private void indent(int x) throws IOException {
+        for (int i=0; i<x; i++) {
+            bw.write("  ");
+        }
+    }
+}
--- /home/mkoch/src/gcc-cvs/libjava/java/util/prefs/AbstractPreferences.java	1970-01-01 01:00:00.000000000 +0100
+++ /home/mkoch/src/gcc-work/libjava/java/util/prefs/AbstractPreferences.java	2002-05-06 18:19:20.000000000 +0200
@@ -0,0 +1,1258 @@
+/* AbstractPreferences - Partial implementation of a Preference node
+   Copyright (C) 2001 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+ 
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+package java.util.prefs;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import java.util.Iterator;
+import java.util.HashMap;
+import java.util.TreeSet;
+
+import gnu.java.util.prefs.NodeWriter;
+
+/**
+ * Partial implementation of a Preference node.
+ *
+ * Methods that still need to be implemented are <code>isUserNode(), XXX
+ *
+ * @since 1.4
+ * @author Mark Wielaard (mark@klomp.org)
+ */
+public abstract class AbstractPreferences extends Preferences {
+
+    // protected fields
+
+    /**
+     * Object used to lock this preference node. Any thread only locks nodes
+     * downwards when it has the lock on the current node. No method should
+     * synchronize on the lock of any of its parent nodes while holding the
+     * lock on the current node.
+     */
+    protected final Object lock = new Object();
+
+    /**
+     * Set to true in the contructor if the node did not exist in the backing
+     * store when this preference node object was created. Should be set in
+     * the contructor of a subclass. Defaults to false. Used to fire node
+     * changed events.
+     */
+    protected boolean newNode = false;
+
+    // private fields
+
+    /**
+     * The parent preferences node or null when this is the root node.
+     */
+    private final AbstractPreferences parent;
+
+    /**
+     * The name of this node.
+     * Only when this is a root node (parent == null) the name is empty.
+     * It has a maximum of 80 characters and cannot contain any '/' characters.
+     */
+    private final String name;
+
+    /** True when this node has been remove, false otherwise. */
+    private boolean removed = false;
+
+    /**
+     * Holds all the child names and nodes of this node that have been
+     * accessed by earlier <code>getChild()</code> or <code>childSpi()</code>
+     * invocations and that have not been removed.
+     */
+    private HashMap childCache = new HashMap();
+
+    // constructor
+
+    /**
+     * Creates a new AbstractPreferences node with the given parent and name.
+     * 
+     * @param parent the parent of this node or null when this is the root node
+     * @param name the name of this node, can not be null, only 80 characters
+     *             maximum, must be empty when parent is null and cannot
+     *             contain any '/' characters
+     * @exception IllegalArgumentException when name is null, greater then 80
+     *            characters, not the empty string but parent is null or
+     *            contains a '/' character
+     */
+    protected AbstractPreferences(AbstractPreferences parent, String name) {
+        if (  (name == null)                            // name should be given
+           || (name.length() > MAX_NAME_LENGTH)         // 80 characters max
+           || (parent == null && name.length() != 0)    // root has no name
+           || (parent != null && name.length() == 0)    // all other nodes do
+           || (name.indexOf('/') != -1))                // must not contain '/'
+            throw new IllegalArgumentException("Illegal name argument '"
+                                               + name
+                                               + "' (parent is "
+                                               + parent == null ? "" : "not "
+                                               + "null)");
+        this.parent = parent;
+        this.name = name;
+    }
+
+    // identification methods
+
+    /**
+     * Returns the absolute path name of this preference node.
+     * The absolute path name of a node is the path name of its parent node
+     * plus a '/' plus its own name. If the node is the root node and has no
+     * parent then its path name is "" and its absolute path name is "/".
+     */
+    public String absolutePath() {
+        if (parent == null)
+            return "/";
+        else
+            return parent.path() + '/' + name;
+    }
+
+    /**
+     * Private helper method for absolutePath. Returns the empty string for a
+     * root node and otherwise the parentPath of its parent plus a '/'.
+     */
+    private String path() {
+        if (parent == null)
+            return "";
+        else
+            return parent.path() + '/' + name;
+    }
+
+    /**
+     * Returns true if this node comes from the user preferences tree, false
+     * if it comes from the system preferences tree.
+     */
+    abstract public boolean isUserNode();
+
+    /**
+     * Returns the name of this preferences node. The name of the node cannot
+     * be null, can be mostly 80 characters and cannot contain any '/'
+     * characters. The root node has as name "".
+     */
+    public String name() {
+        return name;
+    }
+
+    /**
+     * Returns the String given by
+     * <code>
+     * (isUserNode() ? "User":"System") + " Preference Node: " + absolutePath()
+     * </code>
+     */
+    public String toString() {
+        return (isUserNode() ? "User":"System")
+               + " Preference Node: "
+               + absolutePath();
+    }
+
+    /**
+     * Returns all the direct sub nodes of this preferences node.
+     * Needs access to the backing store to give a meaningfull answer.
+     * <p>
+     * This implementation locks this node, checks if the node has not yet
+     * been removed and throws an <code>IllegalStateException</code> when it
+     * has been. Then it creates a new <code>TreeSet</code> and adds any
+     * already cached child nodes names. To get any uncached names it calls
+     * <code>childrenNamesSpi()</code> and adds the result to the set. Finally
+     * it calls <code>toArray()</code> on the created set. When the call to
+     * <code>childrenNamesSpi</code> thows an <code>BackingStoreException</code>
+     * this method will not catch that exception but propagate the exception
+     * to the caller.
+     *
+     * @exception BackingStoreException when the backing store cannot be
+     *            reached
+     * @exception IllegalStateException when this node has been removed
+     */
+    public String[] childrenNames() throws BackingStoreException {
+        synchronized(lock) {
+            if (isRemoved())
+                throw new IllegalStateException("Node removed");
+
+            TreeSet childrenNames = new TreeSet();
+
+            // First get all cached node names
+            childrenNames.addAll(childCache.keySet());
+            
+            // Then add any others
+            String names[] = childrenNamesSpi();
+            for (int i = 0; i < names.length; i++) {
+                childrenNames.add(names[i]);
+            }
+
+            // And return the array of names
+            String[] children = new String[childrenNames.size()];
+            childrenNames.toArray(children);
+            return children;
+
+        }
+    }
+
+    /**
+     * Returns a sub node of this preferences node if the given path is
+     * relative (does not start with a '/') or a sub node of the root
+     * if the path is absolute (does start with a '/').
+     * <p>
+     * This method first locks this node and checks if the node has not been
+     * removed, if it has been removed it throws an exception. Then if the
+     * path is relative (does not start with a '/') it checks if the path is
+     * legal (does not end with a '/' and has no consecutive '/' characters).
+     * Then it recursively gets a name from the path, gets the child node
+     * from the child-cache of this node or calls the <code>childSpi()</code>
+     * method to create a new child sub node. This is done recursively on the
+     * newly created sub node with the rest of the path till the path is empty.
+     * If the path is absolute (starts with a '/') the lock on this node is
+     * droped and this method is called on the root of the preferences tree
+     * with as argument the complete path minus the first '/'.
+     *
+     * @exception IllegalStateException if this node has been removed
+     * @exception IllegalArgumentException if the path contains two or more
+     * consecutive '/' characters, ends with a '/' charactor and is not the
+     * string "/" (indicating the root node) or any name on the path is more
+     * then 80 characters long
+     */
+    public Preferences node(String path) {
+        synchronized(lock) {
+            if (isRemoved())
+                throw new IllegalStateException("Node removed");
+
+            // Is it a relative path?
+            if (!path.startsWith("/")) {
+
+                // Check if it is a valid path
+                if (path.indexOf("//") != -1 || path.endsWith("/"))
+                    throw new IllegalArgumentException(path);
+
+                return getNode(path);
+            }
+        }
+
+        // path started with a '/' so it is absolute
+        // we drop the lock and start from the root (omitting the first '/')
+        Preferences root = isUserNode() ? userRoot() : systemRoot();
+        return root.node(path.substring(1));
+
+    }
+
+    /**
+     * Private helper method for <code>node()</code>. Called with this node
+     * locked. Returns this node when path is the empty string, if it is not
+     * empty the next node name is taken from the path (all chars till the
+     * next '/' or end of path string) and the node is either taken from the
+     * child-cache of this node or the <code>childSpi()</code> method is called
+     * on this node with the name as argument. Then this method is called
+     * recursively on the just constructed child node with the rest of the
+     * path.
+     *
+     * @param path should not end with a '/' character and should not contain
+     *        consecutive '/' characters
+     * @exception IllegalArgumentException if path begins with a name that is
+     *            larger then 80 characters.
+     */
+    private Preferences getNode(String path) {
+        // if mark is dom then goto end
+
+        // Empty String "" indicates this node
+        if (path.length() == 0)
+            return this;
+
+        // Calculate child name and rest of path
+        String childName;
+        String childPath;
+        int nextSlash = path.indexOf('/');
+        if (nextSlash == -1) {
+            childName = path;
+            childPath = "";
+        } else {
+            childName = path.substring(0, nextSlash);
+            childPath = path.substring(nextSlash+1);
+        }
+
+        // Get the child node
+        AbstractPreferences child;
+        child = (AbstractPreferences)childCache.get(childName);
+        if (child == null) {
+
+            if (childName.length() > MAX_NAME_LENGTH)
+               throw new IllegalArgumentException(childName); 
+
+            // Not in childCache yet so create a new sub node
+            child = childSpi(childName);
+            // XXX - check if node is new
+            childCache.put(childName, child);
+        }
+
+        // Lock the child and go down
+        synchronized(child.lock) {
+            return child.getNode(childPath);
+        }
+    }
+
+    /**
+     * Returns true if the node that the path points to exists in memory or
+     * in the backing store. Otherwise it returns false or an exception is
+     * thrown. When this node is removed the only valid parameter is the
+     * empty string (indicating this node), the return value in that case
+     * will be false.
+     *
+     * @exception BackingStoreException when the backing store cannot be
+     *            reached
+     * @exception IllegalStateException if this node has been removed
+     *            and the path is not the empty string (indicating this node)
+     * @exception IllegalArgumentException if the path contains two or more
+     * consecutive '/' characters, ends with a '/' charactor and is not the
+     * string "/" (indicating the root node) or any name on the path is more
+     * then 80 characters long
+     */
+    public boolean nodeExists(String path) throws BackingStoreException {
+        synchronized(lock) {
+            if (isRemoved() && path.length() != 0)
+                throw new IllegalStateException("Node removed");
+
+            // Is it a relative path?
+            if (!path.startsWith("/")) {
+
+                // Check if it is a valid path
+                if (path.indexOf("//") != -1 || path.endsWith("/"))
+                    throw new IllegalArgumentException(path);
+
+                return existsNode(path);
+            }
+        }
+
+        // path started with a '/' so it is absolute
+        // we drop the lock and start from the root (omitting the first '/')
+        Preferences root = isUserNode() ? userRoot() : systemRoot();
+        return root.nodeExists(path.substring(1));
+
+    }
+
+    private boolean existsNode(String path) throws BackingStoreException {
+
+        // Empty String "" indicates this node
+        if (path.length() == 0)
+            return(!isRemoved());
+
+        // Calculate child name and rest of path
+        String childName;
+        String childPath;
+        int nextSlash = path.indexOf('/');
+        if (nextSlash == -1) {
+            childName = path;
+            childPath = "";
+        } else {
+            childName = path.substring(0, nextSlash);
+            childPath = path.substring(nextSlash+1);
+        }
+
+        // Get the child node
+        AbstractPreferences child;
+        child = (AbstractPreferences)childCache.get(childName);
+        if (child == null) {
+
+            if (childName.length() > MAX_NAME_LENGTH)
+               throw new IllegalArgumentException(childName);
+
+            // Not in childCache yet so create a new sub node
+            child = getChild(childName);
+
+            if (child == null)
+                return false;
+
+            childCache.put(childName, child);
+        }
+
+        // Lock the child and go down
+        synchronized(child.lock) {
+            return child.existsNode(childPath);
+        }
+    }
+
+    /**
+     * Returns the child sub node if it exists in the backing store or null
+     * if it does not exist. Called (indirectly) by <code>nodeExists()</code>
+     * when a child node name can not be found in the cache.
+     * <p>
+     * Gets the lock on this node, calls <code>childrenNamesSpi()</code> to
+     * get an array of all (possibly uncached) children and compares the
+     * given name with the names in the array. If the name is found in the
+     * array <code>childSpi()</code> is called to get an instance, otherwise
+     * null is returned.
+     *
+     * @exception BackingStoreException when the backing store cannot be
+     *            reached
+     */
+    protected AbstractPreferences getChild(String name)
+                                    throws BackingStoreException
+    {
+        synchronized(lock) {
+            // Get all the names (not yet in the cache)
+            String[] names = childrenNamesSpi();
+            for (int i=0; i < names.length; i++)
+                if (name.equals(names[i]))
+                    return childSpi(name);
+           
+            // No child with that name found
+            return null;
+        }
+    }
+
+    /**
+     * Returns true if this node has been removed with the
+     * <code>removeNode()</code> method, false otherwise.
+     * <p>
+     * Gets the lock on this node and then returns a boolean field set by
+     * <code>removeNode</code> methods.
+     */
+    protected boolean isRemoved() {
+        synchronized(lock) {
+            return removed;
+        }
+    }
+
+    /**
+     * Returns the parent preferences node of this node or null if this is
+     * the root of the preferences tree.
+     * <p>
+     * Gets the lock on this node, checks that the node has not been removed
+     * and returns the parent given to the constructor.
+     *
+     * @exception IllegalStateException if this node has been removed
+     */
+    public Preferences parent() {
+        synchronized(lock) {
+            if (isRemoved())
+                throw new IllegalStateException("Node removed");
+
+            return parent;
+        }
+    }
+
+    // export methods
+
+    /**
+     * XXX
+     */
+    public void exportNode(OutputStream os)
+                                    throws BackingStoreException,
+                                           IOException
+    {
+        NodeWriter nodeWriter = new NodeWriter(this, os);
+        nodeWriter.writePrefs();
+    }
+
+    /**
+     * XXX
+     */
+    public void exportSubtree(OutputStream os)
+                                    throws BackingStoreException,
+                                           IOException
+    {
+        NodeWriter nodeWriter = new NodeWriter(this, os);
+        nodeWriter.writePrefsTree();
+    }
+
+    // preference entry manipulation methods
+
+    /**
+     * Returns an (possibly empty) array with all the keys of the preference
+     * entries of this node.
+     * <p>
+     * This method locks this node and checks if the node has not been
+     * removed, if it has been removed it throws an exception, then it returns
+     * the result of calling <code>keysSpi()</code>.
+     * 
+     * @exception BackingStoreException when the backing store cannot be     
+     *            reached
+     * @exception IllegalStateException if this node has been removed
+     */
+    public String[] keys() throws BackingStoreException {
+        synchronized(lock) {
+            if (isRemoved())
+                throw new IllegalStateException("Node removed");
+
+            return keysSpi();
+        }
+    }
+
+
+    /**
+     * Returns the value associated with the key in this preferences node. If
+     * the default value of the key cannot be found in the preferences node
+     * entries or something goes wrong with the backing store the supplied
+     * default value is returned.
+     * <p>
+     * Checks that key is not null and not larger then 80 characters,
+     * locks this node, and checks that the node has not been removed.
+     * Then it calls <code>keySpi()</code> and returns
+     * the result of that method or the given default value if it returned
+     * null or throwed an exception.
+     *
+     * @exception IllegalArgumentException if key is larger then 80 characters
+     * @exception IllegalStateException if this node has been removed
+     * @exception NullPointerException if key is null
+     */
+    public String get(String key, String defaultVal) {
+        if (key.length() > MAX_KEY_LENGTH)
+            throw new IllegalArgumentException(key);
+
+        synchronized(lock) {
+            if (isRemoved())
+                throw new IllegalStateException("Node removed");
+
+            String value;
+            try {
+                value = getSpi(key);
+            } catch (Throwable t) {
+                value = null;
+            }
+
+            if (value != null) {
+                return value;
+            } else {
+                return defaultVal;
+            }
+        }
+    }
+
+    /**
+     * Convenience method for getting the given entry as a boolean.
+     * When the string representation of the requested entry is either
+     * "true" or "false" (ignoring case) then that value is returned,
+     * otherwise the given default boolean value is returned.
+     *
+     * @exception IllegalArgumentException if key is larger then 80 characters
+     * @exception IllegalStateException if this node has been removed
+     * @exception NullPointerException if key is null
+     */
+    public boolean getBoolean(String key, boolean defaultVal) {
+        String value = get(key, null);
+
+        if ("true".equalsIgnoreCase(value))
+            return true;
+
+        if ("false".equalsIgnoreCase(value))
+            return false;
+        
+        return defaultVal;
+    }
+
+    /**
+     * Convenience method for getting the given entry as a byte array.
+     * When the string representation of the requested entry is a valid
+     * Base64 encoded string (without any other characters, such as newlines)
+     * then the decoded Base64 string is returned as byte array,
+     * otherwise the given default byte array value is returned.
+     *
+     * @exception IllegalArgumentException if key is larger then 80 characters
+     * @exception IllegalStateException if this node has been removed
+     * @exception NullPointerException if key is null
+     */
+    public byte[] getByteArray(String key, byte[] defaultVal) {
+        String value = get(key, null);
+
+        byte[] b = null;
+        if (value != null) {
+            b = decode64(value);
+        }
+
+        if (b != null)
+            return b;
+        else
+            return defaultVal;
+    }
+    
+    /**
+     * Helper method for decoding a Base64 string as an byte array.
+     * Returns null on encoding error. This method does not allow any other
+     * characters present in the string then the 65 special base64 chars.
+     */
+    private static byte[] decode64(String s) {
+        ByteArrayOutputStream bs = new ByteArrayOutputStream((s.length()/4)*3);
+        char[] c = new char[s.length()];
+        s.getChars(0, s.length(), c, 0);
+
+        // Convert from base64 chars
+        int endchar = -1;
+        for(int j = 0; j < c.length && endchar == -1; j++) {
+            if (c[j] >= 'A' && c[j] <= 'Z') {
+                c[j] -= 'A';
+            } else if (c[j] >= 'a' && c[j] <= 'z') {
+                c[j] = (char) (c[j] + 26 - 'a');
+            } else if (c[j] >= '0' && c[j] <= '9') {
+                c[j] = (char) (c[j] + 52 - '0');
+            } else if (c[j] == '+') {
+                c[j] = 62;
+            } else if (c[j] == '/') {
+                c[j] = 63;
+            } else if (c[j] == '=') {
+                endchar = j;
+            } else {
+                return null; // encoding exception
+            }
+        }
+
+        int remaining = endchar == -1 ? c.length : endchar;
+        int i = 0;
+        while (remaining > 0) {
+            // Four input chars (6 bits) are decoded as three bytes as
+            // 000000 001111 111122 222222
+
+            byte b0 = (byte) (c[i] << 2);
+            if (remaining >= 2) {
+                b0 += (c[i+1] & 0x30) >> 4;
+            }
+            bs.write(b0);
+
+            if (remaining >= 3) {
+                byte b1 = (byte) ((c[i+1] & 0x0F) << 4);
+                b1 += (byte) ((c[i+2] & 0x3C) >> 2);
+                bs.write(b1);
+            }
+
+            if (remaining >= 4) {
+                byte b2 = (byte) ((c[i+2] & 0x03) << 6);
+                b2 += c[i+3];
+                bs.write(b2);
+            }
+
+            i += 4;
+            remaining -= 4;
+        }
+
+        return bs.toByteArray();
+    }
+
+    /**
+     * Convenience method for getting the given entry as a double.
+     * When the string representation of the requested entry can be decoded
+     * with <code>Double.parseDouble()</code> then that double is returned,
+     * otherwise the given default double value is returned.
+     *
+     * @exception IllegalArgumentException if key is larger then 80 characters
+     * @exception IllegalStateException if this node has been removed
+     * @exception NullPointerException if key is null
+     */
+    public double getDouble(String key, double defaultVal) {
+        String value = get(key, null);
+
+        if (value != null) {
+            try {
+                return Double.parseDouble(value);
+            } catch (NumberFormatException nfe) { /* ignore */ }
+        }
+
+        return defaultVal;
+    }
+
+    /**
+     * Convenience method for getting the given entry as a float.
+     * When the string representation of the requested entry can be decoded
+     * with <code>Float.parseFloat()</code> then that float is returned,
+     * otherwise the given default float value is returned.
+     *
+     * @exception IllegalArgumentException if key is larger then 80 characters
+     * @exception IllegalStateException if this node has been removed
+     * @exception NullPointerException if key is null
+     */
+    public float getFloat(String key, float defaultVal) {
+        String value = get(key, null);
+
+        if (value != null) {
+            try {
+                return Float.parseFloat(value);
+            } catch (NumberFormatException nfe) { /* ignore */ }
+        }
+
+        return defaultVal;
+    }
+
+    /**
+     * Convenience method for getting the given entry as an integer.
+     * When the string representation of the requested entry can be decoded
+     * with <code>Integer.parseInt()</code> then that integer is returned,
+     * otherwise the given default integer value is returned.
+     *
+     * @exception IllegalArgumentException if key is larger then 80 characters
+     * @exception IllegalStateException if this node has been removed
+     * @exception NullPointerException if key is null
+     */
+    public int getInt(String key, int defaultVal) {
+        String value = get(key, null);
+
+        if (value != null) {
+            try {
+                return Integer.parseInt(value);
+            } catch (NumberFormatException nfe) { /* ignore */ }
+        }
+
+        return defaultVal;
+    }
+
+    /**
+     * Convenience method for getting the given entry as a long.
+     * When the string representation of the requested entry can be decoded
+     * with <code>Long.parseLong()</code> then that long is returned,
+     * otherwise the given default long value is returned.
+     *
+     * @exception IllegalArgumentException if key is larger then 80 characters
+     * @exception IllegalStateException if this node has been removed
+     * @exception NullPointerException if key is null
+     */
+    public long getLong(String key, long defaultVal) {
+        String value = get(key, null);
+
+        if (value != null) {
+            try {
+                return Long.parseLong(value);
+            } catch (NumberFormatException nfe) { /* ignore */ }
+        }
+
+        return defaultVal;
+    }
+
+    /**
+     * Sets the value of the given preferences entry for this node.
+     * Key and value cannot be null, the key cannot exceed 80 characters
+     * and the value cannot exceed 8192 characters.
+     * <p>
+     * The result will be immediatly visible in this VM, but may not be
+     * immediatly written to the backing store.
+     * <p>
+     * Checks that key and value are valid, locks this node, and checks that
+     * the node has not been removed. Then it calls <code>putSpi()</code>.
+     *
+     * @exception NullPointerException if either key or value are null
+     * @exception IllegalArgumentException if either key or value are to large
+     * @exception IllegalStateException when this node has been removed
+     */
+    public void put(String key, String value) {
+        if (key.length() > MAX_KEY_LENGTH
+            || value.length() > MAX_VALUE_LENGTH)
+            throw new IllegalArgumentException("key ("
+                                               + key.length() + ")"
+                                               + " or value ("
+                                               + value.length() + ")"
+                                               + " to large");
+        synchronized(lock) {
+            if (isRemoved())
+                throw new IllegalStateException("Node removed");
+
+            putSpi(key, value);
+
+            // XXX - fire events
+        }
+            
+    }
+
+    /**
+     * Convenience method for setting the given entry as a boolean.
+     * The boolean is converted with <code>Boolean.toString(value)</code>
+     * and then stored in the preference entry as that string.
+     *
+     * @exception NullPointerException if key is null
+     * @exception IllegalArgumentException if the key length is to large
+     * @exception IllegalStateException when this node has been removed
+     */
+    public void putBoolean(String key, boolean value) {
+        put(key, String.valueOf(value));
+        // XXX - Use when using 1.4 compatible Boolean
+        // put(key, Boolean.toString(value));
+    }
+
+    /**
+     * Convenience method for setting the given entry as an array of bytes.
+     * The byte array is converted to a Base64 encoded string
+     * and then stored in the preference entry as that string.
+     * <p>
+     * Note that a byte array encoded as a Base64 string will be about 1.3
+     * times larger then the original length of the byte array, which means
+     * that the byte array may not be larger about 6 KB.
+     *
+     * @exception NullPointerException if either key or value are null
+     * @exception IllegalArgumentException if either key or value are to large
+     * @exception IllegalStateException when this node has been removed
+     */
+    public void putByteArray(String key, byte[] value) {
+        put(key, encode64(value));
+    }
+
+    /**
+     * Helper method for encoding an array of bytes as a Base64 String.
+     */
+    private static String encode64(byte[] b) {
+        StringBuffer sb = new StringBuffer((b.length/3)*4);
+
+        int i = 0;
+        int remaining = b.length;
+        char c[] = new char[4];
+        while (remaining > 0) {
+            // Three input bytes are encoded as four chars (6 bits) as
+            // 00000011 11112222 22333333
+
+            c[0] = (char) ((b[i] & 0xFC) >> 2);
+            c[1] = (char) ((b[i] & 0x03) << 4);
+            if (remaining >= 2) {
+                c[1] += (char) ((b[i+1] & 0xF0) >> 4);
+                c[2] = (char) ((b[i+1] & 0x0F) << 2);
+                if (remaining >= 3) {
+                    c[2] += (char) ((b[i+2] & 0xC0) >> 6);
+                    c[3] = (char) (b[i+2] & 0x3F);
+                } else {
+                    c[3] = 64;
+                }
+            } else {
+                c[2] = 64;
+                c[3] = 64;
+            }
+
+            // Convert to base64 chars
+            for(int j = 0; j < 4; j++) {
+                if (c[j] < 26) {
+                    c[j] += 'A';
+                } else if (c[j] < 52) {
+                    c[j] = (char) (c[j] - 26 + 'a');
+                } else if (c[j] < 62) {
+                    c[j] = (char) (c[j] - 52 + '0');
+                } else if (c[j] == 62) {
+                    c[j] = '+';
+                } else if (c[j] == 63) {
+                    c[j] = '/';
+                } else {
+                    c[j] = '=';
+                }
+            }
+
+            sb.append(c);
+            i += 3;
+            remaining -= 3;
+        }
+
+        return sb.toString();
+    }
+
+    /**
+     * Convenience method for setting the given entry as a double.
+     * The double is converted with <code>Double.toString(double)</code>
+     * and then stored in the preference entry as that string.
+     *
+     * @exception NullPointerException if the key is null
+     * @exception IllegalArgumentException if the key length is to large
+     * @exception IllegalStateException when this node has been removed
+     */
+    public void putDouble(String key, double value) {
+        put(key, Double.toString(value));
+    }
+
+    /**
+     * Convenience method for setting the given entry as a float.
+     * The float is converted with <code>Float.toString(float)</code>
+     * and then stored in the preference entry as that string.
+     *
+     * @exception NullPointerException if the key is null
+     * @exception IllegalArgumentException if the key length is to large
+     * @exception IllegalStateException when this node has been removed
+     */
+    public void putFloat(String key, float value) {
+        put(key, Float.toString(value));
+    }
+
+    /**
+     * Convenience method for setting the given entry as an integer.
+     * The integer is converted with <code>Integer.toString(int)</code>
+     * and then stored in the preference entry as that string.
+     *
+     * @exception NullPointerException if the key is null
+     * @exception IllegalArgumentException if the key length is to large
+     * @exception IllegalStateException when this node has been removed
+     */
+    public void putInt(String key, int value) {
+        put(key, Integer.toString(value));
+    }
+
+    /**
+     * Convenience method for setting the given entry as a long.
+     * The long is converted with <code>Long.toString(long)</code>
+     * and then stored in the preference entry as that string.
+     *
+     * @exception NullPointerException if the key is null
+     * @exception IllegalArgumentException if the key length is to large
+     * @exception IllegalStateException when this node has been removed
+     */
+    public void putLong(String key, long value) {
+        put(key, Long.toString(value));
+    }
+
+    /**
+     * Removes the preferences entry from this preferences node.
+     * <p>     
+     * The result will be immediatly visible in this VM, but may not be
+     * immediatly written to the backing store.
+     * <p>
+     * This implementation checks that the key is not larger then 80
+     * characters, gets the lock of this node, checks that the node has
+     * not been removed and calls <code>removeSpi</code> with the given key.
+     *
+     * @exception NullPointerException if the key is null
+     * @exception IllegalArgumentException if the key length is to large
+     * @exception IllegalStateException when this node has been removed
+     */
+    public void remove(String key) {
+        if (key.length() > MAX_KEY_LENGTH)
+            throw new IllegalArgumentException(key);
+
+        synchronized(lock) {
+            if (isRemoved())
+                throw new IllegalStateException("Node removed");
+
+            removeSpi(key);
+        }
+    }
+
+    /**
+     * Removes all entries from this preferences node. May need access to the
+     * backing store to get and clear all entries.
+     * <p>
+     * The result will be immediatly visible in this VM, but may not be
+     * immediatly written to the backing store.
+     * <p>
+     * This implementation locks this node, checks that the node has not been
+     * removed and calls <code>keys()</code> to get a complete array of keys
+     * for this node. For every key found <code>removeSpi()</code> is called.
+     *
+     * @exception BackingStoreException when the backing store cannot be
+     *            reached
+     * @exception IllegalStateException if this node has been removed
+     */
+    public void clear() throws BackingStoreException {
+        synchronized(lock) {
+            if (isRemoved())
+                throw new IllegalStateException("Node Removed");
+
+            String[] keys = keys();
+            for (int i = 0; i < keys.length; i++) {
+                removeSpi(keys[i]);
+            }
+        }
+    }
+
+    /**
+     * Writes all preference changes on this and any subnode that have not
+     * yet been written to the backing store. This has no effect on the
+     * preference entries in this VM, but it makes sure that all changes
+     * are visible to other programs (other VMs might need to call the
+     * <code>sync()</code> method to actually see the changes to the backing
+     * store.
+     * <p>
+     * Locks this node, calls the <code>flushSpi()</code> method, gets all
+     * the (cached - already existing in this VM) subnodes and then calls
+     * <code>flushSpi()</code> on every subnode with this node unlocked and
+     * only that particular subnode locked.
+     *
+     * @exception BackingStoreException when the backing store cannot be
+     *            reached
+     */
+    public void flush() throws BackingStoreException {
+        flushNode(false);
+    }
+
+    /**
+     * Writes and reads all preference changes to and from this and any
+     * subnodes. This makes sure that all local changes are written to the
+     * backing store and that all changes to the backing store are visible
+     * in this preference node (and all subnodes).
+     * <p>
+     * Checks that this node is not removed, locks this node, calls the
+     * <code>syncSpi()</code> method, gets all the subnodes and then calls
+     * <code>syncSpi()</code> on every subnode with this node unlocked and
+     * only that particular subnode locked.
+     *
+     * @exception BackingStoreException when the backing store cannot be
+     *            reached
+     * @exception IllegalStateException if this node has been removed
+     */
+    public void sync() throws BackingStoreException {
+        flushNode(true);
+    }
+    
+
+    /**
+     * Private helper method that locks this node and calls either
+     * <code>flushSpi()</code> if <code>sync</code> is false, or
+     * <code>flushSpi()</code> if <code>sync</code> is true. Then it gets all
+     * the currently cached subnodes. For every subnode it calls this method
+     * recursively with this node no longer locked.
+     * <p>
+     * Called by either <code>flush()</code> or <code>sync()</code>
+     */
+    private void flushNode(boolean sync) throws BackingStoreException {
+        String[] keys = null;
+        synchronized(lock) {
+            if (sync) {
+                syncSpi();
+            } else {
+                flushSpi();
+            }
+            keys = (String[]) childCache.keySet().toArray();
+        }
+
+        if (keys != null) {
+            for (int i = 0; i < keys.length; i++) {
+                // Have to lock this node again to access the childCache
+                AbstractPreferences subNode;
+                synchronized(this) {
+                    subNode = (AbstractPreferences) childCache.get(keys[i]);
+                }
+
+                // The child could already have been removed from the cache
+                if (subNode != null) {
+                    subNode.flushNode(sync);
+                }
+            }
+        }
+    }
+
+    /**
+     * Removes this and all subnodes from the backing store and clears all
+     * entries. After removal this instance will not be useable (except for
+     * a few methods that don't throw a <code>InvalidStateException</code>),
+     * even when a new node with the same path name is created this instance
+     * will not be usable again.
+     * <p>
+     * Checks that this is not a root node. If not it locks the parent node,
+     * then locks this node and checks that the node has not yet been removed.
+     * Then it makes sure that all subnodes of this node are in the child cache,
+     * by calling <code>childSpi()</code> on any children not yet in the cache.
+     * Then for all children it locks the subnode and removes it. After all
+     * subnodes have been purged the child cache is cleared, this nodes removed
+     * flag is set and any listeners are called. Finally this node is removed
+     * from the child cache of the parent node.
+     *
+     * @exception BackingStoreException when the backing store cannot be
+     *            reached
+     * @exception IllegalStateException if this node has already been removed
+     * @exception UnsupportedOperationException if this is a root node
+     */
+    public void removeNode() throws BackingStoreException {
+        // Check if it is a root node
+        if (parent == null)
+            throw new UnsupportedOperationException("Cannot remove root node");
+
+        synchronized(parent) {
+            synchronized(this) {
+                if (isRemoved())
+                    throw new IllegalStateException("Node Removed");
+
+                purge();
+            }
+            parent.childCache.remove(name);
+        }
+    }
+
+    /**
+     * Private helper method used to completely remove this node.
+     * Called by <code>removeNode</code> with the parent node and this node
+     * locked.
+     * <p>
+     * Makes sure that all subnodes of this node are in the child cache,
+     * by calling <code>childSpi()</code> on any children not yet in the
+     * cache. Then for all children it locks the subnode and calls this method
+     * on that node. After all subnodes have been purged the child cache is
+     * cleared, this nodes removed flag is set and any listeners are called.
+     */
+    private void purge() throws BackingStoreException
+    {
+        // Make sure all children have an AbstractPreferences node in cache
+        String children[] = childrenNamesSpi();
+        for (int i = 0; i < children.length; i++) {
+            if (childCache.get(children[i]) == null)
+                childCache.put(children[i], childSpi(children[i]));
+        }
+
+        // purge all children
+        Iterator i = childCache.values().iterator();
+        while (i.hasNext()) {
+            AbstractPreferences node = (AbstractPreferences) i.next();
+            synchronized(node) {
+                node.purge();
+            }
+        }
+
+        // Cache is empty now
+        childCache.clear();
+
+        // remove this node
+        removeNodeSpi();
+        removed = true;
+
+        // XXX - check for listeners
+    }
+
+    // listener methods
+
+    /**
+     * XXX
+     */
+    public void addNodeChangeListener(NodeChangeListener listener) {
+        // XXX
+    }
+
+    public void addPreferenceChangeListener(PreferenceChangeListener listener) {
+        // XXX
+    }
+
+    public void removeNodeChangeListener(NodeChangeListener listener) {
+        // XXX
+    }
+
+    public void removePreferenceChangeListener
+                            (PreferenceChangeListener listener)
+    {
+        // XXX
+    }
+
+    // abstract spi methods
+
+    /**
+     * Returns the names of the sub nodes of this preference node.
+     * This method only has to return any not yet cached child names,
+     * but may return all names if that is easier. It must not return
+     * null when there are no children, it has to return an empty array
+     * in that case. Since this method must consult the backing store to
+     * get all the sub node names it may throw a BackingStoreException.
+     * <p>
+     * Called by <code>childrenNames()</code> with this node locked.
+     */
+    protected abstract String[] childrenNamesSpi() throws BackingStoreException;
+
+    /**
+     * Returns a child note with the given name.
+     * This method is called by the <code>node()</code> method (indirectly
+     * through the <code>getNode()</code> helper method) with this node locked
+     * if a sub node with this name does not already exist in the child cache.
+     * If the child node did not aleady exist in the backing store the boolean
+     * field <code>newNode</code> of the returned node should be set.
+     * <p>
+     * Note that this method should even return a non-null child node if the
+     * backing store is not available since it may not throw a
+     * <code>BackingStoreException</code>.
+     */
+    protected abstract AbstractPreferences childSpi(String name);
+
+    /**
+     * Returns an (possibly empty) array with all the keys of the preference
+     * entries of this node.
+     * <p>
+     * Called by <code>keys()</code> with this node locked if this node has
+     * not been removed. May throw an exception when the backing store cannot
+     * be accessed.
+     *
+     * @exception BackingStoreException when the backing store cannot be     
+     *            reached
+     */
+    abstract protected String[] keysSpi() throws BackingStoreException;
+     
+    /**
+     * Returns the value associated with the key in this preferences node or
+     * null when the key does not exist in this preferences node.
+     * <p>
+     * Called by <code>key()</code> with this node locked after checking that
+     * key is valid, not null and that the node has not been removed.
+     * <code>key()</code> will catch any exceptions that this method throws.
+     */
+    abstract protected String getSpi(String key);
+
+    /**
+     * Sets the value of the given preferences entry for this node.
+     * The implementation is not required to propagate the change to the
+     * backing store immediatly. It may not throw an exception when it tries
+     * to write to the backing store and that operation fails, the failure
+     * should be registered so a later invocation of <code>flush()</code>
+     * or <code>sync()</code> can signal the failure.
+     * <p>
+     * Called by <code>put()</code> with this node locked after checking that
+     * key and value are valid and non-null.
+     */
+    abstract protected void putSpi(String key, String value);
+
+    /**
+     * Removes the given key entry from this preferences node.
+     * The implementation is not required to propagate the change to the
+     * backing store immediatly.  It may not throw an exception when it tries
+     * to write to the backing store and that operation fails, the failure
+     * should be registered so a later invocation of <code>flush()</code>
+     * or <code>sync()</code> can signal the failure.
+     * <p>
+     * Called by <code>remove()</code> with this node locked after checking
+     * that the key is valid and non-null.
+     */
+    abstract protected void removeSpi(String key);
+
+    /**
+     * Writes all entries of this preferences node that have not yet been
+     * written to the backing store and possibly creates this node in the
+     * backing store, if it does not yet exist. Should only write changes to
+     * this node and not write changes to any subnodes.
+     * Note that the node can be already removed in this VM. To check if
+     * that is the case the implementation can call <code>isRemoved()</code>.
+     * <p>
+     * Called (indirectly) by <code>flush()</code> with this node locked.
+     */
+    abstract protected void flushSpi() throws BackingStoreException;
+
+    /**
+     * Writes all entries of this preferences node that have not yet been
+     * written to the backing store and reads any entries that have changed
+     * in the backing store but that are not yet visible in this VM.
+     * Should only sync this node and not change any of the subnodes.
+     * Note that the node can be already removed in this VM. To check if
+     * that is the case the implementation can call <code>isRemoved()</code>.
+     * <p>
+     * Called (indirectly) by <code>sync()</code> with this node locked.
+     */
+    abstract protected void syncSpi() throws BackingStoreException;
+
+    /**
+     * Clears this node from this VM and removes it from the backing store.
+     * After this method has been called the node is marked as removed.
+     * <p>
+     * Called (indirectly) by <code>removeNode()</code> with this node locked
+     * after all the sub nodes of this node have already been removed.
+     */
+    abstract protected void removeNodeSpi() throws BackingStoreException;
+}
--- /home/mkoch/src/gcc-cvs/libjava/java/util/prefs/BackingStoreException.java	1970-01-01 01:00:00.000000000 +0100
+++ /home/mkoch/src/gcc-work/libjava/java/util/prefs/BackingStoreException.java	2002-10-02 14:58:40.000000000 +0200
@@ -0,0 +1,104 @@
+/* BackingStoreException.java - chained exception thrown when backing store
+   fails
+   Copyright (C) 2001, 2002 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+package java.util.prefs;
+
+import java.io.ObjectOutputStream;
+import java.io.ObjectInputStream;
+import java.io.NotSerializableException;
+
+/**
+ * Chained exception thrown when backing store fails. This exception is
+ * only thrown from methods that actually have to access the backing store,
+ * such as <code>clear(), keys(), childrenNames(), nodeExists(), removeNode(),
+ * flush(), sync(), exportNode(), exportSubTree()</code>; normal operations
+ * do not throw BackingStoreExceptions.
+ *
+ * <p>Note that although this class inherits the Serializable interface, an
+ * attempt to serialize will fail with a <code>NotSerializableException</code>.
+ *
+ * @author Mark Wielaard <mark@klomp.org>
+ * @since 1.4
+ * @status updated to 1.4
+ */
+public class BackingStoreException extends Exception
+{
+  static final long serialVersionUID = 859796500401108469L;
+
+  /**
+   * Creates a new exception with a descriptive message.
+   *
+   * @param message the message
+   */
+  public BackingStoreException(String message)
+  {
+    super(message);
+  }
+
+  /**
+   * Create a new exception with the given cause.
+   *
+   * @param cause the cause
+   */
+  public BackingStoreException(Throwable cause)
+  {
+    super(cause);
+  }
+
+  /**
+   * This class should not be serialized.
+   *
+   * @param o the output stream
+   */
+  private void writeObject(ObjectOutputStream o) throws NotSerializableException
+  {
+    throw new NotSerializableException
+      ("java.util.prefs.BackingStoreException");
+  }
+
+  /**
+   * This class should not be serialized.
+   *
+   * @param i the input stream
+   */
+  private void readObject(ObjectInputStream i) throws NotSerializableException
+  {
+    throw new NotSerializableException
+      ("java.util.prefs.BackingStoreException");
+  }
+}
--- /home/mkoch/src/gcc-cvs/libjava/java/util/prefs/InvalidPreferencesFormatException.java	1970-01-01 01:00:00.000000000 +0100
+++ /home/mkoch/src/gcc-work/libjava/java/util/prefs/InvalidPreferencesFormatException.java	2002-10-02 14:58:40.000000000 +0200
@@ -0,0 +1,115 @@
+/* InvalidPreferencesFormatException - indicates reading prefs from stream
+   failed
+   Copyright (C) 2001, 2002 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+package java.util.prefs;
+
+import java.io.ObjectOutputStream;
+import java.io.ObjectInputStream;
+import java.io.NotSerializableException;
+
+/**
+ * Indicates reading prefs from stream failed. Thrown by the
+ * <code>importPreferences()</code> method when the supplied input stream
+ * could not be read because it was not in the correct XML format.
+ *
+ * <p>Note that although this class inherits the Serializable interface, an
+ * attempt to serialize will fail with a <code>NotSerializableException</code>.
+ *
+ * @author Mark Wielaard <mark@klomp.org>
+ * @see Preferences
+ * @since 1.4
+ * @status updated to 1.4
+ */
+public class InvalidPreferencesFormatException extends Exception
+{
+  static final long serialVersionUID = -791715184232119669L;
+
+  /**
+   * Creates a new exception with a descriptive message. The cause remains
+   * uninitialized.
+   *
+   * @param message the message
+   */
+  public InvalidPreferencesFormatException(String message)
+  {
+    super(message);
+  }
+
+  /**
+   * Creates a new exception with the given cause.
+   *
+   * @param cause the cause
+   */
+  public InvalidPreferencesFormatException(Throwable cause)
+  {
+    super(cause);
+  }
+
+  /**
+   * Creates a new exception with a descriptive message and a cause.
+   *
+   * @param message the message
+   * @param cause the cause
+   */
+  public InvalidPreferencesFormatException(String message, Throwable cause)
+  {
+    super(message, cause);
+  }
+
+  /**
+   * This class should not be serialized.
+   *
+   * @param o the output stream
+   */
+  private void writeObject(ObjectOutputStream o) throws NotSerializableException
+  {
+    throw new NotSerializableException
+      ("java.util.prefs.InvalidPreferencesFormatException");
+  }
+
+  /**
+   * This class should not be serialized.
+   *
+   * @param i the input stream
+   */
+  private void readObject(ObjectInputStream i) throws NotSerializableException
+  {
+    throw new NotSerializableException
+      ("java.util.prefs.InvalidPreferencesFormatException");
+  }
+}
--- /home/mkoch/src/gcc-cvs/libjava/java/util/prefs/NodeChangeEvent.java	1970-01-01 01:00:00.000000000 +0100
+++ /home/mkoch/src/gcc-work/libjava/java/util/prefs/NodeChangeEvent.java	2003-01-17 06:56:11.000000000 +0100
@@ -0,0 +1,91 @@
+/* NodeChangeEvent - ObjectEvent fired when a Preference node is added/removed
+   Copyright (C) 2001 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+ 
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+package java.util.prefs;
+
+import java.util.EventObject;
+
+/**
+ * ObjectEvent fired when a Preference node is added/removed.
+ * This event is only generated when a new subnode is added or a subnode is
+ * removed from a preference node. Changes in the entries of a preference node
+ * are indicated with a <code>PreferenceChangeEvent</code>.
+ *
+ * @since 1.4
+ * @author Mark Wielaard (mark@klomp.org)
+ */
+public class NodeChangeEvent extends EventObject {
+
+  private static final long serialVersionUID =8068949086596572957L; 
+  
+    /**
+     * The sub node that was added or removed.
+     * Defined transient just like <code>EventObject.source</code> since
+     * this object should be serializable, but Preferences is in general not
+     * serializable.
+     */
+    private final transient Preferences child;
+
+    /**
+     * Creates a new NodeChangeEvent.
+     *
+     * @param parentNode The source preference node from which a subnode was
+     * added or removed
+     * @param childNode The preference node that was added or removed
+     */
+    public NodeChangeEvent(Preferences parentNode, Preferences childNode) {
+        super(parentNode);
+        child = childNode;
+    }
+
+    /**
+     * Returns the source parent preference node from which a subnode was
+     * added or removed.
+     */
+    public Preferences getParent() {
+        return (Preferences) source;
+    }
+
+    /**
+     * Returns the child preference subnode that was added or removed.
+     * To see wether it is still a valid preference node one has to call
+     * <code>event.getChild().nodeExists("")</code>.
+     */
+    public Preferences getChild() {
+        return child;
+    }
+}
--- /home/mkoch/src/gcc-cvs/libjava/java/util/prefs/NodeChangeListener.java	1970-01-01 01:00:00.000000000 +0100
+++ /home/mkoch/src/gcc-work/libjava/java/util/prefs/NodeChangeListener.java	2002-01-22 23:27:02.000000000 +0100
@@ -0,0 +1,64 @@
+/* NodeChangeListener - EventListener for Preferences node addition/removal
+   Copyright (C) 2001 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+ 
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+package java.util.prefs;
+
+import java.util.EventListener;
+
+/**
+ * EventListener for Preferences node addition/removal.
+ * <p>
+ * Note that these events are only generated for the addition and removal
+ * of sub nodes from the preference node. Entry changes in the preference
+ * node can be monitored with a <code>PreferenceChangeListener</code>.
+ *
+ * @since 1.4
+ * @author Mark Wielaard (mark@klomp.org)
+ */
+public interface NodeChangeListener extends EventListener {
+
+    /**
+     * Fired when a sub node is added to the preference node.
+     */
+    void childAdded(NodeChangeEvent event);
+
+    /**
+     * Fired when a sub node is removed from the preference node.
+     */
+    void childRemoved(NodeChangeEvent event);
+
+}
--- /home/mkoch/src/gcc-cvs/libjava/java/util/prefs/PreferenceChangeEvent.java	1970-01-01 01:00:00.000000000 +0100
+++ /home/mkoch/src/gcc-work/libjava/java/util/prefs/PreferenceChangeEvent.java	2003-01-17 06:56:54.000000000 +0100
@@ -0,0 +1,105 @@
+/* PreferenceChangeEvent - ObjectEvent fired when a Preferences entry changes
+   Copyright (C) 2001 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+ 
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+package java.util.prefs;
+
+import java.util.EventObject;
+
+/**
+ * ObjectEvent fired when a Preferences entry changes.
+ * This event is generated when a entry is added, changed or removed.
+ * When an entry is removed then <code>getNewValue</code> will return null.
+ * <p>
+ * Preference change events are only generated for entries in one particular
+ * preference node. Notification of subnode addition/removal is given by a
+ * <code>NodeChangeEvent</code>.
+ *
+ * @since 1.4
+ * @author Mark Wielaard (mark@klomp.org)
+ */
+public class PreferenceChangeEvent extends EventObject {
+
+  private static final long serialVersionUID = 793724513368024975L;
+  
+    /**
+     * The key of the changed entry.
+     */
+    private final String key;
+
+    /**
+     * The new value of the changed entry, or null when the entry was removed.
+     */
+    private final String newValue;
+
+    /**
+     * Creates a new PreferenceChangeEvent.
+     *
+     * @param node The source preference node for which an entry was added,
+     * changed or removed
+     * @param key The key of the entry that was added, changed or removed
+     * @param value The new value of the entry that was added or changed, or
+     * null when the entry was removed
+     */
+    public PreferenceChangeEvent(Preferences node, String key, String value) {
+        super(node);
+        this.key = key;
+        this.newValue = value;
+    }
+
+    /**
+     * Returns the source Preference node from which an entry was added,
+     * changed or removed.
+     */
+    public Preferences getNode() {
+        return (Preferences) source;
+    }
+
+    /**
+     * Returns the key of the entry that was added, changed or removed.
+     */
+    public String getKey() {
+        return key;
+    }
+
+    /**
+     * Returns the new value of the entry that was added or changed, or
+     * returns null when the entry was removed.
+     */
+    public String getNewValue() {
+        return newValue;
+    }
+}
--- /home/mkoch/src/gcc-cvs/libjava/java/util/prefs/PreferenceChangeListener.java	1970-01-01 01:00:00.000000000 +0100
+++ /home/mkoch/src/gcc-work/libjava/java/util/prefs/PreferenceChangeListener.java	2003-01-10 09:00:33.000000000 +0100
@@ -0,0 +1,60 @@
+/* PreferenceChangeListener - EventListener for Preferences entry changes
+   Copyright (C) 2001 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+ 
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+package java.util.prefs;
+
+import java.util.EventListener;
+
+/**
+ * EventListener for Preferences entry addition, change or removal.
+ * <p>
+ * Preference change events are only generated for entries in one particular
+ * preference node. Notification of subnode addition/removal can be monitored
+ * with a <code>NodeChangeListener</code>.
+ *
+ * @since 1.4
+ * @author Mark Wielaard (mark@klomp.org)
+ */
+public interface PreferenceChangeListener extends EventListener {
+
+    /**
+     * Fired when a entry has been added, changed or removed from the
+     * preference node.
+     */
+    void preferenceChange(PreferenceChangeEvent event);
+
+}
--- /home/mkoch/src/gcc-cvs/libjava/java/util/prefs/Preferences.java	1970-01-01 01:00:00.000000000 +0100
+++ /home/mkoch/src/gcc-work/libjava/java/util/prefs/Preferences.java	2002-05-06 18:19:20.000000000 +0200
@@ -0,0 +1,665 @@
+/* Preferences - Preference node containing key value entries and subnodes
+   Copyright (C) 2001 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+ 
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+package java.util.prefs;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.IOException;
+
+import java.security.AccessController;
+import java.security.Permission;
+import java.security.PrivilegedAction;
+
+import gnu.java.util.prefs.*;
+
+/**
+ * Preference node containing key value entries and subnodes.
+ * <p>
+ * There are two preference node trees, a system tree which can be accessed
+ * by calling <code>systemRoot()</code> containing system preferences usefull
+ * for all users, and a user tree that can be accessed by calling
+ * <code>userRoot()</code> containing preferences that can differ between
+ * different users. How different users are identified is implementation
+ * depended. It can be determined by Thread, Access Control Context or Subject.
+ * <p>
+ * This implementation uses the "java.util.prefs.PreferencesFactory" system
+ * property to find a class that implement <code>PreferencesFactory</code>
+ * and initialized that class (if it has a public no arguments contructor)
+ * to get at the actual system or user root. If the system property is not set,
+ * or the class cannot be initialized it uses the default implementation
+ * <code>gnu.java.util.prefs.FileBasedFactory</code>.
+ * <p>
+ * Besides the two static method above to get the roots of the system and user
+ * preference node trees there are also two convenience methods to access the
+ * default preference node for a particular package an object is in. These are
+ * <code>userNodeForPackage()</code> and <code>systemNodeForPackage()</code>.
+ * Both methods take an Object as an argument so accessing preferences values
+ * can be as easy as calling <code>Preferences.userNodeForPackage(this)</code>.
+ * <p>
+ * Note that if a security manager is installed all static methods check for
+ * <code>RuntimePermission("preferences")</code>. But if this permission is
+ * given to the code then it can access and change all (user) preference nodes
+ * and entries. So you should be carefull not to store to sensitive information
+ * or make security decissions based on preference values since there is no
+ * more fine grained control over what preference values can be changed once
+ * code has been given the correct runtime permission.
+ * <p>
+ * XXX
+ *
+ * @since 1.4
+ * @author Mark Wielaard (mark@klomp.org)
+ */
+public abstract class Preferences {
+
+    // Static Fields
+
+    /**
+     * Default PreferencesFactory class used when the system property
+     * "java.util.prefs.PreferencesFactory" is not set.
+	 * <p>
+	 * XXX - Currently set to MemoryBasedPreferencesFactory, should be changed
+	 * when FileBasedPreferences backend works.
+     */
+    private static final String defaultFactoryClass
+        = "gnu.java.util.prefs.MemoryBasedPreferencesFactory";
+
+    /** Permission needed to access system or user root. */
+    private static final Permission prefsPermission
+        = new RuntimePermission("preferences");
+
+    /**
+     * The preferences factory object that supplies the system and user root.
+     * Set and returned by the getFactory() method.
+     */
+    private static PreferencesFactory factory;
+
+    /** Maximum node name length. 80 characters. */
+    public static final int MAX_NAME_LENGTH = 80;
+
+    /** Maximum entry key length. 80 characters. */
+    public static final int MAX_KEY_LENGTH = 80;
+
+    /** Maximum entry value length. 8192 characters. */
+    public static final int MAX_VALUE_LENGTH = 8192;
+
+    // Constructors
+
+    /**
+     * Creates a new Preferences node. Can only be used by subclasses.
+     * Empty implementation.
+     */
+    protected Preferences() {}
+
+    // Static methods
+
+    /**
+     * Returns the system preferences root node containing usefull preferences
+     * for all users. It is save to cache this value since it should always
+     * return the same preference node.
+     *
+     * @return the root system preference node
+     * @exception SecurityException when a security manager is installed and
+     * the caller does not have <code>RuntimePermission("preferences")</code>.
+     */
+    public static Preferences systemRoot() throws SecurityException {
+        // Get the preferences factory and check for permission
+        PreferencesFactory factory = getFactory();
+
+        return factory.systemRoot();
+    }
+
+    /**
+     * Returns the user preferences root node containing preferences for the
+     * the current user. How different users are identified is implementation
+     * depended. It can be determined by Thread, Access Control Context or
+     * Subject.
+     *
+     * @return the root user preference node
+     * @exception SecurityException when a security manager is installed and
+     * the caller does not have <code>RuntimePermission("preferences")</code>.
+     */
+    public static Preferences userRoot() throws SecurityException {
+        // Get the preferences factory and check for permission
+        PreferencesFactory factory = getFactory();
+        return factory.userRoot();
+    }
+
+    /**
+     * Private helper method for <code>systemRoot()</code> and
+     * <code>userRoot()</code>. Checks security permission and instantiates the
+     * correct factory if it has not yet been set.
+     * <p>
+     * When the preferences factory has not yet been set this method first
+     * tries to get the system propery "java.util.prefs.PreferencesFactory"
+     * and tries to initializes that class. If the system property is not set
+     * or initialization fails it returns an instance of the default factory
+     * <code>gnu.java.util.prefs.FileBasedPreferencesFactory</code>.
+     *
+     * @return the preferences factory to use
+     * @exception SecurityException when a security manager is installed and
+     * the caller does not have <code>RuntimePermission("preferences")</code>.
+     */
+    private static PreferencesFactory getFactory() throws SecurityException {
+
+        // First check for permission
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            sm.checkPermission(prefsPermission);
+        }
+
+        // Get the factory
+        if (factory == null) {
+            // Caller might not have enough permissions
+            factory = (PreferencesFactory) AccessController.doPrivileged(
+                        new PrivilegedAction() {
+                            public Object run() {
+                                PreferencesFactory pf = null;
+                                String className = System.getProperty
+                                    ("java.util.prefs.PreferencesFactory");
+                                if (className != null) {
+                                    try {
+                                        Class fc = Class.forName(className);
+                                        Object o = fc.newInstance();
+                                        pf = (PreferencesFactory) o;
+                                    } catch (ClassNotFoundException cnfe)
+                                        {/*ignore*/}
+                                    catch (InstantiationException ie)
+                                        {/*ignore*/}
+                                    catch (IllegalAccessException iae)
+                                        {/*ignore*/}
+                                    catch (ClassCastException cce)
+                                        {/*ignore*/}
+                                }
+                                return pf;
+                            }
+                        });
+
+            // Still no factory? Use our default.
+            if (factory == null) {
+                try {
+                    Object o = Class.forName(defaultFactoryClass);
+                    factory = (PreferencesFactory) o;
+                } catch (ClassNotFoundException cnfe) {
+                    throw new RuntimeException("Couldn't load default factory"
+                        + " '"+ defaultFactoryClass +"'");
+                    // XXX - when using 1.4 compatible throwables add cause
+                }
+            }
+
+        }
+        return factory;
+    }
+
+    /**
+     * Returns the system preferences node for the package of an object.
+     * The package node name of the object is determined by dropping the
+     * class name of the object of the fully quallified class name and
+     * replacing all '.' to '/' in the package name. If the class of the
+     * object has no package then the package node name is "<unnamed>".
+     * The returened node is <code>systemRoot().node(packageNodeName)</code>.
+     *
+     * @param o Object whose default system preference node is requested
+     * @returns system preferences node that should be used by object o
+     * @exception SecurityException when a security manager is installed and
+     * the caller does not have <code>RuntimePermission("preferences")</code>.
+     */
+    public static Preferences systemNodeForPackage(Object o)
+            throws SecurityException
+    {
+        return nodeForPackage(o, systemRoot());
+    }
+
+    /**
+     * Returns the user preferences node for the package of an object.
+     * The package node name of the object is determined by dropping the
+     * class name of the object of the fully quallified class name and
+     * replacing all '.' to '/' in the package name. If the class of the
+     * object has no package then the package node name is "<unnamed>".
+     * The returened node is <code>userRoot().node(packageNodeName)</code>.
+     *
+     * @param o Object whose default user preference node is requested
+     * @returns user preferences node that should be used by object o
+     * @exception SecurityException when a security manager is installed and
+     * the caller does not have <code>RuntimePermission("preferences")</code>.
+     */
+    public static Preferences userNodeForPackage(Object o)
+            throws SecurityException
+    {
+        return nodeForPackage(o, userRoot());
+    }
+
+    /**
+     * Private helper method for <code>systemNodeForPackage()</code> and
+     * <code>userNodeForPackage()</code>. Given the correct system or user
+     * root it returns the correct Preference node for the package node name
+     * of the given object.
+     */
+    private static Preferences nodeForPackage(Object o, Preferences root) {
+        // Get the package path
+        String className = o.getClass().getName();
+        String packagePath;
+        int index = className.lastIndexOf('.');
+        if(index == -1) {
+            packagePath = "<unnamed>";
+        } else {
+            packagePath = className.substring(0,index).replace('.','/');
+        }
+
+        return root.node(packagePath);
+    }
+
+    /**
+     * XXX
+     */
+    public static void importPreferences(InputStream is) 
+                                    throws InvalidPreferencesFormatException,
+                                           IOException
+    {
+        PreferencesFactory factory = getFactory();
+        NodeReader reader = new NodeReader(is, factory);
+        reader.importPreferences();
+    }
+
+    // abstract methods (identification)
+
+    /**
+     * Returns the absolute path name of this preference node.
+     * The absolute path name of a node is the path name of its parent node 
+     * plus a '/' plus its own name. If the node is the root node and has no
+     * parent then its name is "" and its absolute path name is "/".
+     */
+    abstract public String absolutePath();
+
+    /**
+     * Returns true if this node comes from the user preferences tree, false
+     * if it comes from the system preferences tree.
+     */
+    abstract public boolean isUserNode();
+
+    /**
+     * Returns the name of this preferences node. The name of the node cannot
+     * be null, can be mostly 80 characters and cannot contain any '/'
+     * characters. The root node has as name "".
+     */
+    abstract public String name();
+
+    /**
+     * Returns the String given by
+     * <code>
+     * (isUserNode() ? "User":"System") + " Preference Node: " + absolutePath()
+     * </code>
+     */
+    abstract public String toString();
+
+    // abstract methods (navigation)
+
+    /**
+     * Returns all the direct sub nodes of this preferences node.
+     * Needs access to the backing store to give a meaningfull answer.
+     *
+     * @exception BackingStoreException when the backing store cannot be
+     *            reached
+     * @exception IllegalStateException when this node has been removed
+     */
+    abstract public String[] childrenNames() throws BackingStoreException;
+
+    /**
+     * Returns a sub node of this preferences node if the given path is
+     * relative (does not start with a '/') or a sub node of the root
+     * if the path is absolute (does start with a '/').
+     *
+     * @exception IllegalStateException if this node has been removed
+     * @exception IllegalArgumentException if the path contains two or more
+     * consecutive '/' characters, ends with a '/' charactor and is not the
+     * string "/" (indicating the root node) or any name on the path is more
+     * then 80 characters long
+     */
+    abstract public Preferences node(String path);
+
+    /**
+     * Returns true if the node that the path points to exists in memory or
+     * in the backing store. Otherwise it returns false or an exception is
+     * thrown. When this node is removed the only valid parameter is the
+     * empty string (indicating this node), the return value in that case
+     * will be false.
+     *
+     * @exception BackingStoreException when the backing store cannot be
+     *            reached
+     * @exception IllegalStateException if this node has been removed
+     *            and the path is not the empty string (indicating this node)
+     * @exception IllegalArgumentException if the path contains two or more
+     * consecutive '/' characters, ends with a '/' charactor and is not the
+     * string "/" (indicating the root node) or any name on the path is more
+     * then 80 characters long
+     */
+    abstract public boolean nodeExists(String path)
+                                throws BackingStoreException;
+
+    /**
+     * Returns the parent preferences node of this node or null if this is
+     * the root of the preferences tree.
+     *
+     * @exception IllegalStateException if this node has been removed
+     */
+    abstract public Preferences parent();
+
+    // abstract methods (export)
+
+    /**
+     * XXX
+     */
+    abstract public void exportNode(OutputStream os)
+                                throws BackingStoreException,
+                                       IOException;
+
+    /**
+     * XXX
+     */
+    abstract public void exportSubtree(OutputStream os)
+                                throws BackingStoreException,
+                                       IOException;
+
+    // abstract methods (preference entry manipulation)
+
+    /**
+     * Returns an (possibly empty) array with all the keys of the preference
+     * entries of this node.
+     *
+     * @exception BackingStoreException when the backing store cannot be
+     *            reached
+     * @exception IllegalStateException if this node has been removed
+     */
+    abstract public String[] keys() throws BackingStoreException;
+
+    /**
+     * Returns the value associated with the key in this preferences node. If
+     * the default value of the key cannot be found in the preferences node
+     * entries or something goes wrong with the backing store the supplied
+     * default value is returned.
+     *
+     * @exception IllegalArgumentException if key is larger then 80 characters
+     * @exception IllegalStateException if this node has been removed
+     * @exception NullPointerException if key is null
+     */
+    abstract public String get(String key, String defaultVal);
+
+    /**
+     * Convenience method for getting the given entry as a boolean.
+     * When the string representation of the requested entry is either
+     * "true" or "false" (ignoring case) then that value is returned,
+     * otherwise the given default boolean value is returned.
+     *
+     * @exception IllegalArgumentException if key is larger then 80 characters
+     * @exception IllegalStateException if this node has been removed
+     * @exception NullPointerException if key is null
+     */
+    abstract public boolean getBoolean(String key, boolean defaultVal);
+
+    /**
+     * Convenience method for getting the given entry as a byte array.
+     * When the string representation of the requested entry is a valid
+     * Base64 encoded string (without any other characters, such as newlines)
+     * then the decoded Base64 string is returned as byte array,
+     * otherwise the given default byte array value is returned.
+     *
+     * @exception IllegalArgumentException if key is larger then 80 characters
+     * @exception IllegalStateException if this node has been removed
+     * @exception NullPointerException if key is null
+     */
+    abstract public byte[] getByteArray(String key, byte[] defaultVal);
+
+    /**
+     * Convenience method for getting the given entry as a double.
+     * When the string representation of the requested entry can be decoded
+     * with <code>Double.parseDouble()</code> then that double is returned,
+     * otherwise the given default double value is returned.
+     *
+     * @exception IllegalArgumentException if key is larger then 80 characters
+     * @exception IllegalStateException if this node has been removed
+     * @exception NullPointerException if key is null
+     */
+    abstract public double getDouble(String key, double defaultVal);
+
+    /**
+     * Convenience method for getting the given entry as a float.
+     * When the string representation of the requested entry can be decoded
+     * with <code>Float.parseFloat()</code> then that float is returned,
+     * otherwise the given default float value is returned.
+     *
+     * @exception IllegalArgumentException if key is larger then 80 characters
+     * @exception IllegalStateException if this node has been removed
+     * @exception NullPointerException if key is null
+     */
+    abstract public float getFloat(String key, float defaultVal);
+
+    /**
+     * Convenience method for getting the given entry as an integer.
+     * When the string representation of the requested entry can be decoded
+     * with <code>Integer.parseInt()</code> then that integer is returned,
+     * otherwise the given default integer value is returned.
+     *
+     * @exception IllegalArgumentException if key is larger then 80 characters
+     * @exception IllegalStateException if this node has been removed
+     * @exception NullPointerException if key is null
+     */
+    abstract public int getInt(String key, int defaultVal);
+
+    /**
+     * Convenience method for getting the given entry as a long.
+     * When the string representation of the requested entry can be decoded
+     * with <code>Long.parseLong()</code> then that long is returned,
+     * otherwise the given default long value is returned.
+     *
+     * @exception IllegalArgumentException if key is larger then 80 characters
+     * @exception IllegalStateException if this node has been removed
+     * @exception NullPointerException if key is null
+     */
+    abstract public long getLong(String key, long defaultVal);
+
+    /**
+     * Sets the value of the given preferences entry for this node.
+     * Key and value cannot be null, the key cannot exceed 80 characters
+     * and the value cannot exceed 8192 characters.
+     * <p>
+     * The result will be immediatly visible in this VM, but may not be
+     * immediatly written to the backing store.
+     *
+     * @exception NullPointerException if either key or value are null
+     * @exception IllegalArgumentException if either key or value are to large
+     * @exception IllegalStateException when this node has been removed
+     */
+    abstract public void put(String key, String value);
+
+    /**
+     * Convenience method for setting the given entry as a boolean.
+     * The boolean is converted with <code>Boolean.toString(value)</code>
+     * and then stored in the preference entry as that string.
+     *
+     * @exception NullPointerException if key is null
+     * @exception IllegalArgumentException if the key length is to large
+     * @exception IllegalStateException when this node has been removed
+     */
+    abstract public void putBoolean(String key, boolean value);
+
+    /**
+     * Convenience method for setting the given entry as an array of bytes.
+     * The byte array is converted to a Base64 encoded string
+     * and then stored in the preference entry as that string.
+     * <p>
+     * Note that a byte array encoded as a Base64 string will be about 1.3
+     * times larger then the original length of the byte array, which means
+     * that the byte array may not be larger about 6 KB.
+     *
+     * @exception NullPointerException if either key or value are null
+     * @exception IllegalArgumentException if either key or value are to large
+     * @exception IllegalStateException when this node has been removed
+     */
+    abstract public void putByteArray(String key, byte[] value);
+
+    /**
+     * Convenience method for setting the given entry as a double.
+     * The double is converted with <code>Double.toString(double)</code>
+     * and then stored in the preference entry as that string.
+     *
+     * @exception NullPointerException if the key is null
+     * @exception IllegalArgumentException if the key length is to large
+     * @exception IllegalStateException when this node has been removed
+     */
+    abstract public void putDouble(String key, double value);
+
+    /**
+     * Convenience method for setting the given entry as a float.
+     * The float is converted with <code>Float.toString(float)</code>
+     * and then stored in the preference entry as that string.
+     *
+     * @exception NullPointerException if the key is null
+     * @exception IllegalArgumentException if the key length is to large
+     * @exception IllegalStateException when this node has been removed
+     */
+    abstract public void putFloat(String key, float value);
+
+    /**
+     * Convenience method for setting the given entry as an integer.
+     * The integer is converted with <code>Integer.toString(int)</code>
+     * and then stored in the preference entry as that string.
+     *
+     * @exception NullPointerException if the key is null
+     * @exception IllegalArgumentException if the key length is to large
+     * @exception IllegalStateException when this node has been removed
+     */
+    abstract public void putInt(String key, int value);
+
+    /**
+     * Convenience method for setting the given entry as a long.
+     * The long is converted with <code>Long.toString(long)</code>
+     * and then stored in the preference entry as that string.
+     *
+     * @exception NullPointerException if the key is null
+     * @exception IllegalArgumentException if the key length is to large
+     * @exception IllegalStateException when this node has been removed
+     */
+    abstract public void putLong(String key, long value);
+
+    /**
+     * Removes the preferences entry from this preferences node.
+     * <p>
+     * The result will be immediatly visible in this VM, but may not be
+     * immediatly written to the backing store.
+     *
+     * @exception NullPointerException if the key is null
+     * @exception IllegalArgumentException if the key length is to large
+     * @exception IllegalStateException when this node has been removed
+     */
+    abstract public void remove(String key);
+
+    // abstract methods (preference node manipulation)
+
+    /**
+     * Removes all entries from this preferences node. May need access to the
+     * backing store to get and clear all entries.
+     * <p>
+     * The result will be immediatly visible in this VM, but may not be
+     * immediatly written to the backing store.
+     *
+     * @exception BackingStoreException when the backing store cannot be
+     *            reached
+     * @exception IllegalStateException if this node has been removed
+     */
+    abstract public void clear() throws BackingStoreException;
+
+    /**
+     * Writes all preference changes on this and any subnode that have not
+     * yet been written to the backing store. This has no effect on the
+     * preference entries in this VM, but it makes sure that all changes
+     * are visible to other programs (other VMs might need to call the
+     * <code>sync()</code> method to actually see the changes to the backing
+     * store.
+     *
+     * @exception BackingStoreException when the backing store cannot be
+     *            reached
+     * @exception IllegalStateException if this node has been removed
+     */
+    abstract public void flush() throws BackingStoreException;
+
+    /**
+     * Writes and reads all preference changes to and from this and any
+     * subnodes. This makes sure that all local changes are written to the
+     * backing store and that all changes to the backing store are visible
+     * in this preference node (and all subnodes).
+     *
+     * @exception BackingStoreException when the backing store cannot be
+     *            reached
+     * @exception IllegalStateException if this node has been removed
+     */
+    abstract public void sync() throws BackingStoreException;
+
+    /**
+     * Removes this and all subnodes from the backing store and clears all
+     * entries. After removal this instance will not be useable (except for
+     * a few methods that don't throw a <code>InvalidStateException</code>),
+     * even when a new node with the same path name is created this instance
+     * will not be usable again. The root (system or user) may never be removed.
+     * <p>
+     * Note that according to the specification an implementation may delay
+     * removal of the node from the backing store till the <code>flush()</code>
+     * method is called. But the <code>flush()</code> method may throw a 
+     * <code>IllegalStateException</code> when the node has been removed.
+     * So most implementations will actually remove the node and any subnodes
+     * from the backing store immediatly.
+     *
+     * @exception BackingStoreException when the backing store cannot be
+     *            reached
+     * @exception IllegalStateException if this node has already been removed
+     * @exception UnsupportedOperationException if this is a root node
+     */
+    abstract public void removeNode() throws BackingStoreException;
+
+    // abstract methods (listeners)
+
+    abstract public void addNodeChangeListener(NodeChangeListener listener);
+
+    abstract public void addPreferenceChangeListener
+                            (PreferenceChangeListener listener);
+
+    abstract public void removeNodeChangeListener(NodeChangeListener listener);
+
+    abstract public void removePreferenceChangeListener
+                            (PreferenceChangeListener listener);
+
+}
+
--- /home/mkoch/src/gcc-cvs/libjava/java/util/prefs/PreferencesFactory.java	1970-01-01 01:00:00.000000000 +0100
+++ /home/mkoch/src/gcc-work/libjava/java/util/prefs/PreferencesFactory.java	2002-01-22 23:27:02.000000000 +0100
@@ -0,0 +1,66 @@
+/* PreferencesFactory - Preferences system and user root factory interface
+   Copyright (C) 2001 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+ 
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+package java.util.prefs;
+
+import java.util.EventListener;
+
+/**
+ * Preferences system and user root factory interface. Defines how to get
+ * to the system and user root preferences objects. Should be implemented by
+ * new preferences backends.
+ *
+ * @since 1.4
+ * @author Mark Wielaard (mark@klomp.org)
+ */
+public interface PreferencesFactory {
+
+    /**
+     * Returns the system root preferences node. Should always return the
+     * same object.
+     */
+    Preferences systemRoot();
+
+    /**
+     * Returns the user root preferences node. May return different objects
+     * depending on the user that called this method. The user may for example
+     * be determined by the current Thread or the Subject associated with the
+     * current AccessControllContext.
+     */
+    Preferences userRoot();
+
+}
--- /home/mkoch/src/gcc-cvs/libjava/Makefile.in	2003-02-12 11:16:33.000000000 +0100
+++ /home/mkoch/src/gcc-work/libjava/Makefile.in	2003-02-12 11:25:04.000000000 +0100
@@ -1620,6 +1620,15 @@
 java/util/TooManyListenersException.java \
 java/util/Vector.java \
 java/util/WeakHashMap.java \
+java/util/prefs/NodeChangeListener.java \
+java/util/prefs/Preferences.java \
+java/util/prefs/PreferenceChangeListener.java \
+java/util/prefs/NodeChangeEvent.java \
+java/util/prefs/InvalidPreferencesFormatException.java \
+java/util/prefs/AbstractPreferences.java \
+java/util/prefs/BackingStoreException.java \
+java/util/prefs/PreferenceChangeEvent.java \
+java/util/prefs/PreferencesFactory.java \
 java/util/regex/Matcher.java \
 java/util/regex/Pattern.java \
 java/util/regex/PatternSyntaxException.java
@@ -1835,6 +1844,11 @@
 gnu/java/text/WordBreakIterator.java \
 gnu/java/util/DoubleEnumeration.java \
 gnu/java/util/EmptyEnumeration.java \
+gnu/java/util/prefs/MemoryBasedFactory.java \
+gnu/java/util/prefs/NodeReader.java \
+gnu/java/util/prefs/MemoryBasedPreferences.java \
+gnu/java/util/prefs/FileBasedFactory.java \
+gnu/java/util/prefs/NodeWriter.java \
 java/lang/ref/PhantomReference.java \
 java/lang/ref/Reference.java \
 java/lang/ref/ReferenceQueue.java \
@@ -2912,7 +2926,12 @@
 .deps/gnu/java/text/SentenceBreakIterator.P \
 .deps/gnu/java/text/WordBreakIterator.P \
 .deps/gnu/java/util/DoubleEnumeration.P \
-.deps/gnu/java/util/EmptyEnumeration.P .deps/interpret.P \
+.deps/gnu/java/util/EmptyEnumeration.P \
+.deps/gnu/java/util/prefs/FileBasedFactory.P \
+.deps/gnu/java/util/prefs/MemoryBasedFactory.P \
+.deps/gnu/java/util/prefs/MemoryBasedPreferences.P \
+.deps/gnu/java/util/prefs/NodeReader.P \
+.deps/gnu/java/util/prefs/NodeWriter.P .deps/interpret.P \
 .deps/java/applet/Applet.P .deps/java/applet/AppletContext.P \
 .deps/java/applet/AppletStub.P .deps/java/applet/AudioClip.P \
 .deps/java/awt/AWTError.P .deps/java/awt/AWTEvent.P \
@@ -3604,6 +3623,15 @@
 .deps/java/util/jar/JarInputStream.P \
 .deps/java/util/jar/JarOutputStream.P .deps/java/util/jar/Manifest.P \
 .deps/java/util/natResourceBundle.P .deps/java/util/natTimeZone.P \
+.deps/java/util/prefs/AbstractPreferences.P \
+.deps/java/util/prefs/BackingStoreException.P \
+.deps/java/util/prefs/InvalidPreferencesFormatException.P \
+.deps/java/util/prefs/NodeChangeEvent.P \
+.deps/java/util/prefs/NodeChangeListener.P \
+.deps/java/util/prefs/PreferenceChangeEvent.P \
+.deps/java/util/prefs/PreferenceChangeListener.P \
+.deps/java/util/prefs/Preferences.P \
+.deps/java/util/prefs/PreferencesFactory.P \
 .deps/java/util/regex/Matcher.P .deps/java/util/regex/Pattern.P \
 .deps/java/util/regex/PatternSyntaxException.P \
 .deps/java/util/zip/Adler32.P .deps/java/util/zip/CRC32.P \
--- /home/mkoch/src/gcc-cvs/libjava/Makefile.am	2003-02-12 11:16:32.000000000 +0100
+++ /home/mkoch/src/gcc-work/libjava/Makefile.am	2003-02-12 11:24:44.000000000 +0100
@@ -1855,6 +1855,15 @@
 java/util/TooManyListenersException.java \
 java/util/Vector.java \
 java/util/WeakHashMap.java \
+java/util/prefs/NodeChangeListener.java \
+java/util/prefs/Preferences.java \
+java/util/prefs/PreferenceChangeListener.java \
+java/util/prefs/NodeChangeEvent.java \
+java/util/prefs/InvalidPreferencesFormatException.java \
+java/util/prefs/AbstractPreferences.java \
+java/util/prefs/BackingStoreException.java \
+java/util/prefs/PreferenceChangeEvent.java \
+java/util/prefs/PreferencesFactory.java \
 java/util/regex/Matcher.java \
 java/util/regex/Pattern.java \
 java/util/regex/PatternSyntaxException.java
@@ -2075,6 +2084,11 @@
 gnu/java/text/WordBreakIterator.java \
 gnu/java/util/DoubleEnumeration.java \
 gnu/java/util/EmptyEnumeration.java \
+gnu/java/util/prefs/MemoryBasedFactory.java \
+gnu/java/util/prefs/NodeReader.java \
+gnu/java/util/prefs/MemoryBasedPreferences.java \
+gnu/java/util/prefs/FileBasedFactory.java \
+gnu/java/util/prefs/NodeWriter.java \
 java/lang/ref/PhantomReference.java \
 java/lang/ref/Reference.java \
 java/lang/ref/ReferenceQueue.java \

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]