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 final PreferencesFactory factory = findPreferencesFactory(); 103 104 private static PreferencesFactory findPreferencesFactory() { 105 // Try the system property first... 106 PreferencesFactory result = ServiceLoader.loadFromSystemProperty(PreferencesFactory.class); 107 if (result != null) { 108 return result; 109 } 110 // Then use ServiceLoader for META-INF/services/... 111 for (PreferencesFactory impl : ServiceLoader.load(PreferencesFactory.class)) { 112 return impl; 113 } 114 // Finally return a default... 115 return new FilePreferencesFactoryImpl(); 116 } 117 118 /** 119 * Default constructor, for use by subclasses only. 120 */ 121 protected Preferences() { 122 } 123 124 /** 125 * Gets the absolute path string of this preference node. 126 * 127 * @return the preference node's absolute path string. 128 */ 129 public abstract String absolutePath(); 130 131 /** 132 * Returns the names of all children of this node or an empty array if this 133 * node has no children. 134 * 135 * @return the names of all children of this node. 136 * @throws BackingStoreException 137 * if backing store is unavailable or causes an operation 138 * failure. 139 * @throws IllegalStateException 140 * if this node has been removed. 141 */ 142 public abstract String[] childrenNames() throws BackingStoreException; 143 144 /** 145 * Removes all preferences of this node. 146 * 147 * @throws BackingStoreException 148 * if backing store is unavailable or causes an operation 149 * failure. 150 * @throws IllegalStateException 151 * if this node has been removed. 152 */ 153 public abstract void clear() throws BackingStoreException; 154 155 /** 156 * Exports all of the preferences of this node to a XML document using the 157 * given output stream. 158 * <p> 159 * This XML document uses the UTF-8 encoding and is written according to the 160 * DTD in its DOCTYPE declaration, which is the following: 161 * 162 * <pre> 163 * <!DOCTYPE preferences SYSTEM "http://java.sun.com/dtd/preferences.dtd"> 164 * </pre> 165 * 166 * <i>Please note that (unlike the methods of this class that don't concern 167 * serialization), this call is not thread-safe.</i> 168 * </p> 169 * 170 * @param ostream 171 * the output stream to write the XML-formatted data to. 172 * @throws IOException 173 * if an error occurs while exporting. 174 * @throws BackingStoreException 175 * if the backing store is unavailable or causes an operation 176 * failure. 177 * @throws IllegalStateException 178 * if this node has been removed. 179 */ 180 public abstract void exportNode(OutputStream ostream) throws IOException, BackingStoreException; 181 182 /** 183 * Exports all of the preferences of this node and all its descendants to a 184 * XML document using the given output stream. 185 * <p> 186 * This XML document uses the UTF-8 encoding and is written according to the 187 * DTD in its DOCTYPE declaration, which is the following: 188 * 189 * <pre> 190 * <!DOCTYPE preferences SYSTEM "http://java.sun.com/dtd/preferences.dtd"> 191 * </pre> 192 * 193 * <i>Please note that (unlike the methods of this class that don't concern 194 * serialization), this call is not thread-safe.</i> 195 * </p> 196 * 197 * @param ostream 198 * the output stream to write the XML-formatted data to. 199 * @throws IOException 200 * if an error occurs while exporting. 201 * @throws BackingStoreException 202 * if the backing store is unavailable or causes an operation 203 * failure. 204 * @throws IllegalStateException 205 * if this node has been removed. 206 */ 207 public abstract void exportSubtree(OutputStream ostream) throws IOException, 208 BackingStoreException; 209 210 /** 211 * Forces all pending updates to this node and its descendants to be 212 * persisted in the backing store. 213 * <p> 214 * If this node has been removed, the invocation of this method only flushes 215 * this node, not its descendants. 216 * </p> 217 * 218 * @throws BackingStoreException 219 * if the backing store is unavailable or causes an operation 220 * failure. 221 */ 222 public abstract void flush() throws BackingStoreException; 223 224 /** 225 * Gets the {@code String} value mapped to the given key or its default 226 * value if no value is mapped or no backing store is available. 227 * <p> 228 * Some implementations may store default values in backing stores. In this 229 * case, if there is no value mapped to the given key, the stored default 230 * value is returned. 231 * </p> 232 * 233 * @param key 234 * the preference key. 235 * @param deflt 236 * the default value, which will be returned if no value is 237 * mapped to the given key or no backing store is available. 238 * @return the preference value mapped to the given key. 239 * @throws IllegalStateException 240 * if this node has been removed. 241 * @throws NullPointerException 242 * if the parameter {@code key} is {@code null}. 243 */ 244 public abstract String get(String key, String deflt); 245 246 /** 247 * Gets the {@code boolean} value mapped to the given key or its default 248 * value if no value is mapped, if the backing store is unavailable, or if 249 * the value is invalid. 250 * <p> 251 * The only valid values are the {@code String} "true", which represents 252 * {@code true} and "false", which represents {@code false}, ignoring case. 253 * </p> 254 * <p> 255 * Some implementations may store default values in backing stores. In this 256 * case, if there is no value mapped to the given key, the stored default 257 * value is returned. 258 * </p> 259 * 260 * @param key 261 * the preference key. 262 * @param deflt 263 * the default value, which will be returned if no value is 264 * mapped to the given key, if the backing store is unavailable, 265 * or if the value is invalid. 266 * @return the boolean value mapped to the given key. 267 * @throws IllegalStateException 268 * if this node has been removed. 269 * @throws NullPointerException 270 * if the parameter {@code key} is {@code null}. 271 */ 272 public abstract boolean getBoolean(String key, boolean deflt); 273 274 /** 275 * Gets the {@code byte} array value mapped to the given key or its default 276 * value if no value is mapped, if the backing store is unavailable, or if 277 * the value is an invalid string. 278 * <p> 279 * To be valid, the value string must be Base64-encoded binary data. The 280 * Base64 encoding is as defined in <a 281 * href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045</a>, section 6.8. 282 * </p> 283 * <p> 284 * Some implementations may store default values in backing stores. In this 285 * case, if there is no value mapped to the given key, the stored default 286 * value is returned. 287 * </p> 288 * 289 * @param key 290 * the preference key. 291 * @param deflt 292 * the default value, which will be returned if no value is 293 * mapped to the given key, if the backing store is unavailable, 294 * or if the value is invalid. 295 * @return the byte array value mapped to the given key. 296 * @throws IllegalStateException 297 * if this node has been removed. 298 * @throws NullPointerException 299 * if the parameter {@code key} is {@code null}. 300 */ 301 public abstract byte[] getByteArray(String key, byte[] deflt); 302 303 /** 304 * Gets the {@code double} value mapped to the given key or its default 305 * value if no value is mapped, if the backing store is unavailable, or if 306 * the value is an invalid string. 307 * <p> 308 * To be valid, the value string must be a string that can be converted to a 309 * {@code double} by {@link Double#parseDouble(String) 310 * Double.parseDouble(String)}. 311 * <p> 312 * Some implementations may store default values in backing stores. In this 313 * case, if there is no value mapped to the given key, the stored default 314 * value is returned. 315 * </p> 316 * 317 * @param key 318 * the preference key. 319 * @param deflt 320 * the default value, which will be returned if no value is 321 * mapped to the given key, if the backing store is unavailable, or if the 322 * value is invalid. 323 * @return the double value mapped to the given key. 324 * @throws IllegalStateException 325 * if this node has been removed. 326 * @throws NullPointerException 327 * if the parameter {@code key} is {@code null}. 328 */ 329 public abstract double getDouble(String key, double deflt); 330 331 /** 332 * Gets the {@code float} value mapped to the given key or its default value 333 * if no value is mapped, if the backing store is unavailable, or if the 334 * value is an invalid string. 335 * <p> 336 * To be valid, the value string must be a string that can be converted to a 337 * {@code float} by {@link Float#parseFloat(String) 338 * Float.parseFloat(String)}. 339 * </p> 340 * <p> 341 * Some implementations may store default values in backing stores. In this 342 * case, if there is no value mapped to the given key, the stored default 343 * value is returned. 344 * </p> 345 * 346 * @param key 347 * the preference key. 348 * @param deflt 349 * the default value, which will be returned if no value is 350 * mapped to the given key, if the backing store is unavailable, or if the 351 * value is invalid. 352 * @return the float value mapped to the given key. 353 * @throws IllegalStateException 354 * if this node has been removed. 355 * @throws NullPointerException 356 * if the parameter {@code key} is {@code null}. 357 */ 358 public abstract float getFloat(String key, float deflt); 359 360 /** 361 * Gets the {@code int} value mapped to the given key or its default value 362 * if no value is mapped, if the backing store is unavailable, or if the 363 * value is an invalid string. 364 * <p> 365 * To be valid, the value string must be a string that can be converted to 366 * an {@code int} by {@link Integer#parseInt(String) 367 * Integer.parseInt(String)}. 368 * </p> 369 * <p> 370 * Some implementations may store default values in backing stores. In this 371 * case, if there is no value mapped to the given key, the stored default 372 * value is returned. 373 * </p> 374 * 375 * @param key 376 * the preference key. 377 * @param deflt 378 * the default value, which will be returned if no value is 379 * mapped to the given key, if the backing store is unavailable, 380 * or if the value is invalid. 381 * @return the integer value mapped to the given key. 382 * @throws IllegalStateException 383 * if this node has been removed. 384 * @throws NullPointerException 385 * if the parameter {@code key} is {@code null}. 386 */ 387 public abstract int getInt(String key, int deflt); 388 389 /** 390 * Gets the {@code long} value mapped to the given key or its default value 391 * if no value is mapped, if the backing store is unavailable, or if the 392 * value is an invalid string. 393 * <p> 394 * To be valid, the value string must be a string that can be converted to a 395 * {@code long} by {@link Long#parseLong(String) Long.parseLong(String)}. 396 * </p> 397 * <p> 398 * Some implementations may store default values in backing stores. In this 399 * case, if there is no value mapped to the given key, the stored default 400 * value is returned. 401 * </p> 402 * 403 * @param key 404 * the preference key. 405 * @param deflt 406 * the default value, which will be returned if no value is 407 * mapped to the given key, if the backing store is unavailable, 408 * or if the value is invalid. 409 * @return the long value mapped to the given key. 410 * @throws IllegalStateException 411 * if this node has been removed. 412 * @throws NullPointerException 413 * if the parameter {@code key} is {@code null}. 414 */ 415 public abstract long getLong(String key, long deflt); 416 417 /** 418 * Imports all the preferences from an XML document using the given input 419 * stream. 420 * <p> 421 * This XML document uses the UTF-8 encoding and must be written according 422 * to the DTD in its DOCTYPE declaration, which must be the following: 423 * 424 * <pre> 425 * <!DOCTYPE preferences SYSTEM "http://java.sun.com/dtd/preferences.dtd"> 426 * </pre> 427 * 428 * <i>Please note that (unlike the methods of this class that don't concern 429 * serialization), this call is not thread-safe.</i> 430 * </p> 431 * 432 * @param istream 433 * the input stream to read the data from. 434 * @throws InvalidPreferencesFormatException 435 * if the data read from the given input stream is not from a 436 * valid XML document. 437 * @throws IOException 438 * if an error occurs while importing. 439 */ 440 public static void importPreferences (InputStream istream) throws InvalidPreferencesFormatException, IOException { 441 if (istream == null){ 442 throw new MalformedURLException("Inputstream cannot be null"); 443 } 444 XMLParser.importPrefs(istream); 445 } 446 447 /** 448 * Returns whether this is a user preference node. 449 * 450 * @return {@code true}, if this is a user preference node, {@code false} if 451 * this is a system preference node. 452 */ 453 public abstract boolean isUserNode(); 454 455 /** 456 * Returns all preference keys stored in this node or an empty array if no 457 * key was found. 458 * 459 * @return the list of all preference keys of this node. 460 * @throws BackingStoreException 461 * if the backing store is unavailable or causes an operation 462 * failure. 463 * @throws IllegalStateException 464 * if this node has been removed. 465 */ 466 public abstract String[] keys() throws BackingStoreException; 467 468 /** 469 * Returns the name of this node. 470 * 471 * @return the name of this node. 472 */ 473 public abstract String name(); 474 475 /** 476 * Returns the preference node with the given path name. The path name can 477 * be relative or absolute. The requested node and its ancestors will 478 * be created if they do not exist. 479 * <p> 480 * The path is treated as relative to this node if it doesn't start with a 481 * slash, otherwise it will be treated as an absolute path. 482 * </p> 483 * 484 * @param path 485 * the path name of the requested preference node. 486 * @return the requested preference node. 487 * @throws IllegalStateException 488 * if this node has been removed. 489 * @throws IllegalArgumentException 490 * if the path name is invalid. 491 * @throws NullPointerException 492 * if the given path is {@code null}. 493 */ 494 public abstract Preferences node(String path); 495 496 /** 497 * Returns whether the preference node with the given path name exists. The 498 * path is treated as relative to this node if it doesn't start with a slash, 499 * otherwise it is treated as an absolute path. 500 * <p> 501 * Please note that if this node has been removed, an invocation of this 502 * node will throw an {@code IllegalStateException} unless the given path is 503 * an empty string, which will return {@code false}. 504 * </p> 505 * 506 * @param path 507 * the path name of the preference node to query. 508 * @return {@code true}, if the queried preference node exists, {@code false} 509 * otherwise. 510 * @throws IllegalStateException 511 * if this node has been removed and the path is not an empty 512 * string. 513 * @throws IllegalArgumentException 514 * if the path name is invalid. 515 * @throws NullPointerException 516 * if the given path is {@code null}. 517 * @throws BackingStoreException 518 * if the backing store is unavailable or causes an operation 519 * failure. 520 */ 521 public abstract boolean nodeExists(String path) throws BackingStoreException; 522 523 /** 524 * Returns the parent preference node of this node or {@code null} if this 525 * node is the root node. 526 * 527 * @return the parent preference node of this node. 528 * @throws IllegalStateException 529 * if this node has been removed. 530 */ 531 public abstract Preferences parent(); 532 533 /** 534 * Adds a new preference to this node using the given key and value or 535 * updates the value if a preference with the given key already exists. 536 * 537 * @param key 538 * the preference key to be added or updated. 539 * @param value 540 * the preference value for the given key. 541 * @throws NullPointerException 542 * if the given key or value is {@code null}. 543 * @throws IllegalArgumentException 544 * if the given key's length is bigger than {@code 545 * MAX_KEY_LENGTH} or the value's length is bigger than {@code 546 * MAX_VALUE_LENGTH}. 547 * @throws IllegalStateException 548 * if this node has been removed. 549 */ 550 public abstract void put(String key, String value); 551 552 /** 553 * Adds a new preference with a {@code boolean} value to this node using the 554 * given key and value or updates the value if a preference with the given 555 * key already exists. 556 * 557 * @param key 558 * the preference key to be added or updated. 559 * @param value 560 * the preference {@code boolean} value for the given key. 561 * @throws NullPointerException 562 * if the given key is {@code null}. 563 * @throws IllegalArgumentException 564 * if the given key's length is bigger than {@code 565 * MAX_KEY_LENGTH}. 566 * @throws IllegalStateException 567 * if this node has been removed. 568 */ 569 public abstract void putBoolean(String key, boolean value); 570 571 /** 572 * Adds a new preference to this node using the given key and the string 573 * form of the given value or updates the value if a preference with the 574 * given key already exists. 575 * <p> 576 * The string form of the value is the Base64-encoded binary data of the 577 * given byte array. The Base64 encoding is as defined in <a 578 * href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045</a>, section 6.8. 579 * </p> 580 * 581 * @param key 582 * the preference key to be added or updated. 583 * @param value 584 * the preference value for the given key. 585 * @throws NullPointerException 586 * if the given key or value is {@code null}. 587 * @throws IllegalArgumentException 588 * if the given key's length is bigger than {@code 589 * MAX_KEY_LENGTH} or value's length is bigger than three 590 * quarters of {@code MAX_KEY_LENGTH}. 591 * @throws IllegalStateException 592 * if this node has been removed. 593 */ 594 public abstract void putByteArray(String key, byte[] value); 595 596 /** 597 * Adds a new preference to this node using the given key and {@code double} 598 * value or updates the value if a preference with the 599 * given key already exists. 600 * <p> 601 * The value is stored in its string form, which is the result of invoking 602 * {@link Double#toString(double) Double.toString(double)}. 603 * </p> 604 * 605 * @param key 606 * the preference key to be added or updated. 607 * @param value 608 * the preference value for the given key. 609 * @throws NullPointerException 610 * if the given key is {@code null}. 611 * @throws IllegalArgumentException 612 * if the given key's length is bigger than {@code 613 * MAX_KEY_LENGTH}. 614 * @throws IllegalStateException 615 * if this node has been removed. 616 */ 617 public abstract void putDouble(String key, double value); 618 619 /** 620 * Adds a new preference to this node using the given key and {@code float} 621 * value or updates the value if a preference with the 622 * given key already exists. 623 * <p> 624 * The value is stored in its string form, which is the result of invoking 625 * {@link Float#toString(float) Float.toString(float)}. 626 * </p> 627 * 628 * @param key 629 * the preference key to be added or updated. 630 * @param value 631 * the preference value for the given key. 632 * @throws NullPointerException 633 * if the given key is {@code null}. 634 * @throws IllegalArgumentException 635 * if the given key's length is bigger than {@code 636 * MAX_KEY_LENGTH}. 637 * @throws IllegalStateException 638 * if this node has been removed. 639 */ 640 public abstract void putFloat(String key, float value); 641 642 /** 643 * Adds a new preference to this node using the given key and {@code int} 644 * value or updates the value if a preference with the 645 * given key already exists. 646 * <p> 647 * The value is stored in its string form, which is the result of invoking 648 * {@link Integer#toString(int) Integer.toString(int)}. 649 * </p> 650 * 651 * @param key 652 * the preference key to be added or updated. 653 * @param value 654 * the preference value for the given key. 655 * @throws NullPointerException 656 * if the given key is {@code null}. 657 * @throws IllegalArgumentException 658 * if the given key's length is bigger than {@code 659 * MAX_KEY_LENGTH}. 660 * @throws IllegalStateException 661 * if this node has been removed. 662 */ 663 public abstract void putInt(String key, int value); 664 665 /** 666 * Adds a new preference to this node using the given key and {@code long} 667 * value or updates the value if a preference with the 668 * given key already exists. 669 * <p> 670 * The value is stored in its string form, which is the result of invoking 671 * {@link Long#toString(long) Long.toString(long)}. 672 * </p> 673 * 674 * @param key 675 * the preference key to be added or updated. 676 * @param value 677 * the preference value for the given key. 678 * @throws NullPointerException 679 * if the given key is {@code null}. 680 * @throws IllegalArgumentException 681 * if the given key's length is bigger than {@code 682 * MAX_KEY_LENGTH}. 683 * @throws IllegalStateException 684 * if this node has been removed. 685 */ 686 public abstract void putLong(String key, long value); 687 688 /** 689 * Removes the preference mapped to the given key from this node. 690 * 691 * @param key 692 * the key of the preference to be removed. 693 * @throws NullPointerException 694 * if the given key is {@code null}. 695 * @throws IllegalStateException 696 * if this node has been removed. 697 */ 698 public abstract void remove(String key); 699 700 /** 701 * Removes this preference node with all its descendants. The removal won't 702 * necessarily be persisted until the method {@code flush()} is invoked. 703 * 704 * @throws BackingStoreException 705 * if the backing store is unavailable or causes an operation 706 * failure. 707 * @throws IllegalStateException 708 * if this node has been removed. 709 * @throws UnsupportedOperationException 710 * if this is a root node. 711 */ 712 public abstract void removeNode() throws BackingStoreException; 713 714 /** 715 * Registers a {@code NodeChangeListener} instance for this node, which will 716 * handle {@code NodeChangeEvent}s. {@code NodeChangeEvent}s will be fired 717 * when a child node has been added to or removed from this node. 718 * 719 * @param ncl 720 * the listener to be registered. 721 * @throws NullPointerException 722 * if the given listener is {@code null}. 723 * @throws IllegalStateException 724 * if this node has been removed. 725 */ 726 public abstract void addNodeChangeListener(NodeChangeListener ncl); 727 728 /** 729 * Registers a {@code PreferenceChangeListener} instance for this node, 730 * which will handle {@code PreferenceChangeEvent}s. {@code 731 * PreferenceChangeEvent}s will be fired when a preference has been added 732 * to, removed from, or updated for this node. 733 * 734 * @param pcl 735 * the listener to be registered. 736 * @throws NullPointerException 737 * if the given listener is {@code null}. 738 * @throws IllegalStateException 739 * if this node has been removed. 740 */ 741 public abstract void addPreferenceChangeListener (PreferenceChangeListener pcl); 742 743 /** 744 * Removes the given {@code NodeChangeListener} instance from this node. 745 * 746 * @param ncl 747 * the listener to be removed. 748 * @throws IllegalArgumentException 749 * if the given listener is {@code null}. 750 * @throws IllegalStateException 751 * if this node has been removed. 752 */ 753 public abstract void removeNodeChangeListener (NodeChangeListener ncl); 754 755 /** 756 * Removes the given {@code PreferenceChangeListener} instance from this 757 * node. 758 * 759 * @param pcl 760 * the listener to be removed. 761 * @throws IllegalArgumentException 762 * if the given listener is {@code null}. 763 * @throws IllegalStateException 764 * if this node has been removed. 765 */ 766 public abstract void removePreferenceChangeListener (PreferenceChangeListener pcl); 767 768 /** 769 * Synchronizes the data of this preference node and its descendants with 770 * the back-end preference store. Any changes found in the back-end data 771 * should be reflected in this node and its descendants, and at the same 772 * time any local changes to this node and descendants should be persisted. 773 * 774 * @throws BackingStoreException 775 * if the backing store is unavailable or causes an operation 776 * failure. 777 * @throws IllegalStateException 778 * if this node has been removed. 779 */ 780 public abstract void sync() throws BackingStoreException; 781 782 /** 783 * Returns the system preference node for the package of the given class. 784 * The absolute path of the returned node is one slash followed by the given 785 * class's full package name, replacing each period character ('.') with 786 * a slash. For example, the absolute path of the preference associated with 787 * the class Object would be "/java/lang". As a special case, the unnamed 788 * package is associated with a preference node "/<unnamed>". This 789 * method will create the node and its ancestors as needed. Any nodes created 790 * by this method won't necessarily be persisted until the method {@code 791 * flush()} is invoked. 792 * 793 * @param c 794 * the given class. 795 * @return the system preference node for the package of the given class. 796 * @throws NullPointerException 797 * if the given class is {@code null}. 798 */ 799 public static Preferences systemNodeForPackage (Class<?> c) { 800 return factory.systemRoot().node(getNodeName(c)); 801 } 802 803 /** 804 * Returns the root node of the system preference hierarchy. 805 * 806 * @return the system preference hierarchy root node. 807 */ 808 public static Preferences systemRoot() { 809 return factory.systemRoot(); 810 } 811 812 /** 813 * Returns the user preference node for the package of the given class. 814 * The absolute path of the returned node is one slash followed by the given 815 * class's full package name, replacing each period character ('.') with 816 * a slash. For example, the absolute path of the preference associated with 817 * the class Object would be "/java/lang". As a special case, the unnamed 818 * package is associated with a preference node "/<unnamed>". This 819 * method will create the node and its ancestors as needed. Any nodes created 820 * by this method won't necessarily be persisted until the method {@code 821 * flush()} is invoked. 822 * 823 * @param c 824 * the given class. 825 * @return the user preference node for the package of the given class. 826 * @throws NullPointerException 827 * if the given class is {@code null}. 828 */ 829 public static Preferences userNodeForPackage (Class<?> c) { 830 return factory.userRoot().node(getNodeName(c)); 831 } 832 833 //parse node's absolute path from class instance 834 private static String getNodeName(Class<?> c){ 835 Package p = c.getPackage(); 836 if (p == null){ 837 return "/<unnamed>"; 838 } 839 return "/"+p.getName().replace('.', '/'); 840 } 841 842 /** 843 * Returns the root node of the user preference hierarchy. 844 * 845 * @return the user preference hierarchy root node. 846 */ 847 public static Preferences userRoot() { 848 return factory.userRoot(); 849 } 850 851 /** 852 * Returns a string representation of this node. The format is "User/System 853 * Preference Node: " followed by this node's absolute path. 854 * 855 * @return the string representation of this node. 856 */ 857 @Override 858 public abstract String toString(); 859} 860