1/* Licensed to the Apache Software Foundation (ASF) under one or more 2 * contributor license agreements. See the NOTICE file distributed with 3 * this work for additional information regarding copyright ownership. 4 * The ASF licenses this file to You under the Apache License, Version 2.0 5 * (the "License"); you may not use this file except in compliance with 6 * the License. You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package java.util.prefs; 18 19import java.io.IOException; 20import java.io.InputStream; 21import java.io.OutputStream; 22import java.net.MalformedURLException; 23import java.util.ServiceLoader; 24 25/** 26 * An instance of the class {@code Preferences} represents one node in a 27 * preference tree, which provides a mechanism to store and access configuration 28 * data in a hierarchical way. Two hierarchy trees are maintained, one for 29 * system preferences shared by all users and the other for user preferences 30 * specific to the user. {@code Preferences} hierarchy trees and data are stored 31 * in an implementation-dependent back-end. 32 * <p> 33 * Every node has one name and one unique absolute path following the same 34 * notational conventions as directories in a file system. The root node's 35 * name is "", and other node name strings cannot contain the slash character 36 * and cannot be empty. The root node's absolute path is "/", and all other 37 * nodes' absolute paths are constructed in the standard way: <parent's 38 * absolute path> + "/" + <node's name>. Since the set of nodes forms a 39 * tree with the root node at its base, all absolute paths start with the slash 40 * character. Every node has one relative path to each of its ancestors. The 41 * relative path doesn't start with slash: it equals the node's absolute path 42 * with leading substring removed corresponding to the ancestor's absolute path 43 * and a slash. 44 * <p> 45 * Modification to preferences data may be asynchronous, which means that 46 * preference update method calls may return immediately instead of blocking. 47 * The {@code flush()} and {@code sync()} methods force the back-end to 48 * synchronously perform all pending updates, but the implementation is 49 * permitted to perform the modifications on the underlying back-end data 50 * at any time between the moment the request is made and the moment the 51 * {@code flush()} or {@code sync()} method returns. Please note that if the JVM 52 * exits normally, the implementation must assure all modifications are 53 * persisted implicitly. 54 * <p> 55 * When invoking a method that retrieves preferences, the user must provide 56 * a default value. The default value is returned when the preferences cannot 57 * be found or the back-end is unavailable. Some other methods will throw 58 * {@code BackingStoreException} when the back-end is unavailable. 59 * </p> 60 * <p> 61 * Preferences can be exported to and imported from an XML files. These 62 * documents must have an XML DOCTYPE declaration: 63 * <pre>{@code 64 * <!DOCTYPE preferences SYSTEM "http://java.sun.com/dtd/preferences.dtd"> 65 * }</pre> 66 * This system URI is not really accessed by network, it is only a 67 * identification string. Visit the DTD location to see the actual format 68 * permitted. 69 * <p> 70 * There must be a concrete {@code PreferencesFactory} type for every concrete 71 * {@code Preferences} type developed. Every J2SE implementation must provide a 72 * default implementation for every supported platform, and must also provide a 73 * means of replacing the default implementation. This implementation uses the 74 * system property {@code java.util.prefs.PreferencesFactory} to determine which 75 * preferences implementation to use. 76 * <p> 77 * The methods of this class are thread-safe. If multiple JVMs are using the 78 * same back-end concurrently, the back-end won't be corrupted, but no other 79 * behavior guarantees are made. 80 * 81 * @see PreferencesFactory 82 * 83 * @since 1.4 84 */ 85public abstract class Preferences { 86 /** 87 * Maximum size in characters allowed for a preferences key. 88 */ 89 public static final int MAX_KEY_LENGTH = 80; 90 91 /** 92 * Maximum size in characters allowed for a preferences name. 93 */ 94 public static final int MAX_NAME_LENGTH = 80; 95 96 /** 97 * Maximum size in characters allowed for a preferences value. 98 */ 99 public static final int MAX_VALUE_LENGTH = 8192; 100 101 // factory used to get user/system prefs root 102 private static volatile PreferencesFactory factory = findPreferencesFactory(); 103 104 /** 105 * @hide for testing only. 106 */ 107 public static PreferencesFactory setPreferencesFactory(PreferencesFactory pf) { 108 PreferencesFactory previous = factory; 109 factory = pf; 110 return previous; 111 } 112 113 private static PreferencesFactory findPreferencesFactory() { 114 // Try the system property first... 115 PreferencesFactory result = ServiceLoader.loadFromSystemProperty(PreferencesFactory.class); 116 if (result != null) { 117 return result; 118 } 119 // Then use ServiceLoader for META-INF/services/... 120 for (PreferencesFactory impl : ServiceLoader.load(PreferencesFactory.class)) { 121 return impl; 122 } 123 // Finally return a default... 124 return new FilePreferencesFactoryImpl(); 125 } 126 127 /** 128 * Default constructor, for use by subclasses only. 129 */ 130 protected Preferences() { 131 } 132 133 /** 134 * Gets the absolute path string of this preference node. 135 * 136 * @return the preference node's absolute path string. 137 */ 138 public abstract String absolutePath(); 139 140 /** 141 * Returns the names of all children of this node or an empty array if this 142 * node has no children. 143 * 144 * @return the names of all children of this node. 145 * @throws BackingStoreException 146 * if backing store is unavailable or causes an operation 147 * failure. 148 * @throws IllegalStateException 149 * if this node has been removed. 150 */ 151 public abstract String[] childrenNames() throws BackingStoreException; 152 153 /** 154 * Removes all preferences of this node. 155 * 156 * @throws BackingStoreException 157 * if backing store is unavailable or causes an operation 158 * failure. 159 * @throws IllegalStateException 160 * if this node has been removed. 161 */ 162 public abstract void clear() throws BackingStoreException; 163 164 /** 165 * Exports all of the preferences of this node to a XML document using the 166 * given output stream. 167 * <p> 168 * This XML document uses the UTF-8 encoding and is written according to the 169 * DTD in its DOCTYPE declaration, which is the following: 170 * 171 * <pre> 172 * <!DOCTYPE preferences SYSTEM "http://java.sun.com/dtd/preferences.dtd"> 173 * </pre> 174 * 175 * <i>Please note that (unlike the methods of this class that don't concern 176 * serialization), this call is not thread-safe.</i> 177 * </p> 178 * 179 * @param ostream 180 * the output stream to write the XML-formatted data to. 181 * @throws IOException 182 * if an error occurs while exporting. 183 * @throws BackingStoreException 184 * if the backing store is unavailable or causes an operation 185 * failure. 186 * @throws IllegalStateException 187 * if this node has been removed. 188 */ 189 public abstract void exportNode(OutputStream ostream) throws IOException, BackingStoreException; 190 191 /** 192 * Exports all of the preferences of this node and all its descendants to a 193 * XML document using the given output stream. 194 * <p> 195 * This XML document uses the UTF-8 encoding and is written according to the 196 * DTD in its DOCTYPE declaration, which is the following: 197 * 198 * <pre> 199 * <!DOCTYPE preferences SYSTEM "http://java.sun.com/dtd/preferences.dtd"> 200 * </pre> 201 * 202 * <i>Please note that (unlike the methods of this class that don't concern 203 * serialization), this call is not thread-safe.</i> 204 * </p> 205 * 206 * @param ostream 207 * the output stream to write the XML-formatted data to. 208 * @throws IOException 209 * if an error occurs while exporting. 210 * @throws BackingStoreException 211 * if the backing store is unavailable or causes an operation 212 * failure. 213 * @throws IllegalStateException 214 * if this node has been removed. 215 */ 216 public abstract void exportSubtree(OutputStream ostream) throws IOException, 217 BackingStoreException; 218 219 /** 220 * Forces all pending updates to this node and its descendants to be 221 * persisted in the backing store. 222 * <p> 223 * If this node has been removed, the invocation of this method only flushes 224 * this node, not its descendants. 225 * </p> 226 * 227 * @throws BackingStoreException 228 * if the backing store is unavailable or causes an operation 229 * failure. 230 */ 231 public abstract void flush() throws BackingStoreException; 232 233 /** 234 * Gets the {@code String} value mapped to the given key or its default 235 * value if no value is mapped or no backing store is available. 236 * <p> 237 * Some implementations may store default values in backing stores. In this 238 * case, if there is no value mapped to the given key, the stored default 239 * value is returned. 240 * </p> 241 * 242 * @param key 243 * the preference key. 244 * @param deflt 245 * the default value, which will be returned if no value is 246 * mapped to the given key or no backing store is available. 247 * @return the preference value mapped to the given key. 248 * @throws IllegalStateException 249 * if this node has been removed. 250 * @throws NullPointerException 251 * if the parameter {@code key} is {@code null}. 252 */ 253 public abstract String get(String key, String deflt); 254 255 /** 256 * Gets the {@code boolean} value mapped to the given key or its default 257 * value if no value is mapped, if the backing store is unavailable, or if 258 * the value is invalid. 259 * <p> 260 * The only valid values are the {@code String} "true", which represents 261 * {@code true} and "false", which represents {@code false}, ignoring case. 262 * </p> 263 * <p> 264 * Some implementations may store default values in backing stores. In this 265 * case, if there is no value mapped to the given key, the stored default 266 * value is returned. 267 * </p> 268 * 269 * @param key 270 * the preference key. 271 * @param deflt 272 * the default value, which will be returned if no value is 273 * mapped to the given key, if the backing store is unavailable, 274 * or if the value is invalid. 275 * @return the boolean value mapped to the given key. 276 * @throws IllegalStateException 277 * if this node has been removed. 278 * @throws NullPointerException 279 * if the parameter {@code key} is {@code null}. 280 */ 281 public abstract boolean getBoolean(String key, boolean deflt); 282 283 /** 284 * Gets the {@code byte} array value mapped to the given key or its default 285 * value if no value is mapped, if the backing store is unavailable, or if 286 * the value is an invalid string. 287 * <p> 288 * To be valid, the value string must be Base64-encoded binary data. The 289 * Base64 encoding is as defined in <a 290 * href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045</a>, section 6.8. 291 * </p> 292 * <p> 293 * Some implementations may store default values in backing stores. In this 294 * case, if there is no value mapped to the given key, the stored default 295 * value is returned. 296 * </p> 297 * 298 * @param key 299 * the preference key. 300 * @param deflt 301 * the default value, which will be returned if no value is 302 * mapped to the given key, if the backing store is unavailable, 303 * or if the value is invalid. 304 * @return the byte array value mapped to the given key. 305 * @throws IllegalStateException 306 * if this node has been removed. 307 * @throws NullPointerException 308 * if the parameter {@code key} is {@code null}. 309 */ 310 public abstract byte[] getByteArray(String key, byte[] deflt); 311 312 /** 313 * Gets the {@code double} value mapped to the given key or its default 314 * value if no value is mapped, if the backing store is unavailable, or if 315 * the value is an invalid string. 316 * <p> 317 * To be valid, the value string must be a string that can be converted to a 318 * {@code double} by {@link Double#parseDouble(String) 319 * Double.parseDouble(String)}. 320 * <p> 321 * Some implementations may store default values in backing stores. In this 322 * case, if there is no value mapped to the given key, the stored default 323 * value is returned. 324 * </p> 325 * 326 * @param key 327 * the preference key. 328 * @param deflt 329 * the default value, which will be returned if no value is 330 * mapped to the given key, if the backing store is unavailable, or if the 331 * value is invalid. 332 * @return the double value mapped to the given key. 333 * @throws IllegalStateException 334 * if this node has been removed. 335 * @throws NullPointerException 336 * if the parameter {@code key} is {@code null}. 337 */ 338 public abstract double getDouble(String key, double deflt); 339 340 /** 341 * Gets the {@code float} value mapped to the given key or its default value 342 * if no value is mapped, if the backing store is unavailable, or if the 343 * value is an invalid string. 344 * <p> 345 * To be valid, the value string must be a string that can be converted to a 346 * {@code float} by {@link Float#parseFloat(String) 347 * Float.parseFloat(String)}. 348 * </p> 349 * <p> 350 * Some implementations may store default values in backing stores. In this 351 * case, if there is no value mapped to the given key, the stored default 352 * value is returned. 353 * </p> 354 * 355 * @param key 356 * the preference key. 357 * @param deflt 358 * the default value, which will be returned if no value is 359 * mapped to the given key, if the backing store is unavailable, or if the 360 * value is invalid. 361 * @return the float value mapped to the given key. 362 * @throws IllegalStateException 363 * if this node has been removed. 364 * @throws NullPointerException 365 * if the parameter {@code key} is {@code null}. 366 */ 367 public abstract float getFloat(String key, float deflt); 368 369 /** 370 * Gets the {@code int} value mapped to the given key or its default value 371 * if no value is mapped, if the backing store is unavailable, or if the 372 * value is an invalid string. 373 * <p> 374 * To be valid, the value string must be a string that can be converted to 375 * an {@code int} by {@link Integer#parseInt(String) 376 * Integer.parseInt(String)}. 377 * </p> 378 * <p> 379 * Some implementations may store default values in backing stores. In this 380 * case, if there is no value mapped to the given key, the stored default 381 * value is returned. 382 * </p> 383 * 384 * @param key 385 * the preference key. 386 * @param deflt 387 * the default value, which will be returned if no value is 388 * mapped to the given key, if the backing store is unavailable, 389 * or if the value is invalid. 390 * @return the integer value mapped to the given key. 391 * @throws IllegalStateException 392 * if this node has been removed. 393 * @throws NullPointerException 394 * if the parameter {@code key} is {@code null}. 395 */ 396 public abstract int getInt(String key, int deflt); 397 398 /** 399 * Gets the {@code long} value mapped to the given key or its default value 400 * if no value is mapped, if the backing store is unavailable, or if the 401 * value is an invalid string. 402 * <p> 403 * To be valid, the value string must be a string that can be converted to a 404 * {@code long} by {@link Long#parseLong(String) Long.parseLong(String)}. 405 * </p> 406 * <p> 407 * Some implementations may store default values in backing stores. In this 408 * case, if there is no value mapped to the given key, the stored default 409 * value is returned. 410 * </p> 411 * 412 * @param key 413 * the preference key. 414 * @param deflt 415 * the default value, which will be returned if no value is 416 * mapped to the given key, if the backing store is unavailable, 417 * or if the value is invalid. 418 * @return the long value mapped to the given key. 419 * @throws IllegalStateException 420 * if this node has been removed. 421 * @throws NullPointerException 422 * if the parameter {@code key} is {@code null}. 423 */ 424 public abstract long getLong(String key, long deflt); 425 426 /** 427 * Imports all the preferences from an XML document using the given input 428 * stream. 429 * <p> 430 * This XML document uses the UTF-8 encoding and must be written according 431 * to the DTD in its DOCTYPE declaration, which must be the following: 432 * 433 * <pre> 434 * <!DOCTYPE preferences SYSTEM "http://java.sun.com/dtd/preferences.dtd"> 435 * </pre> 436 * 437 * <i>Please note that (unlike the methods of this class that don't concern 438 * serialization), this call is not thread-safe.</i> 439 * </p> 440 * 441 * @param istream 442 * the input stream to read the data from. 443 * @throws InvalidPreferencesFormatException 444 * if the data read from the given input stream is not from a 445 * valid XML document. 446 * @throws IOException 447 * if an error occurs while importing. 448 */ 449 public static void importPreferences (InputStream istream) throws InvalidPreferencesFormatException, IOException { 450 if (istream == null){ 451 throw new MalformedURLException("Inputstream cannot be null"); 452 } 453 XMLParser.importPrefs(istream); 454 } 455 456 /** 457 * Returns whether this is a user preference node. 458 * 459 * @return {@code true}, if this is a user preference node, {@code false} if 460 * this is a system preference node. 461 */ 462 public abstract boolean isUserNode(); 463 464 /** 465 * Returns all preference keys stored in this node or an empty array if no 466 * key was found. 467 * 468 * @return the list of all preference keys of this node. 469 * @throws BackingStoreException 470 * if the backing store is unavailable or causes an operation 471 * failure. 472 * @throws IllegalStateException 473 * if this node has been removed. 474 */ 475 public abstract String[] keys() throws BackingStoreException; 476 477 /** 478 * Returns the name of this node. 479 * 480 * @return the name of this node. 481 */ 482 public abstract String name(); 483 484 /** 485 * Returns the preference node with the given path name. The path name can 486 * be relative or absolute. The requested node and its ancestors will 487 * be created if they do not exist. 488 * <p> 489 * The path is treated as relative to this node if it doesn't start with a 490 * slash, otherwise it will be treated as an absolute path. 491 * </p> 492 * 493 * @param path 494 * the path name of the requested preference node. 495 * @return the requested preference node. 496 * @throws IllegalStateException 497 * if this node has been removed. 498 * @throws IllegalArgumentException 499 * if the path name is invalid. 500 * @throws NullPointerException 501 * if the given path is {@code null}. 502 */ 503 public abstract Preferences node(String path); 504 505 /** 506 * Returns whether the preference node with the given path name exists. The 507 * path is treated as relative to this node if it doesn't start with a slash, 508 * otherwise it is treated as an absolute path. 509 * <p> 510 * Please note that if this node has been removed, an invocation of this 511 * node will throw an {@code IllegalStateException} unless the given path is 512 * an empty string, which will return {@code false}. 513 * </p> 514 * 515 * @param path 516 * the path name of the preference node to query. 517 * @return {@code true}, if the queried preference node exists, {@code false} 518 * otherwise. 519 * @throws IllegalStateException 520 * if this node has been removed and the path is not an empty 521 * string. 522 * @throws IllegalArgumentException 523 * if the path name is invalid. 524 * @throws NullPointerException 525 * if the given path is {@code null}. 526 * @throws BackingStoreException 527 * if the backing store is unavailable or causes an operation 528 * failure. 529 */ 530 public abstract boolean nodeExists(String path) throws BackingStoreException; 531 532 /** 533 * Returns the parent preference node of this node or {@code null} if this 534 * node is the root node. 535 * 536 * @return the parent preference node of this node. 537 * @throws IllegalStateException 538 * if this node has been removed. 539 */ 540 public abstract Preferences parent(); 541 542 /** 543 * Adds a new preference to this node using the given key and value or 544 * updates the value if a preference with the given key already exists. 545 * 546 * @param key 547 * the preference key to be added or updated. 548 * @param value 549 * the preference value for the given key. 550 * @throws NullPointerException 551 * if the given key or value is {@code null}. 552 * @throws IllegalArgumentException 553 * if the given key's length is bigger than {@code 554 * MAX_KEY_LENGTH} or the value's length is bigger than {@code 555 * MAX_VALUE_LENGTH}. 556 * @throws IllegalStateException 557 * if this node has been removed. 558 */ 559 public abstract void put(String key, String value); 560 561 /** 562 * Adds a new preference with a {@code boolean} value to this node using the 563 * given key and value or updates the value if a preference with the given 564 * key already exists. 565 * 566 * @param key 567 * the preference key to be added or updated. 568 * @param value 569 * the preference {@code boolean} value for the given key. 570 * @throws NullPointerException 571 * if the given key is {@code null}. 572 * @throws IllegalArgumentException 573 * if the given key's length is bigger than {@code 574 * MAX_KEY_LENGTH}. 575 * @throws IllegalStateException 576 * if this node has been removed. 577 */ 578 public abstract void putBoolean(String key, boolean value); 579 580 /** 581 * Adds a new preference to this node using the given key and the string 582 * form of the given value or updates the value if a preference with the 583 * given key already exists. 584 * <p> 585 * The string form of the value is the Base64-encoded binary data of the 586 * given byte array. The Base64 encoding is as defined in <a 587 * href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045</a>, section 6.8. 588 * </p> 589 * 590 * @param key 591 * the preference key to be added or updated. 592 * @param value 593 * the preference value for the given key. 594 * @throws NullPointerException 595 * if the given key or value is {@code null}. 596 * @throws IllegalArgumentException 597 * if the given key's length is bigger than {@code 598 * MAX_KEY_LENGTH} or value's length is bigger than three 599 * quarters of {@code MAX_KEY_LENGTH}. 600 * @throws IllegalStateException 601 * if this node has been removed. 602 */ 603 public abstract void putByteArray(String key, byte[] value); 604 605 /** 606 * Adds a new preference to this node using the given key and {@code double} 607 * value or updates the value if a preference with the 608 * given key already exists. 609 * <p> 610 * The value is stored in its string form, which is the result of invoking 611 * {@link Double#toString(double) Double.toString(double)}. 612 * </p> 613 * 614 * @param key 615 * the preference key to be added or updated. 616 * @param value 617 * the preference value for the given key. 618 * @throws NullPointerException 619 * if the given key is {@code null}. 620 * @throws IllegalArgumentException 621 * if the given key's length is bigger than {@code 622 * MAX_KEY_LENGTH}. 623 * @throws IllegalStateException 624 * if this node has been removed. 625 */ 626 public abstract void putDouble(String key, double value); 627 628 /** 629 * Adds a new preference to this node using the given key and {@code float} 630 * value or updates the value if a preference with the 631 * given key already exists. 632 * <p> 633 * The value is stored in its string form, which is the result of invoking 634 * {@link Float#toString(float) Float.toString(float)}. 635 * </p> 636 * 637 * @param key 638 * the preference key to be added or updated. 639 * @param value 640 * the preference value for the given key. 641 * @throws NullPointerException 642 * if the given key is {@code null}. 643 * @throws IllegalArgumentException 644 * if the given key's length is bigger than {@code 645 * MAX_KEY_LENGTH}. 646 * @throws IllegalStateException 647 * if this node has been removed. 648 */ 649 public abstract void putFloat(String key, float value); 650 651 /** 652 * Adds a new preference to this node using the given key and {@code int} 653 * value or updates the value if a preference with the 654 * given key already exists. 655 * <p> 656 * The value is stored in its string form, which is the result of invoking 657 * {@link Integer#toString(int) Integer.toString(int)}. 658 * </p> 659 * 660 * @param key 661 * the preference key to be added or updated. 662 * @param value 663 * the preference value for the given key. 664 * @throws NullPointerException 665 * if the given key is {@code null}. 666 * @throws IllegalArgumentException 667 * if the given key's length is bigger than {@code 668 * MAX_KEY_LENGTH}. 669 * @throws IllegalStateException 670 * if this node has been removed. 671 */ 672 public abstract void putInt(String key, int value); 673 674 /** 675 * Adds a new preference to this node using the given key and {@code long} 676 * value or updates the value if a preference with the 677 * given key already exists. 678 * <p> 679 * The value is stored in its string form, which is the result of invoking 680 * {@link Long#toString(long) Long.toString(long)}. 681 * </p> 682 * 683 * @param key 684 * the preference key to be added or updated. 685 * @param value 686 * the preference value for the given key. 687 * @throws NullPointerException 688 * if the given key is {@code null}. 689 * @throws IllegalArgumentException 690 * if the given key's length is bigger than {@code 691 * MAX_KEY_LENGTH}. 692 * @throws IllegalStateException 693 * if this node has been removed. 694 */ 695 public abstract void putLong(String key, long value); 696 697 /** 698 * Removes the preference mapped to the given key from this node. 699 * 700 * @param key 701 * the key of the preference to be removed. 702 * @throws NullPointerException 703 * if the given key is {@code null}. 704 * @throws IllegalStateException 705 * if this node has been removed. 706 */ 707 public abstract void remove(String key); 708 709 /** 710 * Removes this preference node with all its descendants. The removal won't 711 * necessarily be persisted until the method {@code flush()} is invoked. 712 * 713 * @throws BackingStoreException 714 * if the backing store is unavailable or causes an operation 715 * failure. 716 * @throws IllegalStateException 717 * if this node has been removed. 718 * @throws UnsupportedOperationException 719 * if this is a root node. 720 */ 721 public abstract void removeNode() throws BackingStoreException; 722 723 /** 724 * Registers a {@code NodeChangeListener} instance for this node, which will 725 * handle {@code NodeChangeEvent}s. {@code NodeChangeEvent}s will be fired 726 * when a child node has been added to or removed from this node. 727 * 728 * @param ncl 729 * the listener to be registered. 730 * @throws NullPointerException 731 * if the given listener is {@code null}. 732 * @throws IllegalStateException 733 * if this node has been removed. 734 */ 735 public abstract void addNodeChangeListener(NodeChangeListener ncl); 736 737 /** 738 * Registers a {@code PreferenceChangeListener} instance for this node, 739 * which will handle {@code PreferenceChangeEvent}s. {@code 740 * PreferenceChangeEvent}s will be fired when a preference has been added 741 * to, removed from, or updated for this node. 742 * 743 * @param pcl 744 * the listener to be registered. 745 * @throws NullPointerException 746 * if the given listener is {@code null}. 747 * @throws IllegalStateException 748 * if this node has been removed. 749 */ 750 public abstract void addPreferenceChangeListener (PreferenceChangeListener pcl); 751 752 /** 753 * Removes the given {@code NodeChangeListener} instance from this node. 754 * 755 * @param ncl 756 * the listener to be removed. 757 * @throws IllegalArgumentException 758 * if the given listener is {@code null}. 759 * @throws IllegalStateException 760 * if this node has been removed. 761 */ 762 public abstract void removeNodeChangeListener (NodeChangeListener ncl); 763 764 /** 765 * Removes the given {@code PreferenceChangeListener} instance from this 766 * node. 767 * 768 * @param pcl 769 * the listener to be removed. 770 * @throws IllegalArgumentException 771 * if the given listener is {@code null}. 772 * @throws IllegalStateException 773 * if this node has been removed. 774 */ 775 public abstract void removePreferenceChangeListener (PreferenceChangeListener pcl); 776 777 /** 778 * Synchronizes the data of this preference node and its descendants with 779 * the back-end preference store. Any changes found in the back-end data 780 * should be reflected in this node and its descendants, and at the same 781 * time any local changes to this node and descendants should be persisted. 782 * 783 * @throws BackingStoreException 784 * if the backing store is unavailable or causes an operation 785 * failure. 786 * @throws IllegalStateException 787 * if this node has been removed. 788 */ 789 public abstract void sync() throws BackingStoreException; 790 791 /** 792 * <strong>Legacy code; do not use.</strong> On Android, the Preference nodes 793 * corresponding to the "system" and "user" preferences are stored in sections 794 * of the file system that are inaccessible to apps. Further, allowing apps to set 795 * "system wide" preferences is contrary to android's security model. 796 * 797 * Returns the system preference node for the package of the given class. 798 * The absolute path of the returned node is one slash followed by the given 799 * class's full package name, replacing each period character ('.') with 800 * a slash. For example, the absolute path of the preference associated with 801 * the class Object would be "/java/lang". As a special case, the unnamed 802 * package is associated with a preference node "/<unnamed>". This 803 * method will create the node and its ancestors as needed. Any nodes created 804 * by this method won't necessarily be persisted until the method {@code 805 * flush()} is invoked. 806 * 807 * @param c 808 * the given class. 809 * @return the system preference node for the package of the given class. 810 * @throws NullPointerException 811 * if the given class is {@code null}. 812 */ 813 public static Preferences systemNodeForPackage(Class<?> c) { 814 return factory.systemRoot().node(getNodeName(c)); 815 } 816 817 /** 818 * <strong>Legacy code; do not use.</strong> On Android, the Preference nodes 819 * corresponding to the "system" and "user" preferences are stored in sections 820 * of the file system that are inaccessible to apps. Further, allowing apps to set 821 * "system wide" preferences is contrary to android's security model. 822 * 823 * Returns the root node of the system preference hierarchy. 824 * 825 * @return the system preference hierarchy root node. 826 */ 827 public static Preferences systemRoot() { 828 return factory.systemRoot(); 829 } 830 831 /** 832 * 833 * <strong>Legacy code; do not use.</strong> On Android, the Preference nodes 834 * corresponding to the "system" and "user" preferences are stored in sections 835 * of the file system that are inaccessible to apps. Further, allowing apps to set 836 * "system wide" preferences is contrary to android's security model. 837 * 838 * <p> 839 * Returns the user preference node for the package of the given class. 840 * The absolute path of the returned node is one slash followed by the given 841 * class's full package name, replacing each period character ('.') with 842 * a slash. For example, the absolute path of the preference associated with 843 * the class Object would be "/java/lang". As a special case, the unnamed 844 * package is associated with a preference node "/<unnamed>". This 845 * method will create the node and its ancestors as needed. Any nodes created 846 * by this method won't necessarily be persisted until the method {@code 847 * flush()} is invoked. 848 * 849 * @return the user preference node for the package of the given class. 850 * @throws NullPointerException 851 * if the given class is {@code null}. 852 */ 853 public static Preferences userNodeForPackage(Class<?> c) { 854 return factory.userRoot().node(getNodeName(c)); 855 } 856 857 //parse node's absolute path from class instance 858 private static String getNodeName(Class<?> c){ 859 Package p = c.getPackage(); 860 if (p == null){ 861 return "/<unnamed>"; 862 } 863 return "/"+p.getName().replace('.', '/'); 864 } 865 866 /** 867 * <strong>Legacy code; do not use.</strong> On Android, the Preference nodes 868 * corresponding to the "system" and "user" preferences are stored in sections 869 * of the file system that are inaccessible to apps. Further, allowing apps to set 870 * "system wide" preferences is contrary to android's security model. 871 * 872 * Returns the root node of the user preference hierarchy. 873 * 874 * @return the user preference hierarchy root node. 875 */ 876 public static Preferences userRoot() { 877 return factory.userRoot(); 878 } 879 880 /** 881 * Returns a string representation of this node. The format is "User/System 882 * Preference Node: " followed by this node's absolute path. 883 * 884 * @return the string representation of this node. 885 */ 886 @Override 887 public abstract String toString(); 888} 889