OSDN Git Service

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