0001 /*
0002 * Copyright 2000-2006 Sun Microsystems, Inc. All Rights Reserved.
0003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0004 *
0005 * This code is free software; you can redistribute it and/or modify it
0006 * under the terms of the GNU General Public License version 2 only, as
0007 * published by the Free Software Foundation. Sun designates this
0008 * particular file as subject to the "Classpath" exception as provided
0009 * by Sun in the LICENSE file that accompanied this code.
0010 *
0011 * This code is distributed in the hope that it will be useful, but WITHOUT
0012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0013 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0014 * version 2 for more details (a copy is included in the LICENSE file that
0015 * accompanied this code).
0016 *
0017 * You should have received a copy of the GNU General Public License version
0018 * 2 along with this work; if not, write to the Free Software Foundation,
0019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0020 *
0021 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
0022 * CA 95054 USA or visit www.sun.com if you need additional information or
0023 * have any questions.
0024 */
0025
0026 package java.util.prefs;
0027
0028 import java.io.InputStream;
0029 import java.io.IOException;
0030 import java.io.OutputStream;
0031 import java.security.AccessController;
0032 import java.security.Permission;
0033 import java.security.PrivilegedAction;
0034 import java.util.Iterator;
0035 import sun.misc.Service;
0036 import sun.misc.ServiceConfigurationError;
0037
0038 // These imports needed only as a workaround for a JavaDoc bug
0039 import java.lang.RuntimePermission;
0040 import java.lang.Integer;
0041 import java.lang.Long;
0042 import java.lang.Float;
0043 import java.lang.Double;
0044
0045 /**
0046 * A node in a hierarchical collection of preference data. This class
0047 * allows applications to store and retrieve user and system
0048 * preference and configuration data. This data is stored
0049 * persistently in an implementation-dependent backing store. Typical
0050 * implementations include flat files, OS-specific registries,
0051 * directory servers and SQL databases. The user of this class needn't
0052 * be concerned with details of the backing store.
0053 *
0054 * <p>There are two separate trees of preference nodes, one for user
0055 * preferences and one for system preferences. Each user has a separate user
0056 * preference tree, and all users in a given system share the same system
0057 * preference tree. The precise description of "user" and "system" will vary
0058 * from implementation to implementation. Typical information stored in the
0059 * user preference tree might include font choice, color choice, or preferred
0060 * window location and size for a particular application. Typical information
0061 * stored in the system preference tree might include installation
0062 * configuration data for an application.
0063 *
0064 * <p>Nodes in a preference tree are named in a similar fashion to
0065 * directories in a hierarchical file system. Every node in a preference
0066 * tree has a <i>node name</i> (which is not necessarily unique),
0067 * a unique <i>absolute path name</i>, and a path name <i>relative</i> to each
0068 * ancestor including itself.
0069 *
0070 * <p>The root node has a node name of the empty string (""). Every other
0071 * node has an arbitrary node name, specified at the time it is created. The
0072 * only restrictions on this name are that it cannot be the empty string, and
0073 * it cannot contain the slash character ('/').
0074 *
0075 * <p>The root node has an absolute path name of <tt>"/"</tt>. Children of
0076 * the root node have absolute path names of <tt>"/" + </tt><i><node
0077 * name></i>. All other nodes have absolute path names of <i><parent's
0078 * absolute path name></i><tt> + "/" + </tt><i><node name></i>.
0079 * Note that all absolute path names begin with the slash character.
0080 *
0081 * <p>A node <i>n</i>'s path name relative to its ancestor <i>a</i>
0082 * is simply the string that must be appended to <i>a</i>'s absolute path name
0083 * in order to form <i>n</i>'s absolute path name, with the initial slash
0084 * character (if present) removed. Note that:
0085 * <ul>
0086 * <li>No relative path names begin with the slash character.
0087 * <li>Every node's path name relative to itself is the empty string.
0088 * <li>Every node's path name relative to its parent is its node name (except
0089 * for the root node, which does not have a parent).
0090 * <li>Every node's path name relative to the root is its absolute path name
0091 * with the initial slash character removed.
0092 * </ul>
0093 *
0094 * <p>Note finally that:
0095 * <ul>
0096 * <li>No path name contains multiple consecutive slash characters.
0097 * <li>No path name with the exception of the root's absolute path name
0098 * ends in the slash character.
0099 * <li>Any string that conforms to these two rules is a valid path name.
0100 * </ul>
0101 *
0102 * <p>All of the methods that modify preferences data are permitted to operate
0103 * asynchronously; they may return immediately, and changes will eventually
0104 * propagate to the persistent backing store with an implementation-dependent
0105 * delay. The <tt>flush</tt> method may be used to synchronously force
0106 * updates to the backing store. Normal termination of the Java Virtual
0107 * Machine will <i>not</i> result in the loss of pending updates -- an explicit
0108 * <tt>flush</tt> invocation is <i>not</i> required upon termination to ensure
0109 * that pending updates are made persistent.
0110 *
0111 * <p>All of the methods that read preferences from a <tt>Preferences</tt>
0112 * object require the invoker to provide a default value. The default value is
0113 * returned if no value has been previously set <i>or if the backing store is
0114 * unavailable</i>. The intent is to allow applications to operate, albeit
0115 * with slightly degraded functionality, even if the backing store becomes
0116 * unavailable. Several methods, like <tt>flush</tt>, have semantics that
0117 * prevent them from operating if the backing store is unavailable. Ordinary
0118 * applications should have no need to invoke any of these methods, which can
0119 * be identified by the fact that they are declared to throw {@link
0120 * BackingStoreException}.
0121 *
0122 * <p>The methods in this class may be invoked concurrently by multiple threads
0123 * in a single JVM without the need for external synchronization, and the
0124 * results will be equivalent to some serial execution. If this class is used
0125 * concurrently <i>by multiple JVMs</i> that store their preference data in
0126 * the same backing store, the data store will not be corrupted, but no
0127 * other guarantees are made concerning the consistency of the preference
0128 * data.
0129 *
0130 * <p>This class contains an export/import facility, allowing preferences
0131 * to be "exported" to an XML document, and XML documents representing
0132 * preferences to be "imported" back into the system. This facility
0133 * may be used to back up all or part of a preference tree, and
0134 * subsequently restore from the backup.
0135 *
0136 * <p>The XML document has the following DOCTYPE declaration:
0137 * <pre>
0138 * <!DOCTYPE preferences SYSTEM "http://java.sun.com/dtd/preferences.dtd">
0139 * </pre>
0140 * Note that the system URI (http://java.sun.com/dtd/preferences.dtd) is
0141 * <i>not</i> accessed when exporting or importing preferences; it merely
0142 * serves as a string to uniquely identify the DTD, which is:
0143 * <pre>
0144 * <?xml version="1.0" encoding="UTF-8"?>
0145 *
0146 * <!-- DTD for a Preferences tree. -->
0147 *
0148 * <!-- The preferences element is at the root of an XML document
0149 * representing a Preferences tree. -->
0150 * <!ELEMENT preferences (root)>
0151 *
0152 * <!-- The preferences element contains an optional version attribute,
0153 * which specifies version of DTD. -->
0154 * <!ATTLIST preferences EXTERNAL_XML_VERSION CDATA "0.0" >
0155 *
0156 * <!-- The root element has a map representing the root's preferences
0157 * (if any), and one node for each child of the root (if any). -->
0158 * <!ELEMENT root (map, node*) >
0159 *
0160 * <!-- Additionally, the root contains a type attribute, which
0161 * specifies whether it's the system or user root. -->
0162 * <!ATTLIST root
0163 * type (system|user) #REQUIRED >
0164 *
0165 * <!-- Each node has a map representing its preferences (if any),
0166 * and one node for each child (if any). -->
0167 * <!ELEMENT node (map, node*) >
0168 *
0169 * <!-- Additionally, each node has a name attribute -->
0170 * <!ATTLIST node
0171 * name CDATA #REQUIRED >
0172 *
0173 * <!-- A map represents the preferences stored at a node (if any). -->
0174 * <!ELEMENT map (entry*) >
0175 *
0176 * <!-- An entry represents a single preference, which is simply
0177 * a key-value pair. -->
0178 * <!ELEMENT entry EMPTY >
0179 * <!ATTLIST entry
0180 * key CDATA #REQUIRED
0181 * value CDATA #REQUIRED >
0182 * </pre>
0183 *
0184 * Every <tt>Preferences</tt> implementation must have an associated {@link
0185 * PreferencesFactory} implementation. Every Java(TM) SE implementation must provide
0186 * some means of specifying which <tt>PreferencesFactory</tt> implementation
0187 * is used to generate the root preferences nodes. This allows the
0188 * administrator to replace the default preferences implementation with an
0189 * alternative implementation.
0190 *
0191 * <p>Implementation note: In Sun's JRE, the <tt>PreferencesFactory</tt>
0192 * implementation is located as follows:
0193 *
0194 * <ol>
0195 *
0196 * <li><p>If the system property
0197 * <tt>java.util.prefs.PreferencesFactory</tt> is defined, then it is
0198 * taken to be the fully-qualified name of a class implementing the
0199 * <tt>PreferencesFactory</tt> interface. The class is loaded and
0200 * instantiated; if this process fails then an unspecified error is
0201 * thrown.</p></li>
0202 *
0203 * <li><p> If a <tt>PreferencesFactory</tt> implementation class file
0204 * has been installed in a jar file that is visible to the
0205 * {@link java.lang.ClassLoader#getSystemClassLoader system class loader},
0206 * and that jar file contains a provider-configuration file named
0207 * <tt>java.util.prefs.PreferencesFactory</tt> in the resource
0208 * directory <tt>META-INF/services</tt>, then the first class name
0209 * specified in that file is taken. If more than one such jar file is
0210 * provided, the first one found will be used. The class is loaded
0211 * and instantiated; if this process fails then an unspecified error
0212 * is thrown. </p></li>
0213 *
0214 * <li><p>Finally, if neither the above-mentioned system property nor
0215 * an extension jar file is provided, then the system-wide default
0216 * <tt>PreferencesFactory</tt> implementation for the underlying
0217 * platform is loaded and instantiated.</p></li>
0218 *
0219 * </ol>
0220 *
0221 * @author Josh Bloch
0222 * @version 1.36, 05/05/07
0223 * @since 1.4
0224 */
0225 public abstract class Preferences {
0226
0227 private static final PreferencesFactory factory = factory();
0228
0229 private static PreferencesFactory factory() {
0230 // 1. Try user-specified system property
0231 String factoryName = AccessController
0232 .doPrivileged(new PrivilegedAction<String>() {
0233 public String run() {
0234 return System
0235 .getProperty("java.util.prefs.PreferencesFactory");
0236 }
0237 });
0238 if (factoryName != null) {
0239 // FIXME: This code should be run in a doPrivileged and
0240 // not use the context classloader, to avoid being
0241 // dependent on the invoking thread.
0242 // Checking AllPermission also seems wrong.
0243 try {
0244 return (PreferencesFactory) Class.forName(factoryName,
0245 false, ClassLoader.getSystemClassLoader())
0246 .newInstance();
0247 } catch (Exception ex) {
0248 try {
0249 // workaround for javaws, plugin,
0250 // load factory class using non-system classloader
0251 SecurityManager sm = System.getSecurityManager();
0252 if (sm != null) {
0253 sm
0254 .checkPermission(new java.security.AllPermission());
0255 }
0256 return (PreferencesFactory) Class.forName(
0257 factoryName,
0258 false,
0259 Thread.currentThread()
0260 .getContextClassLoader())
0261 .newInstance();
0262 } catch (Exception e) {
0263 InternalError error = new InternalError(
0264 "Can't instantiate Preferences factory "
0265 + factoryName);
0266 error.initCause(e);
0267 throw error;
0268 }
0269 }
0270 }
0271
0272 return AccessController
0273 .doPrivileged(new PrivilegedAction<PreferencesFactory>() {
0274 public PreferencesFactory run() {
0275 return factory1();
0276 }
0277 });
0278 }
0279
0280 private static PreferencesFactory factory1() {
0281 // 2. Try service provider interface
0282 Iterator i = Service.providers(PreferencesFactory.class,
0283 ClassLoader.getSystemClassLoader());
0284 // choose first provider instance
0285 while (i.hasNext()) {
0286 try {
0287 return (PreferencesFactory) i.next();
0288 } catch (ServiceConfigurationError sce) {
0289 if (sce.getCause() instanceof SecurityException) {
0290 // Ignore the security exception, try the next provider
0291 continue;
0292 }
0293 throw sce;
0294 }
0295 }
0296
0297 // 3. Use platform-specific system-wide default
0298 String platformFactory = System.getProperty("os.name")
0299 .startsWith("Windows") ? "java.util.prefs.WindowsPreferencesFactory"
0300 : "java.util.prefs.FileSystemPreferencesFactory";
0301 try {
0302 return (PreferencesFactory) Class.forName(platformFactory,
0303 false, null).newInstance();
0304 } catch (Exception e) {
0305 InternalError error = new InternalError(
0306 "Can't instantiate platform default Preferences factory "
0307 + platformFactory);
0308 error.initCause(e);
0309 throw error;
0310 }
0311 }
0312
0313 /**
0314 * Maximum length of string allowed as a key (80 characters).
0315 */
0316 public static final int MAX_KEY_LENGTH = 80;
0317
0318 /**
0319 * Maximum length of string allowed as a value (8192 characters).
0320 */
0321 public static final int MAX_VALUE_LENGTH = 8 * 1024;
0322
0323 /**
0324 * Maximum length of a node name (80 characters).
0325 */
0326 public static final int MAX_NAME_LENGTH = 80;
0327
0328 /**
0329 * Returns the preference node from the calling user's preference tree
0330 * that is associated (by convention) with the specified class's package.
0331 * The convention is as follows: the absolute path name of the node is the
0332 * fully qualified package name, preceded by a slash (<tt>'/'</tt>), and
0333 * with each period (<tt>'.'</tt>) replaced by a slash. For example the
0334 * absolute path name of the node associated with the class
0335 * <tt>com.acme.widget.Foo</tt> is <tt>/com/acme/widget</tt>.
0336 *
0337 * <p>This convention does not apply to the unnamed package, whose
0338 * associated preference node is <tt><unnamed></tt>. This node
0339 * is not intended for long term use, but for convenience in the early
0340 * development of programs that do not yet belong to a package, and
0341 * for "throwaway" programs. <i>Valuable data should not be stored
0342 * at this node as it is shared by all programs that use it.</i>
0343 *
0344 * <p>A class <tt>Foo</tt> wishing to access preferences pertaining to its
0345 * package can obtain a preference node as follows: <pre>
0346 * static Preferences prefs = Preferences.userNodeForPackage(Foo.class);
0347 * </pre>
0348 * This idiom obviates the need for using a string to describe the
0349 * preferences node and decreases the likelihood of a run-time failure.
0350 * (If the class name is misspelled, it will typically result in a
0351 * compile-time error.)
0352 *
0353 * <p>Invoking this method will result in the creation of the returned
0354 * node and its ancestors if they do not already exist. If the returned
0355 * node did not exist prior to this call, this node and any ancestors that
0356 * were created by this call are not guaranteed to become permanent until
0357 * the <tt>flush</tt> method is called on the returned node (or one of its
0358 * ancestors or descendants).
0359 *
0360 * @param c the class for whose package a user preference node is desired.
0361 * @return the user preference node associated with the package of which
0362 * <tt>c</tt> is a member.
0363 * @throws NullPointerException if <tt>c</tt> is <tt>null</tt>.
0364 * @throws SecurityException if a security manager is present and
0365 * it denies <tt>RuntimePermission("preferences")</tt>.
0366 * @see RuntimePermission
0367 */
0368 public static Preferences userNodeForPackage(Class<?> c) {
0369 return userRoot().node(nodeName(c));
0370 }
0371
0372 /**
0373 * Returns the preference node from the system preference tree that is
0374 * associated (by convention) with the specified class's package. The
0375 * convention is as follows: the absolute path name of the node is the
0376 * fully qualified package name, preceded by a slash (<tt>'/'</tt>), and
0377 * with each period (<tt>'.'</tt>) replaced by a slash. For example the
0378 * absolute path name of the node associated with the class
0379 * <tt>com.acme.widget.Foo</tt> is <tt>/com/acme/widget</tt>.
0380 *
0381 * <p>This convention does not apply to the unnamed package, whose
0382 * associated preference node is <tt><unnamed></tt>. This node
0383 * is not intended for long term use, but for convenience in the early
0384 * development of programs that do not yet belong to a package, and
0385 * for "throwaway" programs. <i>Valuable data should not be stored
0386 * at this node as it is shared by all programs that use it.</i>
0387 *
0388 * <p>A class <tt>Foo</tt> wishing to access preferences pertaining to its
0389 * package can obtain a preference node as follows: <pre>
0390 * static Preferences prefs = Preferences.systemNodeForPackage(Foo.class);
0391 * </pre>
0392 * This idiom obviates the need for using a string to describe the
0393 * preferences node and decreases the likelihood of a run-time failure.
0394 * (If the class name is misspelled, it will typically result in a
0395 * compile-time error.)
0396 *
0397 * <p>Invoking this method will result in the creation of the returned
0398 * node and its ancestors if they do not already exist. If the returned
0399 * node did not exist prior to this call, this node and any ancestors that
0400 * were created by this call are not guaranteed to become permanent until
0401 * the <tt>flush</tt> method is called on the returned node (or one of its
0402 * ancestors or descendants).
0403 *
0404 * @param c the class for whose package a system preference node is desired.
0405 * @return the system preference node associated with the package of which
0406 * <tt>c</tt> is a member.
0407 * @throws NullPointerException if <tt>c</tt> is <tt>null</tt>.
0408 * @throws SecurityException if a security manager is present and
0409 * it denies <tt>RuntimePermission("preferences")</tt>.
0410 * @see RuntimePermission
0411 */
0412 public static Preferences systemNodeForPackage(Class<?> c) {
0413 return systemRoot().node(nodeName(c));
0414 }
0415
0416 /**
0417 * Returns the absolute path name of the node corresponding to the package
0418 * of the specified object.
0419 *
0420 * @throws IllegalArgumentException if the package has node preferences
0421 * node associated with it.
0422 */
0423 private static String nodeName(Class c) {
0424 if (c.isArray())
0425 throw new IllegalArgumentException(
0426 "Arrays have no associated preferences node.");
0427 String className = c.getName();
0428 int pkgEndIndex = className.lastIndexOf('.');
0429 if (pkgEndIndex < 0)
0430 return "/<unnamed>";
0431 String packageName = className.substring(0, pkgEndIndex);
0432 return "/" + packageName.replace('.', '/');
0433 }
0434
0435 /**
0436 * This permission object represents the permission required to get
0437 * access to the user or system root (which in turn allows for all
0438 * other operations).
0439 */
0440 private static Permission prefsPerm = new RuntimePermission(
0441 "preferences");
0442
0443 /**
0444 * Returns the root preference node for the calling user.
0445 *
0446 * @return the root preference node for the calling user.
0447 * @throws SecurityException If a security manager is present and
0448 * it denies <tt>RuntimePermission("preferences")</tt>.
0449 * @see RuntimePermission
0450 */
0451 public static Preferences userRoot() {
0452 SecurityManager security = System.getSecurityManager();
0453 if (security != null)
0454 security.checkPermission(prefsPerm);
0455
0456 return factory.userRoot();
0457 }
0458
0459 /**
0460 * Returns the root preference node for the system.
0461 *
0462 * @return the root preference node for the system.
0463 * @throws SecurityException If a security manager is present and
0464 * it denies <tt>RuntimePermission("preferences")</tt>.
0465 * @see RuntimePermission
0466 */
0467 public static Preferences systemRoot() {
0468 SecurityManager security = System.getSecurityManager();
0469 if (security != null)
0470 security.checkPermission(prefsPerm);
0471
0472 return factory.systemRoot();
0473 }
0474
0475 /**
0476 * Sole constructor. (For invocation by subclass constructors, typically
0477 * implicit.)
0478 */
0479 protected Preferences() {
0480 }
0481
0482 /**
0483 * Associates the specified value with the specified key in this
0484 * preference node.
0485 *
0486 * @param key key with which the specified value is to be associated.
0487 * @param value value to be associated with the specified key.
0488 * @throws NullPointerException if key or value is <tt>null</tt>.
0489 * @throws IllegalArgumentException if <tt>key.length()</tt> exceeds
0490 * <tt>MAX_KEY_LENGTH</tt> or if <tt>value.length</tt> exceeds
0491 * <tt>MAX_VALUE_LENGTH</tt>.
0492 * @throws IllegalStateException if this node (or an ancestor) has been
0493 * removed with the {@link #removeNode()} method.
0494 */
0495 public abstract void put(String key, String value);
0496
0497 /**
0498 * Returns the value associated with the specified key in this preference
0499 * node. Returns the specified default if there is no value associated
0500 * with the key, or the backing store is inaccessible.
0501 *
0502 * <p>Some implementations may store default values in their backing
0503 * stores. If there is no value associated with the specified key
0504 * but there is such a <i>stored default</i>, it is returned in
0505 * preference to the specified default.
0506 *
0507 * @param key key whose associated value is to be returned.
0508 * @param def the value to be returned in the event that this
0509 * preference node has no value associated with <tt>key</tt>.
0510 * @return the value associated with <tt>key</tt>, or <tt>def</tt>
0511 * if no value is associated with <tt>key</tt>, or the backing
0512 * store is inaccessible.
0513 * @throws IllegalStateException if this node (or an ancestor) has been
0514 * removed with the {@link #removeNode()} method.
0515 * @throws NullPointerException if <tt>key</tt> is <tt>null</tt>. (A
0516 * <tt>null</tt> value for <tt>def</tt> <i>is</i> permitted.)
0517 */
0518 public abstract String get(String key, String def);
0519
0520 /**
0521 * Removes the value associated with the specified key in this preference
0522 * node, if any.
0523 *
0524 * <p>If this implementation supports <i>stored defaults</i>, and there is
0525 * such a default for the specified preference, the stored default will be
0526 * "exposed" by this call, in the sense that it will be returned
0527 * by a succeeding call to <tt>get</tt>.
0528 *
0529 * @param key key whose mapping is to be removed from the preference node.
0530 * @throws NullPointerException if <tt>key</tt> is <tt>null</tt>.
0531 * @throws IllegalStateException if this node (or an ancestor) has been
0532 * removed with the {@link #removeNode()} method.
0533 */
0534 public abstract void remove(String key);
0535
0536 /**
0537 * Removes all of the preferences (key-value associations) in this
0538 * preference node. This call has no effect on any descendants
0539 * of this node.
0540 *
0541 * <p>If this implementation supports <i>stored defaults</i>, and this
0542 * node in the preferences hierarchy contains any such defaults,
0543 * the stored defaults will be "exposed" by this call, in the sense that
0544 * they will be returned by succeeding calls to <tt>get</tt>.
0545 *
0546 * @throws BackingStoreException if this operation cannot be completed
0547 * due to a failure in the backing store, or inability to
0548 * communicate with it.
0549 * @throws IllegalStateException if this node (or an ancestor) has been
0550 * removed with the {@link #removeNode()} method.
0551 * @see #removeNode()
0552 */
0553 public abstract void clear() throws BackingStoreException;
0554
0555 /**
0556 * Associates a string representing the specified int value with the
0557 * specified key in this preference node. The associated string is the
0558 * one that would be returned if the int value were passed to
0559 * {@link Integer#toString(int)}. This method is intended for use in
0560 * conjunction with {@link #getInt}.
0561 *
0562 * @param key key with which the string form of value is to be associated.
0563 * @param value value whose string form is to be associated with key.
0564 * @throws NullPointerException if <tt>key</tt> is <tt>null</tt>.
0565 * @throws IllegalArgumentException if <tt>key.length()</tt> exceeds
0566 * <tt>MAX_KEY_LENGTH</tt>.
0567 * @throws IllegalStateException if this node (or an ancestor) has been
0568 * removed with the {@link #removeNode()} method.
0569 * @see #getInt(String,int)
0570 */
0571 public abstract void putInt(String key, int value);
0572
0573 /**
0574 * Returns the int value represented by the string associated with the
0575 * specified key in this preference node. The string is converted to
0576 * an integer as by {@link Integer#parseInt(String)}. Returns the
0577 * specified default if there is no value associated with the key,
0578 * the backing store is inaccessible, or if
0579 * <tt>Integer.parseInt(String)</tt> would throw a {@link
0580 * NumberFormatException} if the associated value were passed. This
0581 * method is intended for use in conjunction with {@link #putInt}.
0582 *
0583 * <p>If the implementation supports <i>stored defaults</i> and such a
0584 * default exists, is accessible, and could be converted to an int
0585 * with <tt>Integer.parseInt</tt>, this int is returned in preference to
0586 * the specified default.
0587 *
0588 * @param key key whose associated value is to be returned as an int.
0589 * @param def the value to be returned in the event that this
0590 * preference node has no value associated with <tt>key</tt>
0591 * or the associated value cannot be interpreted as an int,
0592 * or the backing store is inaccessible.
0593 * @return the int value represented by the string associated with
0594 * <tt>key</tt> in this preference node, or <tt>def</tt> if the
0595 * associated value does not exist or cannot be interpreted as
0596 * an int.
0597 * @throws IllegalStateException if this node (or an ancestor) has been
0598 * removed with the {@link #removeNode()} method.
0599 * @throws NullPointerException if <tt>key</tt> is <tt>null</tt>.
0600 * @see #putInt(String,int)
0601 * @see #get(String,String)
0602 */
0603 public abstract int getInt(String key, int def);
0604
0605 /**
0606 * Associates a string representing the specified long value with the
0607 * specified key in this preference node. The associated string is the
0608 * one that would be returned if the long value were passed to
0609 * {@link Long#toString(long)}. This method is intended for use in
0610 * conjunction with {@link #getLong}.
0611 *
0612 * @param key key with which the string form of value is to be associated.
0613 * @param value value whose string form is to be associated with key.
0614 * @throws NullPointerException if <tt>key</tt> is <tt>null</tt>.
0615 * @throws IllegalArgumentException if <tt>key.length()</tt> exceeds
0616 * <tt>MAX_KEY_LENGTH</tt>.
0617 * @throws IllegalStateException if this node (or an ancestor) has been
0618 * removed with the {@link #removeNode()} method.
0619 * @see #getLong(String,long)
0620 */
0621 public abstract void putLong(String key, long value);
0622
0623 /**
0624 * Returns the long value represented by the string associated with the
0625 * specified key in this preference node. The string is converted to
0626 * a long as by {@link Long#parseLong(String)}. Returns the
0627 * specified default if there is no value associated with the key,
0628 * the backing store is inaccessible, or if
0629 * <tt>Long.parseLong(String)</tt> would throw a {@link
0630 * NumberFormatException} if the associated value were passed. This
0631 * method is intended for use in conjunction with {@link #putLong}.
0632 *
0633 * <p>If the implementation supports <i>stored defaults</i> and such a
0634 * default exists, is accessible, and could be converted to a long
0635 * with <tt>Long.parseLong</tt>, this long is returned in preference to
0636 * the specified default.
0637 *
0638 * @param key key whose associated value is to be returned as a long.
0639 * @param def the value to be returned in the event that this
0640 * preference node has no value associated with <tt>key</tt>
0641 * or the associated value cannot be interpreted as a long,
0642 * or the backing store is inaccessible.
0643 * @return the long value represented by the string associated with
0644 * <tt>key</tt> in this preference node, or <tt>def</tt> if the
0645 * associated value does not exist or cannot be interpreted as
0646 * a long.
0647 * @throws IllegalStateException if this node (or an ancestor) has been
0648 * removed with the {@link #removeNode()} method.
0649 * @throws NullPointerException if <tt>key</tt> is <tt>null</tt>.
0650 * @see #putLong(String,long)
0651 * @see #get(String,String)
0652 */
0653 public abstract long getLong(String key, long def);
0654
0655 /**
0656 * Associates a string representing the specified boolean value with the
0657 * specified key in this preference node. The associated string is
0658 * <tt>"true"</tt> if the value is true, and <tt>"false"</tt> if it is
0659 * false. This method is intended for use in conjunction with
0660 * {@link #getBoolean}.
0661 *
0662 * @param key key with which the string form of value is to be associated.
0663 * @param value value whose string form is to be associated with key.
0664 * @throws NullPointerException if <tt>key</tt> is <tt>null</tt>.
0665 * @throws IllegalArgumentException if <tt>key.length()</tt> exceeds
0666 * <tt>MAX_KEY_LENGTH</tt>.
0667 * @throws IllegalStateException if this node (or an ancestor) has been
0668 * removed with the {@link #removeNode()} method.
0669 * @see #getBoolean(String,boolean)
0670 * @see #get(String,String)
0671 */
0672 public abstract void putBoolean(String key, boolean value);
0673
0674 /**
0675 * Returns the boolean value represented by the string associated with the
0676 * specified key in this preference node. Valid strings
0677 * are <tt>"true"</tt>, which represents true, and <tt>"false"</tt>, which
0678 * represents false. Case is ignored, so, for example, <tt>"TRUE"</tt>
0679 * and <tt>"False"</tt> are also valid. This method is intended for use in
0680 * conjunction with {@link #putBoolean}.
0681 *
0682 * <p>Returns the specified default if there is no value
0683 * associated with the key, the backing store is inaccessible, or if the
0684 * associated value is something other than <tt>"true"</tt> or
0685 * <tt>"false"</tt>, ignoring case.
0686 *
0687 * <p>If the implementation supports <i>stored defaults</i> and such a
0688 * default exists and is accessible, it is used in preference to the
0689 * specified default, unless the stored default is something other than
0690 * <tt>"true"</tt> or <tt>"false"</tt>, ignoring case, in which case the
0691 * specified default is used.
0692 *
0693 * @param key key whose associated value is to be returned as a boolean.
0694 * @param def the value to be returned in the event that this
0695 * preference node has no value associated with <tt>key</tt>
0696 * or the associated value cannot be interpreted as a boolean,
0697 * or the backing store is inaccessible.
0698 * @return the boolean value represented by the string associated with
0699 * <tt>key</tt> in this preference node, or <tt>def</tt> if the
0700 * associated value does not exist or cannot be interpreted as
0701 * a boolean.
0702 * @throws IllegalStateException if this node (or an ancestor) has been
0703 * removed with the {@link #removeNode()} method.
0704 * @throws NullPointerException if <tt>key</tt> is <tt>null</tt>.
0705 * @see #get(String,String)
0706 * @see #putBoolean(String,boolean)
0707 */
0708 public abstract boolean getBoolean(String key, boolean def);
0709
0710 /**
0711 * Associates a string representing the specified float value with the
0712 * specified key in this preference node. The associated string is the
0713 * one that would be returned if the float value were passed to
0714 * {@link Float#toString(float)}. This method is intended for use in
0715 * conjunction with {@link #getFloat}.
0716 *
0717 * @param key key with which the string form of value is to be associated.
0718 * @param value value whose string form is to be associated with key.
0719 * @throws NullPointerException if <tt>key</tt> is <tt>null</tt>.
0720 * @throws IllegalArgumentException if <tt>key.length()</tt> exceeds
0721 * <tt>MAX_KEY_LENGTH</tt>.
0722 * @throws IllegalStateException if this node (or an ancestor) has been
0723 * removed with the {@link #removeNode()} method.
0724 * @see #getFloat(String,float)
0725 */
0726 public abstract void putFloat(String key, float value);
0727
0728 /**
0729 * Returns the float value represented by the string associated with the
0730 * specified key in this preference node. The string is converted to an
0731 * integer as by {@link Float#parseFloat(String)}. Returns the specified
0732 * default if there is no value associated with the key, the backing store
0733 * is inaccessible, or if <tt>Float.parseFloat(String)</tt> would throw a
0734 * {@link NumberFormatException} if the associated value were passed.
0735 * This method is intended for use in conjunction with {@link #putFloat}.
0736 *
0737 * <p>If the implementation supports <i>stored defaults</i> and such a
0738 * default exists, is accessible, and could be converted to a float
0739 * with <tt>Float.parseFloat</tt>, this float is returned in preference to
0740 * the specified default.
0741 *
0742 * @param key key whose associated value is to be returned as a float.
0743 * @param def the value to be returned in the event that this
0744 * preference node has no value associated with <tt>key</tt>
0745 * or the associated value cannot be interpreted as a float,
0746 * or the backing store is inaccessible.
0747 * @return the float value represented by the string associated with
0748 * <tt>key</tt> in this preference node, or <tt>def</tt> if the
0749 * associated value does not exist or cannot be interpreted as
0750 * a float.
0751 * @throws IllegalStateException if this node (or an ancestor) has been
0752 * removed with the {@link #removeNode()} method.
0753 * @throws NullPointerException if <tt>key</tt> is <tt>null</tt>.
0754 * @see #putFloat(String,float)
0755 * @see #get(String,String)
0756 */
0757 public abstract float getFloat(String key, float def);
0758
0759 /**
0760 * Associates a string representing the specified double value with the
0761 * specified key in this preference node. The associated string is the
0762 * one that would be returned if the double value were passed to
0763 * {@link Double#toString(double)}. This method is intended for use in
0764 * conjunction with {@link #getDouble}.
0765 *
0766 * @param key key with which the string form of value is to be associated.
0767 * @param value value whose string form is to be associated with key.
0768 * @throws NullPointerException if <tt>key</tt> is <tt>null</tt>.
0769 * @throws IllegalArgumentException if <tt>key.length()</tt> exceeds
0770 * <tt>MAX_KEY_LENGTH</tt>.
0771 * @throws IllegalStateException if this node (or an ancestor) has been
0772 * removed with the {@link #removeNode()} method.
0773 * @see #getDouble(String,double)
0774 */
0775 public abstract void putDouble(String key, double value);
0776
0777 /**
0778 * Returns the double value represented by the string associated with the
0779 * specified key in this preference node. The string is converted to an
0780 * integer as by {@link Double#parseDouble(String)}. Returns the specified
0781 * default if there is no value associated with the key, the backing store
0782 * is inaccessible, or if <tt>Double.parseDouble(String)</tt> would throw a
0783 * {@link NumberFormatException} if the associated value were passed.
0784 * This method is intended for use in conjunction with {@link #putDouble}.
0785 *
0786 * <p>If the implementation supports <i>stored defaults</i> and such a
0787 * default exists, is accessible, and could be converted to a double
0788 * with <tt>Double.parseDouble</tt>, this double is returned in preference
0789 * to the specified default.
0790 *
0791 * @param key key whose associated value is to be returned as a double.
0792 * @param def the value to be returned in the event that this
0793 * preference node has no value associated with <tt>key</tt>
0794 * or the associated value cannot be interpreted as a double,
0795 * or the backing store is inaccessible.
0796 * @return the double value represented by the string associated with
0797 * <tt>key</tt> in this preference node, or <tt>def</tt> if the
0798 * associated value does not exist or cannot be interpreted as
0799 * a double.
0800 * @throws IllegalStateException if this node (or an ancestor) has been
0801 * removed with the {@link #removeNode()} method.
0802 * @throws NullPointerException if <tt>key</tt> is <tt>null</tt>.
0803 * @see #putDouble(String,double)
0804 * @see #get(String,String)
0805 */
0806 public abstract double getDouble(String key, double def);
0807
0808 /**
0809 * Associates a string representing the specified byte array with the
0810 * specified key in this preference node. The associated string is
0811 * the <i>Base64</i> encoding of the byte array, as defined in <a
0812 * href=http://www.ietf.org/rfc/rfc2045.txt>RFC 2045</a>, Section 6.8,
0813 * with one minor change: the string will consist solely of characters
0814 * from the <i>Base64 Alphabet</i>; it will not contain any newline
0815 * characters. Note that the maximum length of the byte array is limited
0816 * to three quarters of <tt>MAX_VALUE_LENGTH</tt> so that the length
0817 * of the Base64 encoded String does not exceed <tt>MAX_VALUE_LENGTH</tt>.
0818 * This method is intended for use in conjunction with
0819 * {@link #getByteArray}.
0820 *
0821 * @param key key with which the string form of value is to be associated.
0822 * @param value value whose string form is to be associated with key.
0823 * @throws NullPointerException if key or value is <tt>null</tt>.
0824 * @throws IllegalArgumentException if key.length() exceeds MAX_KEY_LENGTH
0825 * or if value.length exceeds MAX_VALUE_LENGTH*3/4.
0826 * @throws IllegalStateException if this node (or an ancestor) has been
0827 * removed with the {@link #removeNode()} method.
0828 * @see #getByteArray(String,byte[])
0829 * @see #get(String,String)
0830 */
0831 public abstract void putByteArray(String key, byte[] value);
0832
0833 /**
0834 * Returns the byte array value represented by the string associated with
0835 * the specified key in this preference node. Valid strings are
0836 * <i>Base64</i> encoded binary data, as defined in <a
0837 * href=http://www.ietf.org/rfc/rfc2045.txt>RFC 2045</a>, Section 6.8,
0838 * with one minor change: the string must consist solely of characters
0839 * from the <i>Base64 Alphabet</i>; no newline characters or
0840 * extraneous characters are permitted. This method is intended for use
0841 * in conjunction with {@link #putByteArray}.
0842 *
0843 * <p>Returns the specified default if there is no value
0844 * associated with the key, the backing store is inaccessible, or if the
0845 * associated value is not a valid Base64 encoded byte array
0846 * (as defined above).
0847 *
0848 * <p>If the implementation supports <i>stored defaults</i> and such a
0849 * default exists and is accessible, it is used in preference to the
0850 * specified default, unless the stored default is not a valid Base64
0851 * encoded byte array (as defined above), in which case the
0852 * specified default is used.
0853 *
0854 * @param key key whose associated value is to be returned as a byte array.
0855 * @param def the value to be returned in the event that this
0856 * preference node has no value associated with <tt>key</tt>
0857 * or the associated value cannot be interpreted as a byte array,
0858 * or the backing store is inaccessible.
0859 * @return the byte array value represented by the string associated with
0860 * <tt>key</tt> in this preference node, or <tt>def</tt> if the
0861 * associated value does not exist or cannot be interpreted as
0862 * a byte array.
0863 * @throws IllegalStateException if this node (or an ancestor) has been
0864 * removed with the {@link #removeNode()} method.
0865 * @throws NullPointerException if <tt>key</tt> is <tt>null</tt>. (A
0866 * <tt>null</tt> value for <tt>def</tt> <i>is</i> permitted.)
0867 * @see #get(String,String)
0868 * @see #putByteArray(String,byte[])
0869 */
0870 public abstract byte[] getByteArray(String key, byte[] def);
0871
0872 /**
0873 * Returns all of the keys that have an associated value in this
0874 * preference node. (The returned array will be of size zero if
0875 * this node has no preferences.)
0876 *
0877 * <p>If the implementation supports <i>stored defaults</i> and there
0878 * are any such defaults at this node that have not been overridden,
0879 * by explicit preferences, the defaults are returned in the array in
0880 * addition to any explicit preferences.
0881 *
0882 * @return an array of the keys that have an associated value in this
0883 * preference node.
0884 * @throws BackingStoreException if this operation cannot be completed
0885 * due to a failure in the backing store, or inability to
0886 * communicate with it.
0887 * @throws IllegalStateException if this node (or an ancestor) has been
0888 * removed with the {@link #removeNode()} method.
0889 */
0890 public abstract String[] keys() throws BackingStoreException;
0891
0892 /**
0893 * Returns the names of the children of this preference node, relative to
0894 * this node. (The returned array will be of size zero if this node has
0895 * no children.)
0896 *
0897 * @return the names of the children of this preference node.
0898 * @throws BackingStoreException if this operation cannot be completed
0899 * due to a failure in the backing store, or inability to
0900 * communicate with it.
0901 * @throws IllegalStateException if this node (or an ancestor) has been
0902 * removed with the {@link #removeNode()} method.
0903 */
0904 public abstract String[] childrenNames()
0905 throws BackingStoreException;
0906
0907 /**
0908 * Returns the parent of this preference node, or <tt>null</tt> if this is
0909 * the root.
0910 *
0911 * @return the parent of this preference node.
0912 * @throws IllegalStateException if this node (or an ancestor) has been
0913 * removed with the {@link #removeNode()} method.
0914 */
0915 public abstract Preferences parent();
0916
0917 /**
0918 * Returns the named preference node in the same tree as this node,
0919 * creating it and any of its ancestors if they do not already exist.
0920 * Accepts a relative or absolute path name. Relative path names
0921 * (which do not begin with the slash character <tt>('/')</tt>) are
0922 * interpreted relative to this preference node.
0923 *
0924 * <p>If the returned node did not exist prior to this call, this node and
0925 * any ancestors that were created by this call are not guaranteed
0926 * to become permanent until the <tt>flush</tt> method is called on
0927 * the returned node (or one of its ancestors or descendants).
0928 *
0929 * @param pathName the path name of the preference node to return.
0930 * @return the specified preference node.
0931 * @throws IllegalArgumentException if the path name is invalid (i.e.,
0932 * it contains multiple consecutive slash characters, or ends
0933 * with a slash character and is more than one character long).
0934 * @throws NullPointerException if path name is <tt>null</tt>.
0935 * @throws IllegalStateException if this node (or an ancestor) has been
0936 * removed with the {@link #removeNode()} method.
0937 * @see #flush()
0938 */
0939 public abstract Preferences node(String pathName);
0940
0941 /**
0942 * Returns true if the named preference node exists in the same tree
0943 * as this node. Relative path names (which do not begin with the slash
0944 * character <tt>('/')</tt>) are interpreted relative to this preference
0945 * node.
0946 *
0947 * <p>If this node (or an ancestor) has already been removed with the
0948 * {@link #removeNode()} method, it <i>is</i> legal to invoke this method,
0949 * but only with the path name <tt>""</tt>; the invocation will return
0950 * <tt>false</tt>. Thus, the idiom <tt>p.nodeExists("")</tt> may be
0951 * used to test whether <tt>p</tt> has been removed.
0952 *
0953 * @param pathName the path name of the node whose existence
0954 * is to be checked.
0955 * @return true if the specified node exists.
0956 * @throws BackingStoreException if this operation cannot be completed
0957 * due to a failure in the backing store, or inability to
0958 * communicate with it.
0959 * @throws IllegalArgumentException if the path name is invalid (i.e.,
0960 * it contains multiple consecutive slash characters, or ends
0961 * with a slash character and is more than one character long).
0962 * @throws NullPointerException if path name is <tt>null</tt>.
0963 * @throws IllegalStateException if this node (or an ancestor) has been
0964 * removed with the {@link #removeNode()} method and
0965 * <tt>pathName</tt> is not the empty string (<tt>""</tt>).
0966 */
0967 public abstract boolean nodeExists(String pathName)
0968 throws BackingStoreException;
0969
0970 /**
0971 * Removes this preference node and all of its descendants, invalidating
0972 * any preferences contained in the removed nodes. Once a node has been
0973 * removed, attempting any method other than {@link #name()},
0974 * {@link #absolutePath()}, {@link #isUserNode()}, {@link #flush()} or
0975 * {@link #node(String) nodeExists("")} on the corresponding
0976 * <tt>Preferences</tt> instance will fail with an
0977 * <tt>IllegalStateException</tt>. (The methods defined on {@link Object}
0978 * can still be invoked on a node after it has been removed; they will not
0979 * throw <tt>IllegalStateException</tt>.)
0980 *
0981 * <p>The removal is not guaranteed to be persistent until the
0982 * <tt>flush</tt> method is called on this node (or an ancestor).
0983 *
0984 * <p>If this implementation supports <i>stored defaults</i>, removing a
0985 * node exposes any stored defaults at or below this node. Thus, a
0986 * subsequent call to <tt>nodeExists</tt> on this node's path name may
0987 * return <tt>true</tt>, and a subsequent call to <tt>node</tt> on this
0988 * path name may return a (different) <tt>Preferences</tt> instance
0989 * representing a non-empty collection of preferences and/or children.
0990 *
0991 * @throws BackingStoreException if this operation cannot be completed
0992 * due to a failure in the backing store, or inability to
0993 * communicate with it.
0994 * @throws IllegalStateException if this node (or an ancestor) has already
0995 * been removed with the {@link #removeNode()} method.
0996 * @throws UnsupportedOperationException if this method is invoked on
0997 * the root node.
0998 * @see #flush()
0999 */
1000 public abstract void removeNode() throws BackingStoreException;
1001
1002 /**
1003 * Returns this preference node's name, relative to its parent.
1004 *
1005 * @return this preference node's name, relative to its parent.
1006 */
1007 public abstract String name();
1008
1009 /**
1010 * Returns this preference node's absolute path name.
1011 *
1012 * @return this preference node's absolute path name.
1013 */
1014 public abstract String absolutePath();
1015
1016 /**
1017 * Returns <tt>true</tt> if this preference node is in the user
1018 * preference tree, <tt>false</tt> if it's in the system preference tree.
1019 *
1020 * @return <tt>true</tt> if this preference node is in the user
1021 * preference tree, <tt>false</tt> if it's in the system
1022 * preference tree.
1023 */
1024 public abstract boolean isUserNode();
1025
1026 /**
1027 * Returns a string representation of this preferences node,
1028 * as if computed by the expression:<tt>(this.isUserNode() ? "User" :
1029 * "System") + " Preference Node: " + this.absolutePath()</tt>.
1030 */
1031 public abstract String toString();
1032
1033 /**
1034 * Forces any changes in the contents of this preference node and its
1035 * descendants to the persistent store. Once this method returns
1036 * successfully, it is safe to assume that all changes made in the
1037 * subtree rooted at this node prior to the method invocation have become
1038 * permanent.
1039 *
1040 * <p>Implementations are free to flush changes into the persistent store
1041 * at any time. They do not need to wait for this method to be called.
1042 *
1043 * <p>When a flush occurs on a newly created node, it is made persistent,
1044 * as are any ancestors (and descendants) that have yet to be made
1045 * persistent. Note however that any preference value changes in
1046 * ancestors are <i>not</i> guaranteed to be made persistent.
1047 *
1048 * <p> If this method is invoked on a node that has been removed with
1049 * the {@link #removeNode()} method, flushSpi() is invoked on this node,
1050 * but not on others.
1051 *
1052 * @throws BackingStoreException if this operation cannot be completed
1053 * due to a failure in the backing store, or inability to
1054 * communicate with it.
1055 * @see #sync()
1056 */
1057 public abstract void flush() throws BackingStoreException;
1058
1059 /**
1060 * Ensures that future reads from this preference node and its
1061 * descendants reflect any changes that were committed to the persistent
1062 * store (from any VM) prior to the <tt>sync</tt> invocation. As a
1063 * side-effect, forces any changes in the contents of this preference node
1064 * and its descendants to the persistent store, as if the <tt>flush</tt>
1065 * method had been invoked on this node.
1066 *
1067 * @throws BackingStoreException if this operation cannot be completed
1068 * due to a failure in the backing store, or inability to
1069 * communicate with it.
1070 * @throws IllegalStateException if this node (or an ancestor) has been
1071 * removed with the {@link #removeNode()} method.
1072 * @see #flush()
1073 */
1074 public abstract void sync() throws BackingStoreException;
1075
1076 /**
1077 * Registers the specified listener to receive <i>preference change
1078 * events</i> for this preference node. A preference change event is
1079 * generated when a preference is added to this node, removed from this
1080 * node, or when the value associated with a preference is changed.
1081 * (Preference change events are <i>not</i> generated by the {@link
1082 * #removeNode()} method, which generates a <i>node change event</i>.
1083 * Preference change events <i>are</i> generated by the <tt>clear</tt>
1084 * method.)
1085 *
1086 * <p>Events are only guaranteed for changes made within the same JVM
1087 * as the registered listener, though some implementations may generate
1088 * events for changes made outside this JVM. Events may be generated
1089 * before the changes have been made persistent. Events are not generated
1090 * when preferences are modified in descendants of this node; a caller
1091 * desiring such events must register with each descendant.
1092 *
1093 * @param pcl The preference change listener to add.
1094 * @throws NullPointerException if <tt>pcl</tt> is null.
1095 * @throws IllegalStateException if this node (or an ancestor) has been
1096 * removed with the {@link #removeNode()} method.
1097 * @see #removePreferenceChangeListener(PreferenceChangeListener)
1098 * @see #addNodeChangeListener(NodeChangeListener)
1099 */
1100 public abstract void addPreferenceChangeListener(
1101 PreferenceChangeListener pcl);
1102
1103 /**
1104 * Removes the specified preference change listener, so it no longer
1105 * receives preference change events.
1106 *
1107 * @param pcl The preference change listener to remove.
1108 * @throws IllegalArgumentException if <tt>pcl</tt> was not a registered
1109 * preference change listener on this node.
1110 * @throws IllegalStateException if this node (or an ancestor) has been
1111 * removed with the {@link #removeNode()} method.
1112 * @see #addPreferenceChangeListener(PreferenceChangeListener)
1113 */
1114 public abstract void removePreferenceChangeListener(
1115 PreferenceChangeListener pcl);
1116
1117 /**
1118 * Registers the specified listener to receive <i>node change events</i>
1119 * for this node. A node change event is generated when a child node is
1120 * added to or removed from this node. (A single {@link #removeNode()}
1121 * invocation results in multiple <i>node change events</i>, one for every
1122 * node in the subtree rooted at the removed node.)
1123 *
1124 * <p>Events are only guaranteed for changes made within the same JVM
1125 * as the registered listener, though some implementations may generate
1126 * events for changes made outside this JVM. Events may be generated
1127 * before the changes have become permanent. Events are not generated
1128 * when indirect descendants of this node are added or removed; a
1129 * caller desiring such events must register with each descendant.
1130 *
1131 * <p>Few guarantees can be made regarding node creation. Because nodes
1132 * are created implicitly upon access, it may not be feasible for an
1133 * implementation to determine whether a child node existed in the backing
1134 * store prior to access (for example, because the backing store is
1135 * unreachable or cached information is out of date). Under these
1136 * circumstances, implementations are neither required to generate node
1137 * change events nor prohibited from doing so.
1138 *
1139 * @param ncl The <tt>NodeChangeListener</tt> to add.
1140 * @throws NullPointerException if <tt>ncl</tt> is null.
1141 * @throws IllegalStateException if this node (or an ancestor) has been
1142 * removed with the {@link #removeNode()} method.
1143 * @see #removeNodeChangeListener(NodeChangeListener)
1144 * @see #addPreferenceChangeListener(PreferenceChangeListener)
1145 */
1146 public abstract void addNodeChangeListener(NodeChangeListener ncl);
1147
1148 /**
1149 * Removes the specified <tt>NodeChangeListener</tt>, so it no longer
1150 * receives change events.
1151 *
1152 * @param ncl The <tt>NodeChangeListener</tt> to remove.
1153 * @throws IllegalArgumentException if <tt>ncl</tt> was not a registered
1154 * <tt>NodeChangeListener</tt> on this node.
1155 * @throws IllegalStateException if this node (or an ancestor) has been
1156 * removed with the {@link #removeNode()} method.
1157 * @see #addNodeChangeListener(NodeChangeListener)
1158 */
1159 public abstract void removeNodeChangeListener(NodeChangeListener ncl);
1160
1161 /**
1162 * Emits on the specified output stream an XML document representing all
1163 * of the preferences contained in this node (but not its descendants).
1164 * This XML document is, in effect, an offline backup of the node.
1165 *
1166 * <p>The XML document will have the following DOCTYPE declaration:
1167 * <pre>
1168 * <!DOCTYPE preferences SYSTEM "http://java.sun.com/dtd/preferences.dtd">
1169 * </pre>
1170 * The UTF-8 character encoding will be used.
1171 *
1172 * <p>This method is an exception to the general rule that the results of
1173 * concurrently executing multiple methods in this class yields
1174 * results equivalent to some serial execution. If the preferences
1175 * at this node are modified concurrently with an invocation of this
1176 * method, the exported preferences comprise a "fuzzy snapshot" of the
1177 * preferences contained in the node; some of the concurrent modifications
1178 * may be reflected in the exported data while others may not.
1179 *
1180 * @param os the output stream on which to emit the XML document.
1181 * @throws IOException if writing to the specified output stream
1182 * results in an <tt>IOException</tt>.
1183 * @throws BackingStoreException if preference data cannot be read from
1184 * backing store.
1185 * @see #importPreferences(InputStream)
1186 * @throws IllegalStateException if this node (or an ancestor) has been
1187 * removed with the {@link #removeNode()} method.
1188 */
1189 public abstract void exportNode(OutputStream os)
1190 throws IOException, BackingStoreException;
1191
1192 /**
1193 * Emits an XML document representing all of the preferences contained
1194 * in this node and all of its descendants. This XML document is, in
1195 * effect, an offline backup of the subtree rooted at the node.
1196 *
1197 * <p>The XML document will have the following DOCTYPE declaration:
1198 * <pre>
1199 * <!DOCTYPE preferences SYSTEM "http://java.sun.com/dtd/preferences.dtd">
1200 * </pre>
1201 * The UTF-8 character encoding will be used.
1202 *
1203 * <p>This method is an exception to the general rule that the results of
1204 * concurrently executing multiple methods in this class yields
1205 * results equivalent to some serial execution. If the preferences
1206 * or nodes in the subtree rooted at this node are modified concurrently
1207 * with an invocation of this method, the exported preferences comprise a
1208 * "fuzzy snapshot" of the subtree; some of the concurrent modifications
1209 * may be reflected in the exported data while others may not.
1210 *
1211 * @param os the output stream on which to emit the XML document.
1212 * @throws IOException if writing to the specified output stream
1213 * results in an <tt>IOException</tt>.
1214 * @throws BackingStoreException if preference data cannot be read from
1215 * backing store.
1216 * @throws IllegalStateException if this node (or an ancestor) has been
1217 * removed with the {@link #removeNode()} method.
1218 * @see #importPreferences(InputStream)
1219 * @see #exportNode(OutputStream)
1220 */
1221 public abstract void exportSubtree(OutputStream os)
1222 throws IOException, BackingStoreException;
1223
1224 /**
1225 * Imports all of the preferences represented by the XML document on the
1226 * specified input stream. The document may represent user preferences or
1227 * system preferences. If it represents user preferences, the preferences
1228 * will be imported into the calling user's preference tree (even if they
1229 * originally came from a different user's preference tree). If any of
1230 * the preferences described by the document inhabit preference nodes that
1231 * do not exist, the nodes will be created.
1232 *
1233 * <p>The XML document must have the following DOCTYPE declaration:
1234 * <pre>
1235 * <!DOCTYPE preferences SYSTEM "http://java.sun.com/dtd/preferences.dtd">
1236 * </pre>
1237 * (This method is designed for use in conjunction with
1238 * {@link #exportNode(OutputStream)} and
1239 * {@link #exportSubtree(OutputStream)}.
1240 *
1241 * <p>This method is an exception to the general rule that the results of
1242 * concurrently executing multiple methods in this class yields
1243 * results equivalent to some serial execution. The method behaves
1244 * as if implemented on top of the other public methods in this class,
1245 * notably {@link #node(String)} and {@link #put(String, String)}.
1246 *
1247 * @param is the input stream from which to read the XML document.
1248 * @throws IOException if reading from the specified input stream
1249 * results in an <tt>IOException</tt>.
1250 * @throws InvalidPreferencesFormatException Data on input stream does not
1251 * constitute a valid XML document with the mandated document type.
1252 * @throws SecurityException If a security manager is present and
1253 * it denies <tt>RuntimePermission("preferences")</tt>.
1254 * @see RuntimePermission
1255 */
1256 public static void importPreferences(InputStream is)
1257 throws IOException, InvalidPreferencesFormatException {
1258 XmlSupport.importPreferences(is);
1259 }
1260 }
|