Merge from mainline (gomp-merge-2005-02-26).
[official-gcc.git] / libjava / java / util / prefs / Preferences.java
blob4186c805a0ca55d2ad9038d2bf8c94a2b7489c6a
1 /* Preferences -- Preference node containing key value entries and subnodes
2 Copyright (C) 2001, 2004, 2005 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19 02111-1307 USA.
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
38 package java.util.prefs;
40 import gnu.java.util.prefs.NodeReader;
42 import java.io.IOException;
43 import java.io.InputStream;
44 import java.io.OutputStream;
45 import java.security.AccessController;
46 import java.security.Permission;
47 import java.security.PrivilegedAction;
49 /**
50 * Preference node containing key value entries and subnodes.
51 * <p>
52 * There are two preference node trees, a system tree which can be accessed
53 * by calling <code>systemRoot()</code> containing system preferences usefull
54 * for all users, and a user tree that can be accessed by calling
55 * <code>userRoot()</code> containing preferences that can differ between
56 * different users. How different users are identified is implementation
57 * depended. It can be determined by Thread, Access Control Context or Subject.
58 * <p>
59 * This implementation uses the "java.util.prefs.PreferencesFactory" system
60 * property to find a class that implement <code>PreferencesFactory</code>
61 * and initialized that class (if it has a public no arguments contructor)
62 * to get at the actual system or user root. If the system property is not set,
63 * or the class cannot be initialized it uses the default implementation
64 * <code>gnu.java.util.prefs.FileBasedFactory</code>.
65 * <p>
66 * Besides the two static method above to get the roots of the system and user
67 * preference node trees there are also two convenience methods to access the
68 * default preference node for a particular package an object is in. These are
69 * <code>userNodeForPackage()</code> and <code>systemNodeForPackage()</code>.
70 * Both methods take an Object as an argument so accessing preferences values
71 * can be as easy as calling <code>Preferences.userNodeForPackage(this)</code>.
72 * <p>
73 * Note that if a security manager is installed all static methods check for
74 * <code>RuntimePermission("preferences")</code>. But if this permission is
75 * given to the code then it can access and change all (user) preference nodes
76 * and entries. So you should be carefull not to store to sensitive information
77 * or make security decissions based on preference values since there is no
78 * more fine grained control over what preference values can be changed once
79 * code has been given the correct runtime permission.
80 * <p>
81 * XXX
83 * @since 1.4
84 * @author Mark Wielaard (mark@klomp.org)
86 public abstract class Preferences {
88 // Static Fields
90 /**
91 * Default PreferencesFactory class used when the system property
92 * "java.util.prefs.PreferencesFactory" is not set.
93 * <p>
94 * XXX - Currently set to MemoryBasedFactory, should be changed
95 * when FileBasedPreferences backend works.
97 private static final String defaultFactoryClass
98 = "gnu.java.util.prefs.MemoryBasedFactory";
100 /** Permission needed to access system or user root. */
101 private static final Permission prefsPermission
102 = new RuntimePermission("preferences");
105 * The preferences factory object that supplies the system and user root.
106 * Set and returned by the getFactory() method.
108 private static PreferencesFactory factory;
110 /** Maximum node name length. 80 characters. */
111 public static final int MAX_NAME_LENGTH = 80;
113 /** Maximum entry key length. 80 characters. */
114 public static final int MAX_KEY_LENGTH = 80;
116 /** Maximum entry value length. 8192 characters. */
117 public static final int MAX_VALUE_LENGTH = 8192;
119 // Constructors
122 * Creates a new Preferences node. Can only be used by subclasses.
123 * Empty implementation.
125 protected Preferences() {}
127 // Static methods
130 * Returns the system preferences root node containing usefull preferences
131 * for all users. It is save to cache this value since it should always
132 * return the same preference node.
134 * @return the root system preference node
135 * @exception SecurityException when a security manager is installed and
136 * the caller does not have <code>RuntimePermission("preferences")</code>.
138 public static Preferences systemRoot() throws SecurityException {
139 // Get the preferences factory and check for permission
140 PreferencesFactory factory = getFactory();
142 return factory.systemRoot();
146 * Returns the user preferences root node containing preferences for the
147 * the current user. How different users are identified is implementation
148 * depended. It can be determined by Thread, Access Control Context or
149 * Subject.
151 * @return the root user preference node
152 * @exception SecurityException when a security manager is installed and
153 * the caller does not have <code>RuntimePermission("preferences")</code>.
155 public static Preferences userRoot() throws SecurityException {
156 // Get the preferences factory and check for permission
157 PreferencesFactory factory = getFactory();
158 return factory.userRoot();
162 * Private helper method for <code>systemRoot()</code> and
163 * <code>userRoot()</code>. Checks security permission and instantiates the
164 * correct factory if it has not yet been set.
165 * <p>
166 * When the preferences factory has not yet been set this method first
167 * tries to get the system propery "java.util.prefs.PreferencesFactory"
168 * and tries to initializes that class. If the system property is not set
169 * or initialization fails it returns an instance of the default factory
170 * <code>gnu.java.util.prefs.FileBasedPreferencesFactory</code>.
172 * @return the preferences factory to use
173 * @exception SecurityException when a security manager is installed and
174 * the caller does not have <code>RuntimePermission("preferences")</code>.
176 private static PreferencesFactory getFactory() throws SecurityException {
178 // First check for permission
179 SecurityManager sm = System.getSecurityManager();
180 if (sm != null) {
181 sm.checkPermission(prefsPermission);
184 // Get the factory
185 if (factory == null) {
186 // Caller might not have enough permissions
187 factory = (PreferencesFactory) AccessController.doPrivileged(
188 new PrivilegedAction() {
189 public Object run() {
190 PreferencesFactory pf = null;
191 String className = System.getProperty
192 ("java.util.prefs.PreferencesFactory");
193 if (className != null) {
194 try {
195 Class fc = Class.forName(className);
196 Object o = fc.newInstance();
197 pf = (PreferencesFactory) o;
198 } catch (ClassNotFoundException cnfe)
199 {/*ignore*/}
200 catch (InstantiationException ie)
201 {/*ignore*/}
202 catch (IllegalAccessException iae)
203 {/*ignore*/}
204 catch (ClassCastException cce)
205 {/*ignore*/}
207 return pf;
211 // Still no factory? Use our default.
212 if (factory == null)
216 Class cls = Class.forName (defaultFactoryClass);
217 factory = (PreferencesFactory) cls.newInstance();
219 catch (Exception e)
221 throw new RuntimeException ("Couldn't load default factory"
222 + " '"+ defaultFactoryClass +"'");
223 // XXX - when using 1.4 compatible throwables add cause
229 return factory;
233 * Returns the system preferences node for the package of an object.
234 * The package node name of the object is determined by dropping the
235 * class name of the object of the fully quallified class name and
236 * replacing all '.' to '/' in the package name. If the class of the
237 * object has no package then the package node name is "&lt;unnamed&gt;".
238 * The returened node is <code>systemRoot().node(packageNodeName)</code>.
240 * @param o Object whose default system preference node is requested
241 * @returns system preferences node that should be used by object o
242 * @exception SecurityException when a security manager is installed and
243 * the caller does not have <code>RuntimePermission("preferences")</code>.
245 public static Preferences systemNodeForPackage(Class c)
246 throws SecurityException
248 return nodeForPackage(c, systemRoot());
252 * Returns the user preferences node for the package of an object.
253 * The package node name of the object is determined by dropping the
254 * class name of the object of the fully quallified class name and
255 * replacing all '.' to '/' in the package name. If the class of the
256 * object has no package then the package node name is "&lt;unnamed&gt;".
257 * The returened node is <code>userRoot().node(packageNodeName)</code>.
259 * @param o Object whose default user preference node is requested
260 * @returns user preferences node that should be used by object o
261 * @exception SecurityException when a security manager is installed and
262 * the caller does not have <code>RuntimePermission("preferences")</code>.
264 public static Preferences userNodeForPackage(Class c)
265 throws SecurityException
267 return nodeForPackage(c, userRoot());
271 * Private helper method for <code>systemNodeForPackage()</code> and
272 * <code>userNodeForPackage()</code>. Given the correct system or user
273 * root it returns the correct Preference node for the package node name
274 * of the given object.
276 private static Preferences nodeForPackage(Class c, Preferences root) {
277 // Get the package path
278 String className = c.getName();
279 String packagePath;
280 int index = className.lastIndexOf('.');
281 if(index == -1) {
282 packagePath = "<unnamed>";
283 } else {
284 packagePath = className.substring(0,index).replace('.','/');
287 return root.node(packagePath);
291 * XXX
293 public static void importPreferences(InputStream is)
294 throws InvalidPreferencesFormatException,
295 IOException
297 PreferencesFactory factory = getFactory();
298 NodeReader reader = new NodeReader(is, factory);
299 reader.importPreferences();
302 // abstract methods (identification)
305 * Returns the absolute path name of this preference node.
306 * The absolute path name of a node is the path name of its parent node
307 * plus a '/' plus its own name. If the node is the root node and has no
308 * parent then its name is "" and its absolute path name is "/".
310 public abstract String absolutePath();
313 * Returns true if this node comes from the user preferences tree, false
314 * if it comes from the system preferences tree.
316 public abstract boolean isUserNode();
319 * Returns the name of this preferences node. The name of the node cannot
320 * be null, can be mostly 80 characters and cannot contain any '/'
321 * characters. The root node has as name "".
323 public abstract String name();
326 * Returns the String given by
327 * <code>
328 * (isUserNode() ? "User":"System") + " Preference Node: " + absolutePath()
329 * </code>
331 public abstract String toString();
333 // abstract methods (navigation)
336 * Returns all the direct sub nodes of this preferences node.
337 * Needs access to the backing store to give a meaningfull answer.
339 * @exception BackingStoreException when the backing store cannot be
340 * reached
341 * @exception IllegalStateException when this node has been removed
343 public abstract String[] childrenNames() throws BackingStoreException;
346 * Returns a sub node of this preferences node if the given path is
347 * relative (does not start with a '/') or a sub node of the root
348 * if the path is absolute (does start with a '/').
350 * @exception IllegalStateException if this node has been removed
351 * @exception IllegalArgumentException if the path contains two or more
352 * consecutive '/' characters, ends with a '/' charactor and is not the
353 * string "/" (indicating the root node) or any name on the path is more
354 * then 80 characters long
356 public abstract Preferences node(String path);
359 * Returns true if the node that the path points to exists in memory or
360 * in the backing store. Otherwise it returns false or an exception is
361 * thrown. When this node is removed the only valid parameter is the
362 * empty string (indicating this node), the return value in that case
363 * will be false.
365 * @exception BackingStoreException when the backing store cannot be
366 * reached
367 * @exception IllegalStateException if this node has been removed
368 * and the path is not the empty string (indicating this node)
369 * @exception IllegalArgumentException if the path contains two or more
370 * consecutive '/' characters, ends with a '/' charactor and is not the
371 * string "/" (indicating the root node) or any name on the path is more
372 * then 80 characters long
374 public abstract boolean nodeExists(String path)
375 throws BackingStoreException;
378 * Returns the parent preferences node of this node or null if this is
379 * the root of the preferences tree.
381 * @exception IllegalStateException if this node has been removed
383 public abstract Preferences parent();
385 // abstract methods (export)
388 * XXX
390 public abstract void exportNode(OutputStream os)
391 throws BackingStoreException,
392 IOException;
395 * XXX
397 public abstract void exportSubtree(OutputStream os)
398 throws BackingStoreException,
399 IOException;
401 // abstract methods (preference entry manipulation)
404 * Returns an (possibly empty) array with all the keys of the preference
405 * entries of this node.
407 * @exception BackingStoreException when the backing store cannot be
408 * reached
409 * @exception IllegalStateException if this node has been removed
411 public abstract String[] keys() throws BackingStoreException;
414 * Returns the value associated with the key in this preferences node. If
415 * the default value of the key cannot be found in the preferences node
416 * entries or something goes wrong with the backing store the supplied
417 * default value is returned.
419 * @exception IllegalArgumentException if key is larger then 80 characters
420 * @exception IllegalStateException if this node has been removed
421 * @exception NullPointerException if key is null
423 public abstract String get(String key, String defaultVal);
426 * Convenience method for getting the given entry as a boolean.
427 * When the string representation of the requested entry is either
428 * "true" or "false" (ignoring case) then that value is returned,
429 * otherwise the given default boolean value is returned.
431 * @exception IllegalArgumentException if key is larger then 80 characters
432 * @exception IllegalStateException if this node has been removed
433 * @exception NullPointerException if key is null
435 public abstract boolean getBoolean(String key, boolean defaultVal);
438 * Convenience method for getting the given entry as a byte array.
439 * When the string representation of the requested entry is a valid
440 * Base64 encoded string (without any other characters, such as newlines)
441 * then the decoded Base64 string is returned as byte array,
442 * otherwise the given default byte array value is returned.
444 * @exception IllegalArgumentException if key is larger then 80 characters
445 * @exception IllegalStateException if this node has been removed
446 * @exception NullPointerException if key is null
448 public abstract byte[] getByteArray(String key, byte[] defaultVal);
451 * Convenience method for getting the given entry as a double.
452 * When the string representation of the requested entry can be decoded
453 * with <code>Double.parseDouble()</code> then that double is returned,
454 * otherwise the given default double value is returned.
456 * @exception IllegalArgumentException if key is larger then 80 characters
457 * @exception IllegalStateException if this node has been removed
458 * @exception NullPointerException if key is null
460 public abstract double getDouble(String key, double defaultVal);
463 * Convenience method for getting the given entry as a float.
464 * When the string representation of the requested entry can be decoded
465 * with <code>Float.parseFloat()</code> then that float is returned,
466 * otherwise the given default float value is returned.
468 * @exception IllegalArgumentException if key is larger then 80 characters
469 * @exception IllegalStateException if this node has been removed
470 * @exception NullPointerException if key is null
472 public abstract float getFloat(String key, float defaultVal);
475 * Convenience method for getting the given entry as an integer.
476 * When the string representation of the requested entry can be decoded
477 * with <code>Integer.parseInt()</code> then that integer is returned,
478 * otherwise the given default integer value is returned.
480 * @exception IllegalArgumentException if key is larger then 80 characters
481 * @exception IllegalStateException if this node has been removed
482 * @exception NullPointerException if key is null
484 public abstract int getInt(String key, int defaultVal);
487 * Convenience method for getting the given entry as a long.
488 * When the string representation of the requested entry can be decoded
489 * with <code>Long.parseLong()</code> then that long is returned,
490 * otherwise the given default long value is returned.
492 * @exception IllegalArgumentException if key is larger then 80 characters
493 * @exception IllegalStateException if this node has been removed
494 * @exception NullPointerException if key is null
496 public abstract long getLong(String key, long defaultVal);
499 * Sets the value of the given preferences entry for this node.
500 * Key and value cannot be null, the key cannot exceed 80 characters
501 * and the value cannot exceed 8192 characters.
502 * <p>
503 * The result will be immediatly visible in this VM, but may not be
504 * immediatly written to the backing store.
506 * @exception NullPointerException if either key or value are null
507 * @exception IllegalArgumentException if either key or value are to large
508 * @exception IllegalStateException when this node has been removed
510 public abstract void put(String key, String value);
513 * Convenience method for setting the given entry as a boolean.
514 * The boolean is converted with <code>Boolean.toString(value)</code>
515 * and then stored in the preference entry as that string.
517 * @exception NullPointerException if key is null
518 * @exception IllegalArgumentException if the key length is to large
519 * @exception IllegalStateException when this node has been removed
521 public abstract void putBoolean(String key, boolean value);
524 * Convenience method for setting the given entry as an array of bytes.
525 * The byte array is converted to a Base64 encoded string
526 * and then stored in the preference entry as that string.
527 * <p>
528 * Note that a byte array encoded as a Base64 string will be about 1.3
529 * times larger then the original length of the byte array, which means
530 * that the byte array may not be larger about 6 KB.
532 * @exception NullPointerException if either key or value are null
533 * @exception IllegalArgumentException if either key or value are to large
534 * @exception IllegalStateException when this node has been removed
536 public abstract void putByteArray(String key, byte[] value);
539 * Convenience method for setting the given entry as a double.
540 * The double is converted with <code>Double.toString(double)</code>
541 * and then stored in the preference entry as that string.
543 * @exception NullPointerException if the key is null
544 * @exception IllegalArgumentException if the key length is to large
545 * @exception IllegalStateException when this node has been removed
547 public abstract void putDouble(String key, double value);
550 * Convenience method for setting the given entry as a float.
551 * The float is converted with <code>Float.toString(float)</code>
552 * and then stored in the preference entry as that string.
554 * @exception NullPointerException if the key is null
555 * @exception IllegalArgumentException if the key length is to large
556 * @exception IllegalStateException when this node has been removed
558 public abstract void putFloat(String key, float value);
561 * Convenience method for setting the given entry as an integer.
562 * The integer is converted with <code>Integer.toString(int)</code>
563 * and then stored in the preference entry as that string.
565 * @exception NullPointerException if the key is null
566 * @exception IllegalArgumentException if the key length is to large
567 * @exception IllegalStateException when this node has been removed
569 public abstract void putInt(String key, int value);
572 * Convenience method for setting the given entry as a long.
573 * The long is converted with <code>Long.toString(long)</code>
574 * and then stored in the preference entry as that string.
576 * @exception NullPointerException if the key is null
577 * @exception IllegalArgumentException if the key length is to large
578 * @exception IllegalStateException when this node has been removed
580 public abstract void putLong(String key, long value);
583 * Removes the preferences entry from this preferences node.
584 * <p>
585 * The result will be immediatly visible in this VM, but may not be
586 * immediatly written to the backing store.
588 * @exception NullPointerException if the key is null
589 * @exception IllegalArgumentException if the key length is to large
590 * @exception IllegalStateException when this node has been removed
592 public abstract void remove(String key);
594 // abstract methods (preference node manipulation)
597 * Removes all entries from this preferences node. May need access to the
598 * backing store to get and clear all entries.
599 * <p>
600 * The result will be immediatly visible in this VM, but may not be
601 * immediatly written to the backing store.
603 * @exception BackingStoreException when the backing store cannot be
604 * reached
605 * @exception IllegalStateException if this node has been removed
607 public abstract void clear() throws BackingStoreException;
610 * Writes all preference changes on this and any subnode that have not
611 * yet been written to the backing store. This has no effect on the
612 * preference entries in this VM, but it makes sure that all changes
613 * are visible to other programs (other VMs might need to call the
614 * <code>sync()</code> method to actually see the changes to the backing
615 * store.
617 * @exception BackingStoreException when the backing store cannot be
618 * reached
619 * @exception IllegalStateException if this node has been removed
621 public abstract void flush() throws BackingStoreException;
624 * Writes and reads all preference changes to and from this and any
625 * subnodes. This makes sure that all local changes are written to the
626 * backing store and that all changes to the backing store are visible
627 * in this preference node (and all subnodes).
629 * @exception BackingStoreException when the backing store cannot be
630 * reached
631 * @exception IllegalStateException if this node has been removed
633 public abstract void sync() throws BackingStoreException;
636 * Removes this and all subnodes from the backing store and clears all
637 * entries. After removal this instance will not be useable (except for
638 * a few methods that don't throw a <code>InvalidStateException</code>),
639 * even when a new node with the same path name is created this instance
640 * will not be usable again. The root (system or user) may never be removed.
641 * <p>
642 * Note that according to the specification an implementation may delay
643 * removal of the node from the backing store till the <code>flush()</code>
644 * method is called. But the <code>flush()</code> method may throw a
645 * <code>IllegalStateException</code> when the node has been removed.
646 * So most implementations will actually remove the node and any subnodes
647 * from the backing store immediatly.
649 * @exception BackingStoreException when the backing store cannot be
650 * reached
651 * @exception IllegalStateException if this node has already been removed
652 * @exception UnsupportedOperationException if this is a root node
654 public abstract void removeNode() throws BackingStoreException;
656 // abstract methods (listeners)
658 public abstract void addNodeChangeListener(NodeChangeListener listener);
660 public abstract void addPreferenceChangeListener
661 (PreferenceChangeListener listener);
663 public abstract void removeNodeChangeListener(NodeChangeListener listener);
665 public abstract void removePreferenceChangeListener
666 (PreferenceChangeListener listener);