History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/java/util/prefs/Preferences.java (1 of 18352 files). Show all

Unified · Split

java/pkg/java/util/prefs/Preferences.java+1256−0
@@ -0,0 +1,1256 @@
1+/*
2+ * Copyright (c) 2000, 2008, Oracle and/or its affiliates. All rights reserved.
3+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+ *
5+ * This code is free software; you can redistribute it and/or modify it
6+ * under the terms of the GNU General Public License version 2 only, as
7+ * published by the Free Software Foundation. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle in the LICENSE file that accompanied this code.
10+ *
11+ * This code is distributed in the hope that it will be useful, but WITHOUT
12+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+ * version 2 for more details (a copy is included in the LICENSE file that
15+ * accompanied this code).
16+ *
17+ * You should have received a copy of the GNU General Public License version
18+ * 2 along with this work; if not, write to the Free Software Foundation,
19+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+ *
21+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+
26+package java.util.prefs;
27+
28+import java.io.InputStream;
29+import java.io.IOException;
30+import java.io.OutputStream;
31+import java.security.AccessController;
32+import java.security.Permission;
33+import java.security.PrivilegedAction;
34+import java.util.Iterator;
35+import java.util.ServiceLoader;
36+import java.util.ServiceConfigurationError;
37+
38+// These imports needed only as a workaround for a JavaDoc bug
39+import java.lang.RuntimePermission;
40+import java.lang.Integer;
41+import java.lang.Long;
42+import java.lang.Float;
43+import java.lang.Double;
44+
45+/**
46+ * A node in a hierarchical collection of preference data. This class
47+ * allows applications to store and retrieve user and system
48+ * preference and configuration data. This data is stored
49+ * persistently in an implementation-dependent backing store. Typical
50+ * implementations include flat files, OS-specific registries,
51+ * directory servers and SQL databases. The user of this class needn't
52+ * be concerned with details of the backing store.
53+ *
54+ * <p>There are two separate trees of preference nodes, one for user
55+ * preferences and one for system preferences. Each user has a separate user
56+ * preference tree, and all users in a given system share the same system
57+ * preference tree. The precise description of "user" and "system" will vary
58+ * from implementation to implementation. Typical information stored in the
59+ * user preference tree might include font choice, color choice, or preferred
60+ * window location and size for a particular application. Typical information
61+ * stored in the system preference tree might include installation
62+ * configuration data for an application.
63+ *
64+ * <p>Nodes in a preference tree are named in a similar fashion to
65+ * directories in a hierarchical file system. Every node in a preference
66+ * tree has a <i>node name</i> (which is not necessarily unique),
67+ * a unique <i>absolute path name</i>, and a path name <i>relative</i> to each
68+ * ancestor including itself.
69+ *
70+ * <p>The root node has a node name of the empty string (""). Every other
71+ * node has an arbitrary node name, specified at the time it is created. The
72+ * only restrictions on this name are that it cannot be the empty string, and
73+ * it cannot contain the slash character ('/').
74+ *
75+ * <p>The root node has an absolute path name of <tt>"/"</tt>. Children of
76+ * the root node have absolute path names of <tt>"/" + </tt><i>&lt;node
77+ * name&gt;</i>. All other nodes have absolute path names of <i>&lt;parent's
78+ * absolute path name&gt;</i><tt> + "/" + </tt><i>&lt;node name&gt;</i>.
79+ * Note that all absolute path names begin with the slash character.
80+ *
81+ * <p>A node <i>n</i>'s path name relative to its ancestor <i>a</i>
82+ * is simply the string that must be appended to <i>a</i>'s absolute path name
83+ * in order to form <i>n</i>'s absolute path name, with the initial slash
84+ * character (if present) removed. Note that:
85+ * <ul>
86+ * <li>No relative path names begin with the slash character.
87+ * <li>Every node's path name relative to itself is the empty string.
88+ * <li>Every node's path name relative to its parent is its node name (except
89+ * for the root node, which does not have a parent).
90+ * <li>Every node's path name relative to the root is its absolute path name
91+ * with the initial slash character removed.
92+ * </ul>
93+ *
94+ * <p>Note finally that:
95+ * <ul>
96+ * <li>No path name contains multiple consecutive slash characters.
97+ * <li>No path name with the exception of the root's absolute path name
98+ * ends in the slash character.
99+ * <li>Any string that conforms to these two rules is a valid path name.
100+ * </ul>
101+ *
102+ * <p>All of the methods that modify preferences data are permitted to operate
103+ * asynchronously; they may return immediately, and changes will eventually
104+ * propagate to the persistent backing store with an implementation-dependent
105+ * delay. The <tt>flush</tt> method may be used to synchronously force
106+ * updates to the backing store. Normal termination of the Java Virtual
107+ * Machine will <i>not</i> result in the loss of pending updates -- an explicit
108+ * <tt>flush</tt> invocation is <i>not</i> required upon termination to ensure
109+ * that pending updates are made persistent.
110+ *
111+ * <p>All of the methods that read preferences from a <tt>Preferences</tt>
112+ * object require the invoker to provide a default value. The default value is
113+ * returned if no value has been previously set <i>or if the backing store is
114+ * unavailable</i>. The intent is to allow applications to operate, albeit
115+ * with slightly degraded functionality, even if the backing store becomes
116+ * unavailable. Several methods, like <tt>flush</tt>, have semantics that
117+ * prevent them from operating if the backing store is unavailable. Ordinary
118+ * applications should have no need to invoke any of these methods, which can
119+ * be identified by the fact that they are declared to throw {@link
120+ * BackingStoreException}.
121+ *
122+ * <p>The methods in this class may be invoked concurrently by multiple threads
123+ * in a single JVM without the need for external synchronization, and the
124+ * results will be equivalent to some serial execution. If this class is used
125+ * concurrently <i>by multiple JVMs</i> that store their preference data in
126+ * the same backing store, the data store will not be corrupted, but no
127+ * other guarantees are made concerning the consistency of the preference
128+ * data.
129+ *
130+ * <p>This class contains an export/import facility, allowing preferences
131+ * to be "exported" to an XML document, and XML documents representing
132+ * preferences to be "imported" back into the system. This facility
133+ * may be used to back up all or part of a preference tree, and
134+ * subsequently restore from the backup.
135+ *
136+ * <p>The XML document has the following DOCTYPE declaration:
137+ * <pre>
138+ * &lt;!DOCTYPE preferences SYSTEM "http://java.sun.com/dtd/preferences.dtd"&gt;
139+ * </pre>
140+ * Note that the system URI (http://java.sun.com/dtd/preferences.dtd) is
141+ * <i>not</i> accessed when exporting or importing preferences; it merely
142+ * serves as a string to uniquely identify the DTD, which is:
143+ * <pre>
144+ * &lt;?xml version="1.0" encoding="UTF-8"?&gt;
145+ *
146+ * &lt;!-- DTD for a Preferences tree. --&gt;
147+ *
148+ * &lt;!-- The preferences element is at the root of an XML document
149+ * representing a Preferences tree. --&gt;
150+ * &lt;!ELEMENT preferences (root)&gt;
151+ *
152+ * &lt;!-- The preferences element contains an optional version attribute,
153+ * which specifies version of DTD. --&gt;
154+ * &lt;!ATTLIST preferences EXTERNAL_XML_VERSION CDATA "0.0" &gt
155+ *
156+ * &lt;!-- The root element has a map representing the root's preferences
157+ * (if any), and one node for each child of the root (if any). --&gt;
158+ * &lt;!ELEMENT root (map, node*) &gt;
159+ *
160+ * &lt;!-- Additionally, the root contains a type attribute, which
161+ * specifies whether it's the system or user root. --&gt;
162+ * &lt;!ATTLIST root
163+ * type (system|user) #REQUIRED &gt;
164+ *
165+ * &lt;!-- Each node has a map representing its preferences (if any),
166+ * and one node for each child (if any). --&gt;
167+ * &lt;!ELEMENT node (map, node*) &gt;
168+ *
169+ * &lt;!-- Additionally, each node has a name attribute --&gt;
170+ * &lt;!ATTLIST node
171+ * name CDATA #REQUIRED &gt;
172+ *
173+ * &lt;!-- A map represents the preferences stored at a node (if any). --&gt;
174+ * &lt;!ELEMENT map (entry*) &gt;
175+ *
176+ * &lt;!-- An entry represents a single preference, which is simply
177+ * a key-value pair. --&gt;
178+ * &lt;!ELEMENT entry EMPTY &gt;
179+ * &lt;!ATTLIST entry
180+ * key CDATA #REQUIRED
181+ * value CDATA #REQUIRED &gt;
182+ * </pre>
183+ *
184+ * Every <tt>Preferences</tt> implementation must have an associated {@link
185+ * PreferencesFactory} implementation. Every Java(TM) SE implementation must provide
186+ * some means of specifying which <tt>PreferencesFactory</tt> implementation
187+ * is used to generate the root preferences nodes. This allows the
188+ * administrator to replace the default preferences implementation with an
189+ * alternative implementation.
190+ *
191+ * <p>Implementation note: In Sun's JRE, the <tt>PreferencesFactory</tt>
192+ * implementation is located as follows:
193+ *
194+ * <ol>
195+ *
196+ * <li><p>If the system property
197+ * <tt>java.util.prefs.PreferencesFactory</tt> is defined, then it is
198+ * taken to be the fully-qualified name of a class implementing the
199+ * <tt>PreferencesFactory</tt> interface. The class is loaded and
200+ * instantiated; if this process fails then an unspecified error is
201+ * thrown.</p></li>
202+ *
203+ * <li><p> If a <tt>PreferencesFactory</tt> implementation class file
204+ * has been installed in a jar file that is visible to the
205+ * {@link java.lang.ClassLoader#getSystemClassLoader system class loader},
206+ * and that jar file contains a provider-configuration file named
207+ * <tt>java.util.prefs.PreferencesFactory</tt> in the resource
208+ * directory <tt>META-INF/services</tt>, then the first class name
209+ * specified in that file is taken. If more than one such jar file is
210+ * provided, the first one found will be used. The class is loaded
211+ * and instantiated; if this process fails then an unspecified error
212+ * is thrown. </p></li>
213+ *
214+ * <li><p>Finally, if neither the above-mentioned system property nor
215+ * an extension jar file is provided, then the system-wide default
216+ * <tt>PreferencesFactory</tt> implementation for the underlying
217+ * platform is loaded and instantiated.</p></li>
218+ *
219+ * </ol>
220+ *
221+ * @author Josh Bloch
222+ * @since 1.4
223+ */
224+public abstract class Preferences {
225+
226+ private static final PreferencesFactory factory = factory();
227+
228+ private static PreferencesFactory factory() {
229+ // 1. Try user-specified system property
230+ String factoryName = AccessController.doPrivileged(
231+ new PrivilegedAction<String>() {
232+ public String run() {
233+ return System.getProperty(
234+ "java.util.prefs.PreferencesFactory");}});
235+ if (factoryName != null) {
236+ // FIXME: This code should be run in a doPrivileged and
237+ // not use the context classloader, to avoid being
238+ // dependent on the invoking thread.
239+ // Checking AllPermission also seems wrong.
240+ try {
241+ return (PreferencesFactory)
242+ Class.forName(factoryName, false,
243+ ClassLoader.getSystemClassLoader())
244+ .newInstance();
245+ } catch (Exception ex) {
246+ try {
247+ // workaround for javaws, plugin,
248+ // load factory class using non-system classloader
249+ SecurityManager sm = System.getSecurityManager();
250+ if (sm != null) {
251+ sm.checkPermission(new java.security.AllPermission());
252+ }
253+ return (PreferencesFactory)
254+ Class.forName(factoryName, false,
255+ Thread.currentThread()
256+ .getContextClassLoader())
257+ .newInstance();
258+ } catch (Exception e) {
259+ InternalError error = new InternalError(
260+ "Can't instantiate Preferences factory "
261+ + factoryName);
262+ error.initCause(e);
263+ throw error;
264+ }
265+ }
266+ }
267+
268+ return AccessController.doPrivileged(
269+ new PrivilegedAction<PreferencesFactory>() {
270+ public PreferencesFactory run() {
271+ return factory1();}});
272+ }
273+
274+ private static PreferencesFactory factory1() {
275+ // 2. Try service provider interface
276+ Iterator<PreferencesFactory> itr = ServiceLoader
277+ .load(PreferencesFactory.class, ClassLoader.getSystemClassLoader())
278+ .iterator();
279+
280+ // choose first provider instance
281+ while (itr.hasNext()) {
282+ try {
283+ return itr.next();
284+ } catch (ServiceConfigurationError sce) {
285+ if (sce.getCause() instanceof SecurityException) {
286+ // Ignore the security exception, try the next provider
287+ continue;
288+ }
289+ throw sce;
290+ }
291+ }
292+
293+ // 3. Use platform-specific system-wide default
294+ String platformFactory =
295+ System.getProperty("os.name").startsWith("Windows")
296+ ? "java.util.prefs.WindowsPreferencesFactory"
297+ : "java.util.prefs.FileSystemPreferencesFactory";
298+ try {
299+ return (PreferencesFactory)
300+ Class.forName(platformFactory, false, null).newInstance();
301+ } catch (Exception e) {
302+ InternalError error = new InternalError(
303+ "Can't instantiate platform default Preferences factory "
304+ + platformFactory);
305+ error.initCause(e);
306+ throw error;
307+ }
308+ }
309+
310+ /**
311+ * Maximum length of string allowed as a key (80 characters).
312+ */
313+ public static final int MAX_KEY_LENGTH = 80;
314+
315+ /**
316+ * Maximum length of string allowed as a value (8192 characters).
317+ */
318+ public static final int MAX_VALUE_LENGTH = 8*1024;
319+
320+ /**
321+ * Maximum length of a node name (80 characters).
322+ */
323+ public static final int MAX_NAME_LENGTH = 80;
324+
325+ /**
326+ * Returns the preference node from the calling user's preference tree
327+ * that is associated (by convention) with the specified class's package.
328+ * The convention is as follows: the absolute path name of the node is the
329+ * fully qualified package name, preceded by a slash (<tt>'/'</tt>), and
330+ * with each period (<tt>'.'</tt>) replaced by a slash. For example the
331+ * absolute path name of the node associated with the class
332+ * <tt>com.acme.widget.Foo</tt> is <tt>/com/acme/widget</tt>.
333+ *
334+ * <p>This convention does not apply to the unnamed package, whose
335+ * associated preference node is <tt>&lt;unnamed&gt;</tt>. This node
336+ * is not intended for long term use, but for convenience in the early
337+ * development of programs that do not yet belong to a package, and
338+ * for "throwaway" programs. <i>Valuable data should not be stored
339+ * at this node as it is shared by all programs that use it.</i>
340+ *
341+ * <p>A class <tt>Foo</tt> wishing to access preferences pertaining to its
342+ * package can obtain a preference node as follows: <pre>
343+ * static Preferences prefs = Preferences.userNodeForPackage(Foo.class);
344+ * </pre>
345+ * This idiom obviates the need for using a string to describe the
346+ * preferences node and decreases the likelihood of a run-time failure.
347+ * (If the class name is misspelled, it will typically result in a
348+ * compile-time error.)
349+ *
350+ * <p>Invoking this method will result in the creation of the returned
351+ * node and its ancestors if they do not already exist. If the returned
352+ * node did not exist prior to this call, this node and any ancestors that
353+ * were created by this call are not guaranteed to become permanent until
354+ * the <tt>flush</tt> method is called on the returned node (or one of its
355+ * ancestors or descendants).
356+ *
357+ * @param c the class for whose package a user preference node is desired.
358+ * @return the user preference node associated with the package of which
359+ * <tt>c</tt> is a member.
360+ * @throws NullPointerException if <tt>c</tt> is <tt>null</tt>.
361+ * @throws SecurityException if a security manager is present and
362+ * it denies <tt>RuntimePermission("preferences")</tt>.
363+ * @see RuntimePermission
364+ */
365+ public static Preferences userNodeForPackage(Class<?> c) {
366+ return userRoot().node(nodeName(c));
367+ }
368+
369+ /**
370+ * Returns the preference node from the system preference tree that is
371+ * associated (by convention) with the specified class's package. The
372+ * convention is as follows: the absolute path name of the node is the
373+ * fully qualified package name, preceded by a slash (<tt>'/'</tt>), and
374+ * with each period (<tt>'.'</tt>) replaced by a slash. For example the
375+ * absolute path name of the node associated with the class
376+ * <tt>com.acme.widget.Foo</tt> is <tt>/com/acme/widget</tt>.
377+ *
378+ * <p>This convention does not apply to the unnamed package, whose
379+ * associated preference node is <tt>&lt;unnamed&gt;</tt>. This node
380+ * is not intended for long term use, but for convenience in the early
381+ * development of programs that do not yet belong to a package, and
382+ * for "throwaway" programs. <i>Valuable data should not be stored
383+ * at this node as it is shared by all programs that use it.</i>
384+ *
385+ * <p>A class <tt>Foo</tt> wishing to access preferences pertaining to its
386+ * package can obtain a preference node as follows: <pre>
387+ * static Preferences prefs = Preferences.systemNodeForPackage(Foo.class);
388+ * </pre>
389+ * This idiom obviates the need for using a string to describe the
390+ * preferences node and decreases the likelihood of a run-time failure.
391+ * (If the class name is misspelled, it will typically result in a
392+ * compile-time error.)
393+ *
394+ * <p>Invoking this method will result in the creation of the returned
395+ * node and its ancestors if they do not already exist. If the returned
396+ * node did not exist prior to this call, this node and any ancestors that
397+ * were created by this call are not guaranteed to become permanent until
398+ * the <tt>flush</tt> method is called on the returned node (or one of its
399+ * ancestors or descendants).
400+ *
401+ * @param c the class for whose package a system preference node is desired.
402+ * @return the system preference node associated with the package of which
403+ * <tt>c</tt> is a member.
404+ * @throws NullPointerException if <tt>c</tt> is <tt>null</tt>.
405+ * @throws SecurityException if a security manager is present and
406+ * it denies <tt>RuntimePermission("preferences")</tt>.
407+ * @see RuntimePermission
408+ */
409+ public static Preferences systemNodeForPackage(Class<?> c) {
410+ return systemRoot().node(nodeName(c));
411+ }
412+
413+ /**
414+ * Returns the absolute path name of the node corresponding to the package
415+ * of the specified object.
416+ *
417+ * @throws IllegalArgumentException if the package has node preferences
418+ * node associated with it.
419+ */
420+ private static String nodeName(Class c) {
421+ if (c.isArray())
422+ throw new IllegalArgumentException(
423+ "Arrays have no associated preferences node.");
424+ String className = c.getName();
425+ int pkgEndIndex = className.lastIndexOf('.');
426+ if (pkgEndIndex < 0)
427+ return "/<unnamed>";
428+ String packageName = className.substring(0, pkgEndIndex);
429+ return "/" + packageName.replace('.', '/');
430+ }
431+
432+ /**
433+ * This permission object represents the permission required to get
434+ * access to the user or system root (which in turn allows for all
435+ * other operations).
436+ */
437+ private static Permission prefsPerm = new RuntimePermission("preferences");
438+
439+ /**
440+ * Returns the root preference node for the calling user.
441+ *
442+ * @return the root preference node for the calling user.
443+ * @throws SecurityException If a security manager is present and
444+ * it denies <tt>RuntimePermission("preferences")</tt>.
445+ * @see RuntimePermission
446+ */
447+ public static Preferences userRoot() {
448+ SecurityManager security = System.getSecurityManager();
449+ if (security != null)
450+ security.checkPermission(prefsPerm);
451+
452+ return factory.userRoot();
453+ }
454+
455+ /**
456+ * Returns the root preference node for the system.
457+ *
458+ * @return the root preference node for the system.
459+ * @throws SecurityException If a security manager is present and
460+ * it denies <tt>RuntimePermission("preferences")</tt>.
461+ * @see RuntimePermission
462+ */
463+ public static Preferences systemRoot() {
464+ SecurityManager security = System.getSecurityManager();
465+ if (security != null)
466+ security.checkPermission(prefsPerm);
467+
468+ return factory.systemRoot();
469+ }
470+
471+ /**
472+ * Sole constructor. (For invocation by subclass constructors, typically
473+ * implicit.)
474+ */
475+ protected Preferences() {
476+ }
477+
478+ /**
479+ * Associates the specified value with the specified key in this
480+ * preference node.
481+ *
482+ * @param key key with which the specified value is to be associated.
483+ * @param value value to be associated with the specified key.
484+ * @throws NullPointerException if key or value is <tt>null</tt>.
485+ * @throws IllegalArgumentException if <tt>key.length()</tt> exceeds
486+ * <tt>MAX_KEY_LENGTH</tt> or if <tt>value.length</tt> exceeds
487+ * <tt>MAX_VALUE_LENGTH</tt>.
488+ * @throws IllegalStateException if this node (or an ancestor) has been
489+ * removed with the {@link #removeNode()} method.
490+ */
491+ public abstract void put(String key, String value);
492+
493+ /**
494+ * Returns the value associated with the specified key in this preference
495+ * node. Returns the specified default if there is no value associated
496+ * with the key, or the backing store is inaccessible.
497+ *
498+ * <p>Some implementations may store default values in their backing
499+ * stores. If there is no value associated with the specified key
500+ * but there is such a <i>stored default</i>, it is returned in
501+ * preference to the specified default.
502+ *
503+ * @param key key whose associated value is to be returned.
504+ * @param def the value to be returned in the event that this
505+ * preference node has no value associated with <tt>key</tt>.
506+ * @return the value associated with <tt>key</tt>, or <tt>def</tt>
507+ * if no value is associated with <tt>key</tt>, or the backing
508+ * store is inaccessible.
509+ * @throws IllegalStateException if this node (or an ancestor) has been
510+ * removed with the {@link #removeNode()} method.
511+ * @throws NullPointerException if <tt>key</tt> is <tt>null</tt>. (A
512+ * <tt>null</tt> value for <tt>def</tt> <i>is</i> permitted.)
513+ */
514+ public abstract String get(String key, String def);
515+
516+ /**
517+ * Removes the value associated with the specified key in this preference
518+ * node, if any.
519+ *
520+ * <p>If this implementation supports <i>stored defaults</i>, and there is
521+ * such a default for the specified preference, the stored default will be
522+ * "exposed" by this call, in the sense that it will be returned
523+ * by a succeeding call to <tt>get</tt>.
524+ *
525+ * @param key key whose mapping is to be removed from the preference node.
526+ * @throws NullPointerException if <tt>key</tt> is <tt>null</tt>.
527+ * @throws IllegalStateException if this node (or an ancestor) has been
528+ * removed with the {@link #removeNode()} method.
529+ */
530+ public abstract void remove(String key);
531+
532+ /**
533+ * Removes all of the preferences (key-value associations) in this
534+ * preference node. This call has no effect on any descendants
535+ * of this node.
536+ *
537+ * <p>If this implementation supports <i>stored defaults</i>, and this
538+ * node in the preferences hierarchy contains any such defaults,
539+ * the stored defaults will be "exposed" by this call, in the sense that
540+ * they will be returned by succeeding calls to <tt>get</tt>.
541+ *
542+ * @throws BackingStoreException if this operation cannot be completed
543+ * due to a failure in the backing store, or inability to
544+ * communicate with it.
545+ * @throws IllegalStateException if this node (or an ancestor) has been
546+ * removed with the {@link #removeNode()} method.
547+ * @see #removeNode()
548+ */
549+ public abstract void clear() throws BackingStoreException;
550+
551+ /**
552+ * Associates a string representing the specified int value with the
553+ * specified key in this preference node. The associated string is the
554+ * one that would be returned if the int value were passed to
555+ * {@link Integer#toString(int)}. This method is intended for use in
556+ * conjunction with {@link #getInt}.
557+ *
558+ * @param key key with which the string form of value is to be associated.
559+ * @param value value whose string form is to be associated with key.
560+ * @throws NullPointerException if <tt>key</tt> is <tt>null</tt>.
561+ * @throws IllegalArgumentException if <tt>key.length()</tt> exceeds
562+ * <tt>MAX_KEY_LENGTH</tt>.
563+ * @throws IllegalStateException if this node (or an ancestor) has been
564+ * removed with the {@link #removeNode()} method.
565+ * @see #getInt(String,int)
566+ */
567+ public abstract void putInt(String key, int value);
568+
569+ /**
570+ * Returns the int value represented by the string associated with the
571+ * specified key in this preference node. The string is converted to
572+ * an integer as by {@link Integer#parseInt(String)}. Returns the
573+ * specified default if there is no value associated with the key,
574+ * the backing store is inaccessible, or if
575+ * <tt>Integer.parseInt(String)</tt> would throw a {@link
576+ * NumberFormatException} if the associated value were passed. This
577+ * method is intended for use in conjunction with {@link #putInt}.
578+ *
579+ * <p>If the implementation supports <i>stored defaults</i> and such a
580+ * default exists, is accessible, and could be converted to an int
581+ * with <tt>Integer.parseInt</tt>, this int is returned in preference to
582+ * the specified default.
583+ *
584+ * @param key key whose associated value is to be returned as an int.
585+ * @param def the value to be returned in the event that this
586+ * preference node has no value associated with <tt>key</tt>
587+ * or the associated value cannot be interpreted as an int,
588+ * or the backing store is inaccessible.
589+ * @return the int value represented by the string associated with
590+ * <tt>key</tt> in this preference node, or <tt>def</tt> if the
591+ * associated value does not exist or cannot be interpreted as
592+ * an int.
593+ * @throws IllegalStateException if this node (or an ancestor) has been
594+ * removed with the {@link #removeNode()} method.
595+ * @throws NullPointerException if <tt>key</tt> is <tt>null</tt>.
596+ * @see #putInt(String,int)
597+ * @see #get(String,String)
598+ */
599+ public abstract int getInt(String key, int def);
600+
601+ /**
602+ * Associates a string representing the specified long value with the
603+ * specified key in this preference node. The associated string is the
604+ * one that would be returned if the long value were passed to
605+ * {@link Long#toString(long)}. This method is intended for use in
606+ * conjunction with {@link #getLong}.
607+ *
608+ * @param key key with which the string form of value is to be associated.
609+ * @param value value whose string form is to be associated with key.
610+ * @throws NullPointerException if <tt>key</tt> is <tt>null</tt>.
611+ * @throws IllegalArgumentException if <tt>key.length()</tt> exceeds
612+ * <tt>MAX_KEY_LENGTH</tt>.
613+ * @throws IllegalStateException if this node (or an ancestor) has been
614+ * removed with the {@link #removeNode()} method.
615+ * @see #getLong(String,long)
616+ */
617+ public abstract void putLong(String key, long value);
618+
619+ /**
620+ * Returns the long value represented by the string associated with the
621+ * specified key in this preference node. The string is converted to
622+ * a long as by {@link Long#parseLong(String)}. Returns the
623+ * specified default if there is no value associated with the key,
624+ * the backing store is inaccessible, or if
625+ * <tt>Long.parseLong(String)</tt> would throw a {@link
626+ * NumberFormatException} if the associated value were passed. This
627+ * method is intended for use in conjunction with {@link #putLong}.
628+ *
629+ * <p>If the implementation supports <i>stored defaults</i> and such a
630+ * default exists, is accessible, and could be converted to a long
631+ * with <tt>Long.parseLong</tt>, this long is returned in preference to
632+ * the specified default.
633+ *
634+ * @param key key whose associated value is to be returned as a long.
635+ * @param def the value to be returned in the event that this
636+ * preference node has no value associated with <tt>key</tt>
637+ * or the associated value cannot be interpreted as a long,
638+ * or the backing store is inaccessible.
639+ * @return the long value represented by the string associated with
640+ * <tt>key</tt> in this preference node, or <tt>def</tt> if the
641+ * associated value does not exist or cannot be interpreted as
642+ * a long.
643+ * @throws IllegalStateException if this node (or an ancestor) has been
644+ * removed with the {@link #removeNode()} method.
645+ * @throws NullPointerException if <tt>key</tt> is <tt>null</tt>.
646+ * @see #putLong(String,long)
647+ * @see #get(String,String)
648+ */
649+ public abstract long getLong(String key, long def);
650+
651+ /**
652+ * Associates a string representing the specified boolean value with the
653+ * specified key in this preference node. The associated string is
654+ * <tt>"true"</tt> if the value is true, and <tt>"false"</tt> if it is
655+ * false. This method is intended for use in conjunction with
656+ * {@link #getBoolean}.
657+ *
658+ * @param key key with which the string form of value is to be associated.
659+ * @param value value whose string form is to be associated with key.
660+ * @throws NullPointerException if <tt>key</tt> is <tt>null</tt>.
661+ * @throws IllegalArgumentException if <tt>key.length()</tt> exceeds
662+ * <tt>MAX_KEY_LENGTH</tt>.
663+ * @throws IllegalStateException if this node (or an ancestor) has been
664+ * removed with the {@link #removeNode()} method.
665+ * @see #getBoolean(String,boolean)
666+ * @see #get(String,String)
667+ */
668+ public abstract void putBoolean(String key, boolean value);
669+
670+ /**
671+ * Returns the boolean value represented by the string associated with the
672+ * specified key in this preference node. Valid strings
673+ * are <tt>"true"</tt>, which represents true, and <tt>"false"</tt>, which
674+ * represents false. Case is ignored, so, for example, <tt>"TRUE"</tt>
675+ * and <tt>"False"</tt> are also valid. This method is intended for use in
676+ * conjunction with {@link #putBoolean}.
677+ *
678+ * <p>Returns the specified default if there is no value
679+ * associated with the key, the backing store is inaccessible, or if the
680+ * associated value is something other than <tt>"true"</tt> or
681+ * <tt>"false"</tt>, ignoring case.
682+ *
683+ * <p>If the implementation supports <i>stored defaults</i> and such a
684+ * default exists and is accessible, it is used in preference to the
685+ * specified default, unless the stored default is something other than
686+ * <tt>"true"</tt> or <tt>"false"</tt>, ignoring case, in which case the
687+ * specified default is used.
688+ *
689+ * @param key key whose associated value is to be returned as a boolean.
690+ * @param def the value to be returned in the event that this
691+ * preference node has no value associated with <tt>key</tt>
692+ * or the associated value cannot be interpreted as a boolean,
693+ * or the backing store is inaccessible.
694+ * @return the boolean value represented by the string associated with
695+ * <tt>key</tt> in this preference node, or <tt>def</tt> if the
696+ * associated value does not exist or cannot be interpreted as
697+ * a boolean.
698+ * @throws IllegalStateException if this node (or an ancestor) has been
699+ * removed with the {@link #removeNode()} method.
700+ * @throws NullPointerException if <tt>key</tt> is <tt>null</tt>.
701+ * @see #get(String,String)
702+ * @see #putBoolean(String,boolean)
703+ */
704+ public abstract boolean getBoolean(String key, boolean def);
705+
706+ /**
707+ * Associates a string representing the specified float value with the
708+ * specified key in this preference node. The associated string is the
709+ * one that would be returned if the float value were passed to
710+ * {@link Float#toString(float)}. This method is intended for use in
711+ * conjunction with {@link #getFloat}.
712+ *
713+ * @param key key with which the string form of value is to be associated.
714+ * @param value value whose string form is to be associated with key.
715+ * @throws NullPointerException if <tt>key</tt> is <tt>null</tt>.
716+ * @throws IllegalArgumentException if <tt>key.length()</tt> exceeds
717+ * <tt>MAX_KEY_LENGTH</tt>.
718+ * @throws IllegalStateException if this node (or an ancestor) has been
719+ * removed with the {@link #removeNode()} method.
720+ * @see #getFloat(String,float)
721+ */
722+ public abstract void putFloat(String key, float value);
723+
724+ /**
725+ * Returns the float value represented by the string associated with the
726+ * specified key in this preference node. The string is converted to an
727+ * integer as by {@link Float#parseFloat(String)}. Returns the specified
728+ * default if there is no value associated with the key, the backing store
729+ * is inaccessible, or if <tt>Float.parseFloat(String)</tt> would throw a
730+ * {@link NumberFormatException} if the associated value were passed.
731+ * This method is intended for use in conjunction with {@link #putFloat}.
732+ *
733+ * <p>If the implementation supports <i>stored defaults</i> and such a
734+ * default exists, is accessible, and could be converted to a float
735+ * with <tt>Float.parseFloat</tt>, this float is returned in preference to
736+ * the specified default.
737+ *
738+ * @param key key whose associated value is to be returned as a float.
739+ * @param def the value to be returned in the event that this
740+ * preference node has no value associated with <tt>key</tt>
741+ * or the associated value cannot be interpreted as a float,
742+ * or the backing store is inaccessible.
743+ * @return the float value represented by the string associated with
744+ * <tt>key</tt> in this preference node, or <tt>def</tt> if the
745+ * associated value does not exist or cannot be interpreted as
746+ * a float.
747+ * @throws IllegalStateException if this node (or an ancestor) has been
748+ * removed with the {@link #removeNode()} method.
749+ * @throws NullPointerException if <tt>key</tt> is <tt>null</tt>.
750+ * @see #putFloat(String,float)
751+ * @see #get(String,String)
752+ */
753+ public abstract float getFloat(String key, float def);
754+
755+ /**
756+ * Associates a string representing the specified double value with the
757+ * specified key in this preference node. The associated string is the
758+ * one that would be returned if the double value were passed to
759+ * {@link Double#toString(double)}. This method is intended for use in
760+ * conjunction with {@link #getDouble}.
761+ *
762+ * @param key key with which the string form of value is to be associated.
763+ * @param value value whose string form is to be associated with key.
764+ * @throws NullPointerException if <tt>key</tt> is <tt>null</tt>.
765+ * @throws IllegalArgumentException if <tt>key.length()</tt> exceeds
766+ * <tt>MAX_KEY_LENGTH</tt>.
767+ * @throws IllegalStateException if this node (or an ancestor) has been
768+ * removed with the {@link #removeNode()} method.
769+ * @see #getDouble(String,double)
770+ */
771+ public abstract void putDouble(String key, double value);
772+
773+ /**
774+ * Returns the double value represented by the string associated with the
775+ * specified key in this preference node. The string is converted to an
776+ * integer as by {@link Double#parseDouble(String)}. Returns the specified
777+ * default if there is no value associated with the key, the backing store
778+ * is inaccessible, or if <tt>Double.parseDouble(String)</tt> would throw a
779+ * {@link NumberFormatException} if the associated value were passed.
780+ * This method is intended for use in conjunction with {@link #putDouble}.
781+ *
782+ * <p>If the implementation supports <i>stored defaults</i> and such a
783+ * default exists, is accessible, and could be converted to a double
784+ * with <tt>Double.parseDouble</tt>, this double is returned in preference
785+ * to the specified default.
786+ *
787+ * @param key key whose associated value is to be returned as a double.
788+ * @param def the value to be returned in the event that this
789+ * preference node has no value associated with <tt>key</tt>
790+ * or the associated value cannot be interpreted as a double,
791+ * or the backing store is inaccessible.
792+ * @return the double value represented by the string associated with
793+ * <tt>key</tt> in this preference node, or <tt>def</tt> if the
794+ * associated value does not exist or cannot be interpreted as
795+ * a double.
796+ * @throws IllegalStateException if this node (or an ancestor) has been
797+ * removed with the {@link #removeNode()} method.
798+ * @throws NullPointerException if <tt>key</tt> is <tt>null</tt>.
799+ * @see #putDouble(String,double)
800+ * @see #get(String,String)
801+ */
802+ public abstract double getDouble(String key, double def);
803+
804+ /**
805+ * Associates a string representing the specified byte array with the
806+ * specified key in this preference node. The associated string is
807+ * the <i>Base64</i> encoding of the byte array, as defined in <a
808+ * href=http://www.ietf.org/rfc/rfc2045.txt>RFC 2045</a>, Section 6.8,
809+ * with one minor change: the string will consist solely of characters
810+ * from the <i>Base64 Alphabet</i>; it will not contain any newline
811+ * characters. Note that the maximum length of the byte array is limited
812+ * to three quarters of <tt>MAX_VALUE_LENGTH</tt> so that the length
813+ * of the Base64 encoded String does not exceed <tt>MAX_VALUE_LENGTH</tt>.
814+ * This method is intended for use in conjunction with
815+ * {@link #getByteArray}.
816+ *
817+ * @param key key with which the string form of value is to be associated.
818+ * @param value value whose string form is to be associated with key.
819+ * @throws NullPointerException if key or value is <tt>null</tt>.
820+ * @throws IllegalArgumentException if key.length() exceeds MAX_KEY_LENGTH
821+ * or if value.length exceeds MAX_VALUE_LENGTH*3/4.
822+ * @throws IllegalStateException if this node (or an ancestor) has been
823+ * removed with the {@link #removeNode()} method.
824+ * @see #getByteArray(String,byte[])
825+ * @see #get(String,String)
826+ */
827+ public abstract void putByteArray(String key, byte[] value);
828+
829+ /**
830+ * Returns the byte array value represented by the string associated with
831+ * the specified key in this preference node. Valid strings are
832+ * <i>Base64</i> encoded binary data, as defined in <a
833+ * href=http://www.ietf.org/rfc/rfc2045.txt>RFC 2045</a>, Section 6.8,
834+ * with one minor change: the string must consist solely of characters
835+ * from the <i>Base64 Alphabet</i>; no newline characters or
836+ * extraneous characters are permitted. This method is intended for use
837+ * in conjunction with {@link #putByteArray}.
838+ *
839+ * <p>Returns the specified default if there is no value
840+ * associated with the key, the backing store is inaccessible, or if the
841+ * associated value is not a valid Base64 encoded byte array
842+ * (as defined above).
843+ *
844+ * <p>If the implementation supports <i>stored defaults</i> and such a
845+ * default exists and is accessible, it is used in preference to the
846+ * specified default, unless the stored default is not a valid Base64
847+ * encoded byte array (as defined above), in which case the
848+ * specified default is used.
849+ *
850+ * @param key key whose associated value is to be returned as a byte array.
851+ * @param def the value to be returned in the event that this
852+ * preference node has no value associated with <tt>key</tt>
853+ * or the associated value cannot be interpreted as a byte array,
854+ * or the backing store is inaccessible.
855+ * @return the byte array value represented by the string associated with
856+ * <tt>key</tt> in this preference node, or <tt>def</tt> if the
857+ * associated value does not exist or cannot be interpreted as
858+ * a byte array.
859+ * @throws IllegalStateException if this node (or an ancestor) has been
860+ * removed with the {@link #removeNode()} method.
861+ * @throws NullPointerException if <tt>key</tt> is <tt>null</tt>. (A
862+ * <tt>null</tt> value for <tt>def</tt> <i>is</i> permitted.)
863+ * @see #get(String,String)
864+ * @see #putByteArray(String,byte[])
865+ */
866+ public abstract byte[] getByteArray(String key, byte[] def);
867+
868+ /**
869+ * Returns all of the keys that have an associated value in this
870+ * preference node. (The returned array will be of size zero if
871+ * this node has no preferences.)
872+ *
873+ * <p>If the implementation supports <i>stored defaults</i> and there
874+ * are any such defaults at this node that have not been overridden,
875+ * by explicit preferences, the defaults are returned in the array in
876+ * addition to any explicit preferences.
877+ *
878+ * @return an array of the keys that have an associated value in this
879+ * preference node.
880+ * @throws BackingStoreException if this operation cannot be completed
881+ * due to a failure in the backing store, or inability to
882+ * communicate with it.
883+ * @throws IllegalStateException if this node (or an ancestor) has been
884+ * removed with the {@link #removeNode()} method.
885+ */
886+ public abstract String[] keys() throws BackingStoreException;
887+
888+ /**
889+ * Returns the names of the children of this preference node, relative to
890+ * this node. (The returned array will be of size zero if this node has
891+ * no children.)
892+ *
893+ * @return the names of the children of this preference node.
894+ * @throws BackingStoreException if this operation cannot be completed
895+ * due to a failure in the backing store, or inability to
896+ * communicate with it.
897+ * @throws IllegalStateException if this node (or an ancestor) has been
898+ * removed with the {@link #removeNode()} method.
899+ */
900+ public abstract String[] childrenNames() throws BackingStoreException;
901+
902+ /**
903+ * Returns the parent of this preference node, or <tt>null</tt> if this is
904+ * the root.
905+ *
906+ * @return the parent of this preference node.
907+ * @throws IllegalStateException if this node (or an ancestor) has been
908+ * removed with the {@link #removeNode()} method.
909+ */
910+ public abstract Preferences parent();
911+
912+ /**
913+ * Returns the named preference node in the same tree as this node,
914+ * creating it and any of its ancestors if they do not already exist.
915+ * Accepts a relative or absolute path name. Relative path names
916+ * (which do not begin with the slash character <tt>('/')</tt>) are
917+ * interpreted relative to this preference node.
918+ *
919+ * <p>If the returned node did not exist prior to this call, this node and
920+ * any ancestors that were created by this call are not guaranteed
921+ * to become permanent until the <tt>flush</tt> method is called on
922+ * the returned node (or one of its ancestors or descendants).
923+ *
924+ * @param pathName the path name of the preference node to return.
925+ * @return the specified preference node.
926+ * @throws IllegalArgumentException if the path name is invalid (i.e.,
927+ * it contains multiple consecutive slash characters, or ends
928+ * with a slash character and is more than one character long).
929+ * @throws NullPointerException if path name is <tt>null</tt>.
930+ * @throws IllegalStateException if this node (or an ancestor) has been
931+ * removed with the {@link #removeNode()} method.
932+ * @see #flush()
933+ */
934+ public abstract Preferences node(String pathName);
935+
936+ /**
937+ * Returns true if the named preference node exists in the same tree
938+ * as this node. Relative path names (which do not begin with the slash
939+ * character <tt>('/')</tt>) are interpreted relative to this preference
940+ * node.
941+ *
942+ * <p>If this node (or an ancestor) has already been removed with the
943+ * {@link #removeNode()} method, it <i>is</i> legal to invoke this method,
944+ * but only with the path name <tt>""</tt>; the invocation will return
945+ * <tt>false</tt>. Thus, the idiom <tt>p.nodeExists("")</tt> may be
946+ * used to test whether <tt>p</tt> has been removed.
947+ *
948+ * @param pathName the path name of the node whose existence
949+ * is to be checked.
950+ * @return true if the specified node exists.
951+ * @throws BackingStoreException if this operation cannot be completed
952+ * due to a failure in the backing store, or inability to
953+ * communicate with it.
954+ * @throws IllegalArgumentException if the path name is invalid (i.e.,
955+ * it contains multiple consecutive slash characters, or ends
956+ * with a slash character and is more than one character long).
957+ * @throws NullPointerException if path name is <tt>null</tt>.
958+ * @throws IllegalStateException if this node (or an ancestor) has been
959+ * removed with the {@link #removeNode()} method and
960+ * <tt>pathName</tt> is not the empty string (<tt>""</tt>).
961+ */
962+ public abstract boolean nodeExists(String pathName)
963+ throws BackingStoreException;
964+
965+ /**
966+ * Removes this preference node and all of its descendants, invalidating
967+ * any preferences contained in the removed nodes. Once a node has been
968+ * removed, attempting any method other than {@link #name()},
969+ * {@link #absolutePath()}, {@link #isUserNode()}, {@link #flush()} or
970+ * {@link #node(String) nodeExists("")} on the corresponding
971+ * <tt>Preferences</tt> instance will fail with an
972+ * <tt>IllegalStateException</tt>. (The methods defined on {@link Object}
973+ * can still be invoked on a node after it has been removed; they will not
974+ * throw <tt>IllegalStateException</tt>.)
975+ *
976+ * <p>The removal is not guaranteed to be persistent until the
977+ * <tt>flush</tt> method is called on this node (or an ancestor).
978+ *
979+ * <p>If this implementation supports <i>stored defaults</i>, removing a
980+ * node exposes any stored defaults at or below this node. Thus, a
981+ * subsequent call to <tt>nodeExists</tt> on this node's path name may
982+ * return <tt>true</tt>, and a subsequent call to <tt>node</tt> on this
983+ * path name may return a (different) <tt>Preferences</tt> instance
984+ * representing a non-empty collection of preferences and/or children.
985+ *
986+ * @throws BackingStoreException if this operation cannot be completed
987+ * due to a failure in the backing store, or inability to
988+ * communicate with it.
989+ * @throws IllegalStateException if this node (or an ancestor) has already
990+ * been removed with the {@link #removeNode()} method.
991+ * @throws UnsupportedOperationException if this method is invoked on
992+ * the root node.
993+ * @see #flush()
994+ */
995+ public abstract void removeNode() throws BackingStoreException;
996+
997+ /**
998+ * Returns this preference node's name, relative to its parent.
999+ *
1000+ * @return this preference node's name, relative to its parent.
1001+ */
1002+ public abstract String name();
1003+
1004+ /**
1005+ * Returns this preference node's absolute path name.
1006+ *
1007+ * @return this preference node's absolute path name.
1008+ */
1009+ public abstract String absolutePath();
1010+
1011+ /**
1012+ * Returns <tt>true</tt> if this preference node is in the user
1013+ * preference tree, <tt>false</tt> if it's in the system preference tree.
1014+ *
1015+ * @return <tt>true</tt> if this preference node is in the user
1016+ * preference tree, <tt>false</tt> if it's in the system
1017+ * preference tree.
1018+ */
1019+ public abstract boolean isUserNode();
1020+
1021+ /**
1022+ * Returns a string representation of this preferences node,
1023+ * as if computed by the expression:<tt>(this.isUserNode() ? "User" :
1024+ * "System") + " Preference Node: " + this.absolutePath()</tt>.
1025+ */
1026+ public abstract String toString();
1027+
1028+ /**
1029+ * Forces any changes in the contents of this preference node and its
1030+ * descendants to the persistent store. Once this method returns
1031+ * successfully, it is safe to assume that all changes made in the
1032+ * subtree rooted at this node prior to the method invocation have become
1033+ * permanent.
1034+ *
1035+ * <p>Implementations are free to flush changes into the persistent store
1036+ * at any time. They do not need to wait for this method to be called.
1037+ *
1038+ * <p>When a flush occurs on a newly created node, it is made persistent,
1039+ * as are any ancestors (and descendants) that have yet to be made
1040+ * persistent. Note however that any preference value changes in
1041+ * ancestors are <i>not</i> guaranteed to be made persistent.
1042+ *
1043+ * <p> If this method is invoked on a node that has been removed with
1044+ * the {@link #removeNode()} method, flushSpi() is invoked on this node,
1045+ * but not on others.
1046+ *
1047+ * @throws BackingStoreException if this operation cannot be completed
1048+ * due to a failure in the backing store, or inability to
1049+ * communicate with it.
1050+ * @see #sync()
1051+ */
1052+ public abstract void flush() throws BackingStoreException;
1053+
1054+ /**
1055+ * Ensures that future reads from this preference node and its
1056+ * descendants reflect any changes that were committed to the persistent
1057+ * store (from any VM) prior to the <tt>sync</tt> invocation. As a
1058+ * side-effect, forces any changes in the contents of this preference node
1059+ * and its descendants to the persistent store, as if the <tt>flush</tt>
1060+ * method had been invoked on this node.
1061+ *
1062+ * @throws BackingStoreException if this operation cannot be completed
1063+ * due to a failure in the backing store, or inability to
1064+ * communicate with it.
1065+ * @throws IllegalStateException if this node (or an ancestor) has been
1066+ * removed with the {@link #removeNode()} method.
1067+ * @see #flush()
1068+ */
1069+ public abstract void sync() throws BackingStoreException;
1070+
1071+ /**
1072+ * Registers the specified listener to receive <i>preference change
1073+ * events</i> for this preference node. A preference change event is
1074+ * generated when a preference is added to this node, removed from this
1075+ * node, or when the value associated with a preference is changed.
1076+ * (Preference change events are <i>not</i> generated by the {@link
1077+ * #removeNode()} method, which generates a <i>node change event</i>.
1078+ * Preference change events <i>are</i> generated by the <tt>clear</tt>
1079+ * method.)
1080+ *
1081+ * <p>Events are only guaranteed for changes made within the same JVM
1082+ * as the registered listener, though some implementations may generate
1083+ * events for changes made outside this JVM. Events may be generated
1084+ * before the changes have been made persistent. Events are not generated
1085+ * when preferences are modified in descendants of this node; a caller
1086+ * desiring such events must register with each descendant.
1087+ *
1088+ * @param pcl The preference change listener to add.
1089+ * @throws NullPointerException if <tt>pcl</tt> is null.
1090+ * @throws IllegalStateException if this node (or an ancestor) has been
1091+ * removed with the {@link #removeNode()} method.
1092+ * @see #removePreferenceChangeListener(PreferenceChangeListener)
1093+ * @see #addNodeChangeListener(NodeChangeListener)
1094+ */
1095+ public abstract void addPreferenceChangeListener(
1096+ PreferenceChangeListener pcl);
1097+
1098+ /**
1099+ * Removes the specified preference change listener, so it no longer
1100+ * receives preference change events.
1101+ *
1102+ * @param pcl The preference change listener to remove.
1103+ * @throws IllegalArgumentException if <tt>pcl</tt> was not a registered
1104+ * preference change listener on this node.
1105+ * @throws IllegalStateException if this node (or an ancestor) has been
1106+ * removed with the {@link #removeNode()} method.
1107+ * @see #addPreferenceChangeListener(PreferenceChangeListener)
1108+ */
1109+ public abstract void removePreferenceChangeListener(
1110+ PreferenceChangeListener pcl);
1111+
1112+ /**
1113+ * Registers the specified listener to receive <i>node change events</i>
1114+ * for this node. A node change event is generated when a child node is
1115+ * added to or removed from this node. (A single {@link #removeNode()}
1116+ * invocation results in multiple <i>node change events</i>, one for every
1117+ * node in the subtree rooted at the removed node.)
1118+ *
1119+ * <p>Events are only guaranteed for changes made within the same JVM
1120+ * as the registered listener, though some implementations may generate
1121+ * events for changes made outside this JVM. Events may be generated
1122+ * before the changes have become permanent. Events are not generated
1123+ * when indirect descendants of this node are added or removed; a
1124+ * caller desiring such events must register with each descendant.
1125+ *
1126+ * <p>Few guarantees can be made regarding node creation. Because nodes
1127+ * are created implicitly upon access, it may not be feasible for an
1128+ * implementation to determine whether a child node existed in the backing
1129+ * store prior to access (for example, because the backing store is
1130+ * unreachable or cached information is out of date). Under these
1131+ * circumstances, implementations are neither required to generate node
1132+ * change events nor prohibited from doing so.
1133+ *
1134+ * @param ncl The <tt>NodeChangeListener</tt> to add.
1135+ * @throws NullPointerException if <tt>ncl</tt> is null.
1136+ * @throws IllegalStateException if this node (or an ancestor) has been
1137+ * removed with the {@link #removeNode()} method.
1138+ * @see #removeNodeChangeListener(NodeChangeListener)
1139+ * @see #addPreferenceChangeListener(PreferenceChangeListener)
1140+ */
1141+ public abstract void addNodeChangeListener(NodeChangeListener ncl);
1142+
1143+ /**
1144+ * Removes the specified <tt>NodeChangeListener</tt>, so it no longer
1145+ * receives change events.
1146+ *
1147+ * @param ncl The <tt>NodeChangeListener</tt> to remove.
1148+ * @throws IllegalArgumentException if <tt>ncl</tt> was not a registered
1149+ * <tt>NodeChangeListener</tt> on this node.
1150+ * @throws IllegalStateException if this node (or an ancestor) has been
1151+ * removed with the {@link #removeNode()} method.
1152+ * @see #addNodeChangeListener(NodeChangeListener)
1153+ */
1154+ public abstract void removeNodeChangeListener(NodeChangeListener ncl);
1155+
1156+ /**
1157+ * Emits on the specified output stream an XML document representing all
1158+ * of the preferences contained in this node (but not its descendants).
1159+ * This XML document is, in effect, an offline backup of the node.
1160+ *
1161+ * <p>The XML document will have the following DOCTYPE declaration:
1162+ * <pre>
1163+ * &lt;!DOCTYPE preferences SYSTEM "http://java.sun.com/dtd/preferences.dtd"&gt;
1164+ * </pre>
1165+ * The UTF-8 character encoding will be used.
1166+ *
1167+ * <p>This method is an exception to the general rule that the results of
1168+ * concurrently executing multiple methods in this class yields
1169+ * results equivalent to some serial execution. If the preferences
1170+ * at this node are modified concurrently with an invocation of this
1171+ * method, the exported preferences comprise a "fuzzy snapshot" of the
1172+ * preferences contained in the node; some of the concurrent modifications
1173+ * may be reflected in the exported data while others may not.
1174+ *
1175+ * @param os the output stream on which to emit the XML document.
1176+ * @throws IOException if writing to the specified output stream
1177+ * results in an <tt>IOException</tt>.
1178+ * @throws BackingStoreException if preference data cannot be read from
1179+ * backing store.
1180+ * @see #importPreferences(InputStream)
1181+ * @throws IllegalStateException if this node (or an ancestor) has been
1182+ * removed with the {@link #removeNode()} method.
1183+ */
1184+ public abstract void exportNode(OutputStream os)
1185+ throws IOException, BackingStoreException;
1186+
1187+ /**
1188+ * Emits an XML document representing all of the preferences contained
1189+ * in this node and all of its descendants. This XML document is, in
1190+ * effect, an offline backup of the subtree rooted at the node.
1191+ *
1192+ * <p>The XML document will have the following DOCTYPE declaration:
1193+ * <pre>
1194+ * &lt;!DOCTYPE preferences SYSTEM "http://java.sun.com/dtd/preferences.dtd"&gt;
1195+ * </pre>
1196+ * The UTF-8 character encoding will be used.
1197+ *
1198+ * <p>This method is an exception to the general rule that the results of
1199+ * concurrently executing multiple methods in this class yields
1200+ * results equivalent to some serial execution. If the preferences
1201+ * or nodes in the subtree rooted at this node are modified concurrently
1202+ * with an invocation of this method, the exported preferences comprise a
1203+ * "fuzzy snapshot" of the subtree; some of the concurrent modifications
1204+ * may be reflected in the exported data while others may not.
1205+ *
1206+ * @param os the output stream on which to emit the XML document.
1207+ * @throws IOException if writing to the specified output stream
1208+ * results in an <tt>IOException</tt>.
1209+ * @throws BackingStoreException if preference data cannot be read from
1210+ * backing store.
1211+ * @throws IllegalStateException if this node (or an ancestor) has been
1212+ * removed with the {@link #removeNode()} method.
1213+ * @see #importPreferences(InputStream)
1214+ * @see #exportNode(OutputStream)
1215+ */
1216+ public abstract void exportSubtree(OutputStream os)
1217+ throws IOException, BackingStoreException;
1218+
1219+ /**
1220+ * Imports all of the preferences represented by the XML document on the
1221+ * specified input stream. The document may represent user preferences or
1222+ * system preferences. If it represents user preferences, the preferences
1223+ * will be imported into the calling user's preference tree (even if they
1224+ * originally came from a different user's preference tree). If any of
1225+ * the preferences described by the document inhabit preference nodes that
1226+ * do not exist, the nodes will be created.
1227+ *
1228+ * <p>The XML document must have the following DOCTYPE declaration:
1229+ * <pre>
1230+ * &lt;!DOCTYPE preferences SYSTEM "http://java.sun.com/dtd/preferences.dtd"&gt;
1231+ * </pre>
1232+ * (This method is designed for use in conjunction with
1233+ * {@link #exportNode(OutputStream)} and
1234+ * {@link #exportSubtree(OutputStream)}.
1235+ *
1236+ * <p>This method is an exception to the general rule that the results of
1237+ * concurrently executing multiple methods in this class yields
1238+ * results equivalent to some serial execution. The method behaves
1239+ * as if implemented on top of the other public methods in this class,
1240+ * notably {@link #node(String)} and {@link #put(String, String)}.
1241+ *
1242+ * @param is the input stream from which to read the XML document.
1243+ * @throws IOException if reading from the specified input stream
1244+ * results in an <tt>IOException</tt>.
1245+ * @throws InvalidPreferencesFormatException Data on input stream does not
1246+ * constitute a valid XML document with the mandated document type.
1247+ * @throws SecurityException If a security manager is present and
1248+ * it denies <tt>RuntimePermission("preferences")</tt>.
1249+ * @see RuntimePermission
1250+ */
1251+ public static void importPreferences(InputStream is)
1252+ throws IOException, InvalidPreferencesFormatException
1253+ {
1254+ XmlSupport.importPreferences(is);
1255+ }
1256+}