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