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