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