001: /* Licensed to the Apache Software Foundation (ASF) under one or more
002: * contributor license agreements. See the NOTICE file distributed with
003: * this work for additional information regarding copyright ownership.
004: * The ASF licenses this file to You under the Apache License, Version 2.0
005: * (the "License"); you may not use this file except in compliance with
006: * the License. You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016:
017: package java.util.prefs;
018:
019: import java.io.IOException;
020: import java.io.InputStream;
021: import java.io.OutputStream;
022: import java.net.MalformedURLException;
023: import java.security.AccessController;
024: import java.security.PrivilegedAction;
025:
026: import org.apache.harmony.prefs.internal.nls.Messages;
027:
028: /**
029: * <code>Preferences</code> instance represents one node in preferences tree,
030: * which provide a mechanisms to store and access configuration data in a
031: * hierarchical way. Two hierarchy tree is maintained, one for system
032: * preferences shared by all users, and the other for user preferences which is
033: * specific for each user. Preferences hierarchy tree and data is stored
034: * precisely in implementation-dependent backend, and user doesn't need to care
035: * about the details.
036: * <p>
037: * Every node has one name and one unique absolute path in a similar way with
038: * directories in file system. The root node's name is "", and other nodes' name
039: * string cannot contains slash and cannot be empty. The root node's absolute
040: * path is "/", and other nodes' absolute path equals <parent's absolute
041: * path> + "/" + <node's name>. All absolute paths start with slash.
042: * Every node has one relative path to one of its ancestor. Relative path
043: * doesn't start with slash, and equals to absolute path when following after
044: * ancestor's absolute path and a slash.
045: * </p>
046: * <p>
047: * The modification to preferences data may be asynchronous, which means they
048: * may don't block and may returns immediately, implementation can feel free to
049: * the modifications to the backend in any time until the flush() or sync()
050: * method is invoked, these two methods force synchronized updates to backend.
051: * Please note that if JVM exit normally, the implementation must assure all
052: * modifications are persisted implicitly.
053: * </p>
054: * <p>
055: * User invoking methods that retrieve preferences must provide default value,
056: * default value is returned when preferences cannot be found or backend is
057: * unavailable. Some other methods will throw <code>BackingStoreException</code>
058: * when backend is unavailable.
059: * </p>
060: * <p>
061: * Preferences can be export to/import from XML files, the XML document must
062: * have the following DOCTYPE declaration:
063: * </p>
064: * <p>
065: * <!DOCTYPE preferences SYSTEM "http://java.sun.com/dtd/preferences.dtd">
066: * </p>
067: * <p>
068: * This system URI is not really accessed by network, it is only a
069: * identification string. Visit the DTD location to see the actual format
070: * permitted.
071: * </p>
072: * <p>
073: * There has to be a concrete <code>PreferencesFactory</code> type for every
074: * concrete <code>Preferences</code> type developed. Every J2SE implementation
075: * must provide a default implementation for every supported platform, and the
076: * default implementation can be replaced in some way. This implementation uses
077: * system property java.util.prefs.PreferencesFactory to dictate the preferences
078: * implementation.
079: * </p>
080: * <p>
081: * Methods of this class is thread-safe. If multi JVMs using same backend
082: * concurrently, the backend won't be corrupted, but no other guarantees is
083: * made.
084: * </p>
085: *
086: * @see PreferencesFactory
087: *
088: * @since 1.4
089: */
090: public abstract class Preferences {
091:
092: /*
093: * ---------------------------------------------------------
094: * Class fields
095: * ---------------------------------------------------------
096: */
097:
098: /**
099: * Maximum size in characters of preferences key
100: */
101: public static final int MAX_KEY_LENGTH = 80;
102:
103: /**
104: * Maximum size in characters of preferences name
105: */
106: public static final int MAX_NAME_LENGTH = 80;
107:
108: /**
109: * Maximum size in characters of preferences value
110: */
111: public static final int MAX_VALUE_LENGTH = 8192;
112:
113: //permission
114: private static final RuntimePermission PREFS_PERM = new RuntimePermission(
115: "preferences"); //$NON-NLS-1$
116:
117: //factory used to get user/system prefs root
118: private static final PreferencesFactory factory;
119:
120: /**
121: * ---------------------------------------------------------
122: * Class initializer
123: * ---------------------------------------------------------
124: */
125: static {
126: String factoryClassName = AccessController
127: .doPrivileged(new PrivilegedAction<String>() {
128: public String run() {
129: return System
130: .getProperty("java.util.prefs.PreferencesFactory"); //$NON-NLS-1$
131: }
132: });
133: try {
134: ClassLoader loader = Thread.currentThread()
135: .getContextClassLoader();
136: if (loader == null) {
137: loader = ClassLoader.getSystemClassLoader();
138: }
139: Class<?> factoryClass = loader.loadClass(factoryClassName);
140: factory = (PreferencesFactory) factoryClass.newInstance();
141: } catch (Exception e) {
142: // prefs.10=Cannot initiate PreferencesFactory: {0}. Caused by {1}
143: throw new InternalError(Messages.getString(
144: "prefs.10", factoryClassName, e)); //$NON-NLS-1$
145: }
146: }
147:
148: /*
149: * ---------------------------------------------------------
150: * Constructors
151: * ---------------------------------------------------------
152: */
153:
154: /**
155: * Default constructor, for use by subclasses only.
156: */
157: protected Preferences() {
158: super ();
159: }
160:
161: /*
162: * ---------------------------------------------------------
163: * Methods
164: * ---------------------------------------------------------
165: */
166:
167: /**
168: * Get this preference node's absolute path string.
169: *
170: * @return this preference node's absolute path string.
171: */
172: public abstract String absolutePath();
173:
174: /**
175: * Return names of all children of this node, or empty string if this node
176: * has no children.
177: *
178: * @return names of all children of this node
179: * @throws BackingStoreException
180: * if backing store is unavailable or causes operation failure
181: * @throws IllegalStateException
182: * if this node has been removed
183: */
184: public abstract String[] childrenNames()
185: throws BackingStoreException;
186:
187: /**
188: * Remove all preferences of this node.
189: *
190: * @throws BackingStoreException
191: * if backing store is unavailable or causes operation failure
192: * @throws IllegalStateException
193: * if this node has been removed
194: */
195: public abstract void clear() throws BackingStoreException;
196:
197: /**
198: * Export all preferences of this node to the given output stream in XML
199: * document.
200: * <p>
201: * This XML document has the following DOCTYPE declaration:
202: * <pre>
203: * <!DOCTYPE preferences SYSTEM "http://java.sun.com/dtd/preferences.dtd"></pre>
204: * And the UTF-8 encoding will be used. Please note that this node is not
205: * thread-safe, which is an exception of this class.
206: * </p>
207: * @param ostream
208: * the output stream to export the XML
209: * @throws IOException
210: * if export operation caused an <code>IOException</code>
211: * @throws BackingStoreException
212: * if backing store is unavailable or causes operation failure
213: * @throws IllegalStateException
214: * if this node has been removed
215: */
216: public abstract void exportNode(OutputStream ostream)
217: throws IOException, BackingStoreException;
218:
219: /**
220: * Export all preferences of this node and its all descendants to the given
221: * output stream in XML document.
222: * <p>
223: * This XML document has the following DOCTYPE declaration:
224: * <pre>
225: * <!DOCTYPE preferences SYSTEM "http://java.sun.com/dtd/preferences.dtd"></pre> *
226: * And the UTF-8 encoding will be used. Please note that this node is not
227: * thread-safe, which is an exception of this class.
228: * </p>
229: * @param ostream
230: * the output stream to export the XML
231: * @throws IOException
232: * if export operation caused an <code>IOException</code>
233: * @throws BackingStoreException
234: * if backing store is unavailable or causes operation failure
235: * @throws IllegalStateException
236: * if this node has been removed
237: */
238: public abstract void exportSubtree(OutputStream ostream)
239: throws IOException, BackingStoreException;
240:
241: /**
242: * Force the updates to this node and its descendants to the backing store.
243: * <p>
244: * If this node has been removed, then the invocation of this method only
245: * flush this node without descendants.
246: * </p>
247: * @throws BackingStoreException
248: * if backing store is unavailable or causes operation failure
249: */
250: public abstract void flush() throws BackingStoreException;
251:
252: /**
253: * Return the string value mapped to the given key, or default value if no
254: * value is mapped or backing store is unavailable.
255: * <p>
256: * Some implementations may store default values in backing stores. In this case,
257: * if there is no value mapped to the given key, the stored default value is
258: * returned.
259: * </p>
260: *
261: * @param key the preference key
262: * @param deflt the default value, which will be returned if no value is
263: * mapped to the given key or backing store unavailable
264: * @return the preference value mapped to the given key, or default value if
265: * no value is mapped or backing store unavailable
266: * @throws IllegalStateException
267: * if this node has been removed
268: * @throws NullPointerException
269: * if parameter key is null
270: */
271: public abstract String get(String key, String deflt);
272:
273: /**
274: * Return the boolean value mapped to the given key, or default value if no
275: * value is mapped, backing store is unavailable, or the value is invalid.
276: * <p>
277: * The valid value is string equals "true", which represents true, or "false",
278: * which represents false, case is ignored.
279: * </p>
280: * <p>
281: * Some implementations may store default values in backing stores. In this case,
282: * if there is no value mapped to the given key, the stored default value is
283: * returned.
284: * </p>
285: *
286: * @param key the preference key
287: * @param deflt the default value, which will be returned if no value is
288: * mapped to the given key, backing store unavailable or value
289: * is invalid
290: * @return the boolean value mapped to the given key, or default value if
291: * no value is mapped, backing store unavailable or value is invalid
292: * @throws IllegalStateException
293: * if this node has been removed
294: * @throws NullPointerException
295: * if parameter key is null
296: */
297: public abstract boolean getBoolean(String key, boolean deflt);
298:
299: /**
300: * Return the byte array value mapped to the given key, or default value if no
301: * value is mapped, backing store is unavailable, or the value is invalid string.
302: * <p>
303: * The valid value string is Base64 encoded binary data. The Base64 encoding
304: * is as defined in <a href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045</a>,
305: * section 6.8.
306: * </p>
307: * <p>
308: * Some implementations may store default values in backing stores. In this case,
309: * if there is no value mapped to the given key, the stored default value is
310: * returned.
311: * </p>
312: *
313: * @param key the preference key
314: * @param deflt the default value, which will be returned if no value is
315: * mapped to the given key, backing store unavailable or value
316: * is invalid
317: * @return the byte array value mapped to the given key, or default value if
318: * no value is mapped, backing store unavailable or value is invalid
319: * @throws IllegalStateException
320: * if this node has been removed
321: * @throws NullPointerException
322: * if parameter key is null
323: */
324: public abstract byte[] getByteArray(String key, byte[] deflt);
325:
326: /**
327: * Return the double value mapped to the given key, or default value if no
328: * value is mapped, backing store is unavailable, or the value is invalid string.
329: * <p>
330: * The valid value string can be converted to double number by
331: * {@link Double#parseDouble(String) Double.parseDouble(String)}.
332: * </p>
333: * <p>
334: * Some implementations may store default values in backing stores. In this case,
335: * if there is no value mapped to the given key, the stored default value is
336: * returned.
337: * </p>
338: *
339: * @param key the preference key
340: * @param deflt the default value, which will be returned if no value is
341: * mapped to the given key, backing store unavailable or value
342: * is invalid
343: * @return the double value mapped to the given key, or default value if
344: * no value is mapped, backing store unavailable or value is invalid
345: * @throws IllegalStateException
346: * if this node has been removed
347: * @throws NullPointerException
348: * if parameter key is null
349: */
350: public abstract double getDouble(String key, double deflt);
351:
352: /**
353: * Return the float value mapped to the given key, or default value if no
354: * value is mapped, backing store is unavailable, or the value is invalid string.
355: * <p>
356: * The valid value string can be converted to float number by
357: * {@link Float#parseFloat(String) Float.parseFloat(String)}.
358: * </p>
359: * <p>
360: * Some implementations may store default values in backing stores. In this case,
361: * if there is no value mapped to the given key, the stored default value is
362: * returned.
363: * </p>
364: *
365: * @param key the preference key
366: * @param deflt the default value, which will be returned if no value is
367: * mapped to the given key, backing store unavailable or value
368: * is invalid
369: * @return the float value mapped to the given key, or default value if
370: * no value is mapped, backing store unavailable or value is invalid
371: * @throws IllegalStateException
372: * if this node has been removed
373: * @throws NullPointerException
374: * if parameter key is null
375: */
376: public abstract float getFloat(String key, float deflt);
377:
378: /**
379: * Return the float value mapped to the given key, or default value if no
380: * value is mapped, backing store is unavailable, or the value is invalid string.
381: * <p>
382: * The valid value string can be converted to integer by
383: * {@link Integer#parseInt(String) Integer.parseInt(String)}.
384: * </p>
385: * <p>
386: * Some implementations may store default values in backing stores. In this case,
387: * if there is no value mapped to the given key, the stored default value is
388: * returned.
389: * </p>
390: *
391: * @param key the preference key
392: * @param deflt the default value, which will be returned if no value is
393: * mapped to the given key, backing store unavailable or value
394: * is invalid
395: * @return the integer value mapped to the given key, or default value if
396: * no value is mapped, backing store unavailable or value is invalid
397: * @throws IllegalStateException
398: * if this node has been removed
399: * @throws NullPointerException
400: * if parameter key is null
401: */
402: public abstract int getInt(String key, int deflt);
403:
404: /**
405: * Return the long value mapped to the given key, or default value if no
406: * value is mapped, backing store is unavailable, or the value is invalid string.
407: * <p>
408: * The valid value string can be converted to long integer by
409: * {@link Long#parseLong(String) Long.parseLong(String)}.
410: * </p>
411: * <p>
412: * Some implementations may store default values in backing stores. In this case,
413: * if there is no value mapped to the given key, the stored default value is
414: * returned.
415: * </p>
416: *
417: * @param key the preference key
418: * @param deflt the default value, which will be returned if no value is
419: * mapped to the given key, backing store unavailable or value
420: * is invalid
421: * @return the long value mapped to the given key, or default value if
422: * no value is mapped, backing store unavailable or value is invalid
423: * @throws IllegalStateException
424: * if this node has been removed
425: * @throws NullPointerException
426: * if parameter key is null
427: */
428: public abstract long getLong(String key, long deflt);
429:
430: /**
431: * Import all preferences from the given input stream in XML document.
432: * <p>
433: * This XML document has the following DOCTYPE declaration:
434: * <pre>
435: * <!DOCTYPE preferences SYSTEM "http://java.sun.com/dtd/preferences.dtd"></pre> *
436: * Please note that this node is not thread-safe, which is an exception of
437: * this class.
438: * </p>
439: *
440: * @param istream
441: * the given input stream to read data
442: * @throws InvalidPreferencesFormatException
443: * if the data read from given input stream is not valid XML
444: * document
445: * @throws IOException
446: * if import operation caused an <code>IOException</code>
447: * @throws SecurityException
448: * if <code>RuntimePermission("preferences")</code> is denied
449: * by a <code>SecurityManager</code>
450: */
451: public static void importPreferences(InputStream istream)
452: throws InvalidPreferencesFormatException, IOException {
453: checkSecurity();
454: if (null == istream) {
455: // prefs.0=Inputstream cannot be null\!
456: throw new MalformedURLException(Messages
457: .getString("prefs.0")); //$NON-NLS-1$
458: }
459: XMLParser.importPrefs(istream);
460: }
461:
462: /**
463: * Return true if this is a user preferences, false if this is a system
464: * preferences
465: *
466: * @return true if this is a user preferences, false if this is a
467: * system preferences
468: */
469: public abstract boolean isUserNode();
470:
471: /**
472: * Return all preferences keys stored in this node, or empty array if no
473: * key is found.
474: *
475: * @return all preferences keys in this node
476: * @throws BackingStoreException
477: * if backing store is unavailable or causes operation failure
478: * @throws IllegalStateException
479: * if this node has been removed
480: */
481: public abstract String[] keys() throws BackingStoreException;
482:
483: /**
484: * Return name of this node.
485: *
486: * @return the name of this node
487: */
488: public abstract String name();
489:
490: /**
491: * Return the preferences node with the given path name. The path name can
492: * be relative or absolute. The dictated preferences and its ancestors will
493: * be created if they do not exist.
494: * <p>
495: * The path is treated as relative to this node if it doesn't start with
496: * slash, or as absolute otherwise.</p>
497: *
498: * @param path the path name of dictated preferences
499: * @return the dictated preferences node
500: * @throws IllegalStateException
501: * if this node has been removed.
502: * @throws IllegalArgumentException
503: * if the path name is invalid.
504: * @throws NullPointerException
505: * if given path is null.
506: */
507: public abstract Preferences node(String path);
508:
509: /**
510: * Return the preferences node with the given path name. The path is treated
511: * as relative to this node if it doesn't start with slash, or as absolute
512: * otherwise.
513: * <p>
514: * Please note that if this node has been removed, invocation of this node
515: * will throw <code>IllegalStateException</code> except the given path is
516: * empty string, which will return false.
517: * </p>
518: *
519: * @param path the path name of dictated preferences
520: * @return true if the dictated preferences node exists
521: * @throws IllegalStateException
522: * if this node has been removed and the path is not empty string.
523: * @throws IllegalArgumentException
524: * if the path name is invalid.
525: * @throws NullPointerException
526: * if given path is null.
527: * @throws BackingStoreException
528: * if backing store is unavailable or causes operation failure
529: */
530: public abstract boolean nodeExists(String path)
531: throws BackingStoreException;
532:
533: /**
534: * Return the parent preferences node of this node, or null if this node is root.
535: *
536: * @return the parent preferences node of this node.
537: * @throws IllegalStateException
538: * if this node has been removed
539: */
540: public abstract Preferences parent();
541:
542: /**
543: * Add new preferences to this node using given key and value, or update
544: * value if preferences with given key has already existed.
545: *
546: * @param key the preferences key to be added or be updated
547: * @param value the preferences value for the given key
548: * @throws NullPointerException
549: * if the given key or value is null
550: * @throws IllegalArgumentException
551: * if the given key's length is bigger than
552: * <code>MAX_KEY_LENGTH</code>, or the value's length is bigger
553: * than <code>MAX_VALUE_LENGTH</code>
554: * @throws IllegalStateException
555: * if this node has been removed
556: */
557: public abstract void put(String key, String value);
558:
559: /**
560: * Add new preferences to this node using given key and string form of given
561: * value, or update value if preferences with given key has already existed.
562: *
563: * @param key the preferences key to be added or be updated
564: * @param value the preferences value for the given key
565: * @throws NullPointerException
566: * if the given key is null
567: * @throws IllegalArgumentException
568: * if the given key's length is bigger than
569: * <code>MAX_KEY_LENGTH</code>
570: * @throws IllegalStateException
571: * if this node has been removed
572: */
573: public abstract void putBoolean(String key, boolean value);
574:
575: /**
576: * Add new preferences to this node using given key and string form of given
577: * value, or update value if preferences with given key has already existed.
578: * <p>
579: * The string form of value is the Base64 encoded binary data of the given
580: * byte array. The Base64 encoding is as defined in
581: * <a href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045</a>, section 6.8.</p>
582: *
583: * @param key the preferences key to be added or be updated
584: * @param value the preferences value for the given key
585: * @throws NullPointerException
586: * if the given key or value is null
587: * @throws IllegalArgumentException
588: * if the given key's length is bigger than
589: * <code>MAX_KEY_LENGTH</code> or value's length is bigger than
590: * three quarters of <code>MAX_KEY_LENGTH</code>
591: * @throws IllegalStateException
592: * if this node has been removed
593: */
594: public abstract void putByteArray(String key, byte[] value);
595:
596: /**
597: * Add new preferences to this node using given key and string form of given
598: * value, or update value if preferences with given key has already existed.
599: * <p>
600: * The string form of given value is the result of invoking
601: * {@link Double#toString(double) Double.toString(double)}</p>
602: *
603: * @param key the preferences key to be added or be updated
604: * @param value the preferences value for the given key
605: * @throws NullPointerException
606: * if the given key is null
607: * @throws IllegalArgumentException
608: * if the given key's length is bigger than
609: * <code>MAX_KEY_LENGTH</code>
610: * @throws IllegalStateException
611: * if this node has been removed
612: */
613: public abstract void putDouble(String key, double value);
614:
615: /**
616: * Add new preferences to this node using given key and string form of given
617: * value, or update value if preferences with given key has already existed.
618: * <p>
619: * The string form of given value is the result of invoking
620: * {@link Float#toString(float) Float.toString(float)}</p>
621: *
622: * @param key the preferences key to be added or be updated
623: * @param value the preferences value for the given key
624: * @throws NullPointerException
625: * if the given key is null
626: * @throws IllegalArgumentException
627: * if the given key's length is bigger than
628: * <code>MAX_KEY_LENGTH</code>
629: * @throws IllegalStateException
630: * if this node has been removed
631: */
632: public abstract void putFloat(String key, float value);
633:
634: /**
635: * Add new preferences to this node using given key and string form of given
636: * value, or update value if preferences with given key has already existed.
637: * <p>
638: * The string form of given value is the result of invoking
639: * {@link Integer#toString(int) Integer.toString(int)}</p>
640: *
641: * @param key the preferences key to be added or be updated
642: * @param value the preferences value for the given key
643: * @throws NullPointerException
644: * if the given key is null
645: * @throws IllegalArgumentException
646: * if the given key's length is bigger than
647: * <code>MAX_KEY_LENGTH</code>
648: * @throws IllegalStateException
649: * if this node has been removed
650: */
651: public abstract void putInt(String key, int value);
652:
653: /**
654: * Add new preferences to this node using given key and string form of given
655: * value, or update value if preferences with given key has already existed.
656: * <p>
657: * The string form of given value is the result of invoking
658: * {@link Long#toString(long) Long.toString(long)}</p>
659: *
660: * @param key the preferences key to be added or be updated
661: * @param value the preferences value for the given key
662: * @throws NullPointerException
663: * if the given key is null
664: * @throws IllegalArgumentException
665: * if the given key's length is bigger than
666: * <code>MAX_KEY_LENGTH</code>
667: * @throws IllegalStateException
668: * if this node has been removed
669: */
670: public abstract void putLong(String key, long value);
671:
672: /**
673: * Remove the preferences mapped to the given key from this node.
674: *
675: * @param key the given preferences key to removed
676: * @throws NullPointerException
677: * if the given key is null
678: * @throws IllegalStateException
679: * if this node has been removed
680: */
681: public abstract void remove(String key);
682:
683: /**
684: * Remove this preferences node and its all descendants. The removal maybe
685: * won't be persisted until the <code>flush()</code> method is invoked.
686: *
687: * @throws BackingStoreException
688: * if backing store is unavailable or causes operation failure
689: * @throws IllegalStateException
690: * if this node has been removed
691: * @throws UnsupportedOperationException
692: * if this is a root node
693: */
694: public abstract void removeNode() throws BackingStoreException;
695:
696: /**
697: * Register an <code>NodeChangeListener</code> instance for this node, which
698: * will receive <code>NodeChangeEvent</code>. <code>NodeChangeEvent</code> will
699: * be produced when direct child node is added to or removed from this node.
700: *
701: * @param ncl the given listener to be registered
702: * @throws NullPointerException
703: * if the given listener is null
704: * @throws IllegalStateException
705: * if this node has been removed
706: */
707: public abstract void addNodeChangeListener(NodeChangeListener ncl);
708:
709: /**
710: * Register an <code>PreferenceChangeListener</code> instance for this node, which
711: * will receive <code>PreferenceChangeEvent</code>. <code>PreferenceChangeEvent</code> will
712: * be produced when preference is added to, removed from or updated for this node.
713: *
714: * @param pcl the given listener to be registered
715: * @throws NullPointerException
716: * if the given listener is null
717: * @throws IllegalStateException
718: * if this node has been removed
719: */
720: public abstract void addPreferenceChangeListener(
721: PreferenceChangeListener pcl);
722:
723: /**
724: * Remove the given <code>NodeChangeListener</code> instance from this node.
725: *
726: * @param ncl the given listener to be removed
727: * @throws IllegalArgumentException
728: * if the given listener
729: * @throws IllegalStateException
730: * if this node has been removed
731: */
732: public abstract void removeNodeChangeListener(NodeChangeListener ncl);
733:
734: /**
735: * Remove the given <code>PreferenceChangeListener</code> instance from this node.
736: *
737: * @param pcl the given listener to be removed
738: * @throws IllegalArgumentException
739: * if the given listener
740: * @throws IllegalStateException
741: * if this node has been removed
742: */
743: public abstract void removePreferenceChangeListener(
744: PreferenceChangeListener pcl);
745:
746: /**
747: * Synchronize this preferences node and its descendants' data with the back
748: * end preferences store. The changes of back end should be reflect by this
749: * node and its descendants, meanwhile, the changes of this node and descendants
750: * should be persisted.
751: *
752: * @throws BackingStoreException
753: * if backing store is unavailable or causes operation failure
754: * @throws IllegalStateException
755: * if this node has been removed
756: */
757: public abstract void sync() throws BackingStoreException;
758:
759: /**
760: * Return the system preference node for the package of given class. The
761: * absolute path of the returned node is one slash followed by the given
762: * class's full package name with replacing each period ('.') with slash.
763: * For example, the preference's associated with class <code>Object<code>
764: * has absolute path like "/java/lang". As a special case, the unnamed
765: * package is associated with preference node "/<unnamed>".
766: *
767: * This method will create node and its ancestors if needed, and the new
768: * created nodes maybe won't be persisted until the <code>flush()</code>
769: * is invoked.
770: *
771: * @param c the given class
772: * @return the system preference node for the package of given class.
773: * @throws NullPointerException
774: * if the given class is null
775: * @throws SecurityException
776: * if <code>RuntimePermission("preferences")</code> is denied
777: * by a <code>SecurityManager</code>
778: */
779: public static Preferences systemNodeForPackage(Class<?> c) {
780: checkSecurity();
781: return factory.systemRoot().node(getNodeName(c));
782: }
783:
784: /**
785: * Return the root node for system preference hierarchy.
786: *
787: * @return the root node for system preference hierarchy
788: * @throws SecurityException
789: * if <code>RuntimePermission("preferences")</code> is denied
790: * by a <code>SecurityManager</code>
791: */
792: public static Preferences systemRoot() {
793: checkSecurity();
794: return factory.systemRoot();
795: }
796:
797: //check the RuntimePermission("preferences")
798: private static void checkSecurity() {
799: SecurityManager manager = System.getSecurityManager();
800: if (null != manager) {
801: manager.checkPermission(PREFS_PERM);
802: }
803:
804: }
805:
806: /**
807: * Return the user preference node for the package of given class. The
808: * absolute path of the returned node is one slash followed by the given
809: * class's full package name with replacing each period ('.') with slash.
810: * For example, the preference's associated with class <code>Object<code>
811: * has absolute path like "/java/lang". As a special case, the unnamed
812: * package is associated with preference node "/<unnamed>".
813: *
814: * This method will create node and its ancestors if needed, and the new
815: * created nodes maybe won't be persisted until the <code>flush()</code>
816: * is invoked.
817: *
818: * @param c the given class
819: * @return the user preference node for the package of given class.
820: * @throws NullPointerException
821: * if the given class is null
822: * @throws SecurityException
823: * if <code>RuntimePermission("preferences")</code> is denied
824: * by a <code>SecurityManager</code>
825: */
826: public static Preferences userNodeForPackage(Class<?> c) {
827: checkSecurity();
828: return factory.userRoot().node(getNodeName(c));
829: }
830:
831: //parse node's absolute path from class instance
832: private static String getNodeName(Class<?> c) {
833: Package p = c.getPackage();
834: if (null == p) {
835: return "/<unnamed>"; //$NON-NLS-1$
836: }
837: return "/" + p.getName().replace('.', '/'); //$NON-NLS-1$
838: }
839:
840: /**
841: * Return the root node for user preference hierarchy.
842: *
843: * @return the root node for user preference hierarchy
844: * @throws SecurityException
845: * if <code>RuntimePermission("preferences")</code> is denied
846: * by a <code>SecurityManager</code>
847: */
848: public static Preferences userRoot() {
849: checkSecurity();
850: return factory.userRoot();
851: }
852:
853: /**
854: * Return a string description of this node. The format is "User/System
855: * Preference Node: " followed by this node's absolute path.
856: *
857: * @return a string description of this node
858: *
859: */
860: @Override
861: public abstract String toString();
862: }
|