1 /*
2 * Copyright 2000-2006 Sun Microsystems, Inc. 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. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any 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><node
77 * name></i>. All other nodes have absolute path names of <i><parent's
78 * absolute path name></i><tt> + "/" + </tt><i><node name></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 * <!DOCTYPE preferences SYSTEM "http://java.sun.com/dtd/preferences.dtd">
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 * <?xml version="1.0" encoding="UTF-8"?>
145 *
146 * <!-- DTD for a Preferences tree. -->
147 *
148 * <!-- The preferences element is at the root of an XML document
149 * representing a Preferences tree. -->
150 * <!ELEMENT preferences (root)>
151 *
152 * <!-- The preferences element contains an optional version attribute,
153 * which specifies version of DTD. -->
154 * <!ATTLIST preferences EXTERNAL_XML_VERSION CDATA "0.0" >
155 *
156 * <!-- 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). -->
158 * <!ELEMENT root (map, node*) >
159 *
160 * <!-- Additionally, the root contains a type attribute, which
161 * specifies whether it's the system or user root. -->
162 * <!ATTLIST root
163 * type (system|user) #REQUIRED >
164 *
165 * <!-- Each node has a map representing its preferences (if any),
166 * and one node for each child (if any). -->
167 * <!ELEMENT node (map, node*) >
168 *
169 * <!-- Additionally, each node has a name attribute -->
170 * <!ATTLIST node
171 * name CDATA #REQUIRED >
172 *
173 * <!-- A map represents the preferences stored at a node (if any). -->
174 * <!ELEMENT map (entry*) >
175 *
176 * <!-- An entry represents a single preference, which is simply
177 * a key-value pair. -->
178 * <!ELEMENT entry EMPTY >
179 * <!ATTLIST entry
180 * key CDATA #REQUIRED
181 * value CDATA #REQUIRED >
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><unnamed></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><unnamed></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 * <!DOCTYPE preferences SYSTEM "http://java.sun.com/dtd/preferences.dtd">
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 * <!DOCTYPE preferences SYSTEM "http://java.sun.com/dtd/preferences.dtd">
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 * <!DOCTYPE preferences SYSTEM "http://java.sun.com/dtd/preferences.dtd">
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 }