summaryrefslogtreecommitdiff
path: root/libjava/classpath/gnu/java/util/prefs/GConfBasedPreferences.java
diff options
context:
space:
mode:
Diffstat (limited to 'libjava/classpath/gnu/java/util/prefs/GConfBasedPreferences.java')
-rw-r--r--libjava/classpath/gnu/java/util/prefs/GConfBasedPreferences.java419
1 files changed, 419 insertions, 0 deletions
diff --git a/libjava/classpath/gnu/java/util/prefs/GConfBasedPreferences.java b/libjava/classpath/gnu/java/util/prefs/GConfBasedPreferences.java
new file mode 100644
index 000000000..e3374eee9
--- /dev/null
+++ b/libjava/classpath/gnu/java/util/prefs/GConfBasedPreferences.java
@@ -0,0 +1,419 @@
+/* GConfBasedPreferences.java -- GConf based Preferences implementation
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+ This file is part of GNU Classpath.
+
+ GNU Classpath is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ GNU Classpath is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU Classpath; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301 USA.
+
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library. Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module. An independent module is a module which is not derived from
+ or based on this library. If you modify this library, you may extend
+ this exception to your version of the library, but you are not
+ obligated to do so. If you do not wish to do so, delete this
+ exception statement from your version. */
+
+package gnu.java.util.prefs;
+
+import gnu.java.util.prefs.gconf.GConfNativePeer;
+
+import java.security.Permission;
+
+import java.util.List;
+import java.util.prefs.AbstractPreferences;
+import java.util.prefs.BackingStoreException;
+
+/**
+ * This is a GConf based preference implementation which writes the preferences
+ * as GConf key-value pairs. System Root is defined to be the
+ * <code>"/system"</code> directory of GConf for the current user, while User
+ * Root is <code>"/apps/java"</code>. These defaults can be modified by
+ * defining two system properties:<br />
+ * <br />
+ * User Root:<br />
+ * <br />
+ *
+ * <pre>
+ * gnu.java.util.prefs.gconf.user_root
+ * </pre>
+ *
+ * <br />
+ * <br />
+ * and System Root:<br />
+ * <br />
+ *
+ * <pre>
+ * gnu.java.util.prefs.gconf.system_root
+ * </pre>
+ *
+ * <br />
+ *
+ * @author Mario Torre <neugens@limasoftware.net>
+ */
+public class GConfBasedPreferences
+ extends AbstractPreferences
+{
+ /** Get access to Runtime permission */
+ private static final Permission PERMISSION
+ = new RuntimePermission("preferences");
+
+ /** CGonf client backend */
+ private static GConfNativePeer backend = new GConfNativePeer();
+
+ /** Default user root path */
+ private static final String DEFAULT_USER_ROOT = "/apps/classpath";
+
+ /** Default system root path */
+ private static final String DEFAULT_SYSTEM_ROOT = "/system";
+
+ /** current node full path */
+ private String node = "";
+
+ /** True if this is a preference node in the user tree, false otherwise. */
+ private final boolean isUser;
+
+ /**
+ * Creates a preference root user node.
+ */
+ public GConfBasedPreferences()
+ {
+ this(true);
+ }
+
+ /**
+ * Creates a preference root node. When <code>isUser</code> is true it will
+ * be user node otherwise it will be a system node.
+ */
+ public GConfBasedPreferences(boolean isUser)
+ {
+ this(null, "", isUser);
+ }
+
+ /**
+ * Creates a new preference node given a parent node and a name, which has to
+ * be relative to its parent. When <code>isUser</code> is true it will be user
+ * node otherwise it will be a system node.
+ *
+ * @param parent The parent node of this newly created node.
+ * @param name A name relative to the parent node.
+ * @param isUser Set to <code>true</code> initializes this node to be
+ * a user node, <code>false</code> initialize it to be a system node.
+ */
+ public GConfBasedPreferences(AbstractPreferences parent, String name,
+ boolean isUser)
+ {
+ super(parent, name);
+ this.isUser = isUser;
+
+ // stores the fully qualified name of this node
+ String absolutePath = this.absolutePath();
+ if (absolutePath != null && absolutePath.endsWith("/"))
+ {
+ absolutePath = absolutePath.substring(0, absolutePath.length() - 1);
+ }
+
+ // strip invalid characters
+ // please, note that all names are unescaped into the native peer
+ int index = absolutePath.lastIndexOf('/');
+ if (index > -1)
+ {
+ absolutePath = absolutePath.substring(0, index + 1);
+ absolutePath = absolutePath + GConfNativePeer.escapeString(name);
+ }
+
+ this.node = this.getRealRoot(isUser) + absolutePath;
+
+ boolean nodeExist = backend.nodeExist(this.node);
+
+ this.newNode = !nodeExist;
+ }
+
+ /**
+ * Returns a child node with the given name.
+ * If the child node does not exists, it will be created.
+ *
+ * @param name The name of the requested node.
+ * @return A new reference to the node, creating the node if it is necessary.
+ */
+ protected AbstractPreferences childSpi(String name)
+ {
+ // we don't check anything here, if the node is a new node this will be
+ // detected in the constructor, so we simply return a new reference to
+ // the requested node.
+
+ GConfBasedPreferences preferenceNode
+ = new GConfBasedPreferences(this, name, this.isUser);
+
+ return preferenceNode;
+ }
+
+ /**
+ * Returns an array of names of the children of this preference node.
+ * If the current node does not have children, the returned array will be
+ * of <code>size</code> 0 (that is, not <code>null</code>).
+ *
+ * @return A <code>String</code> array of names of children of the current
+ * node.
+ * @throws BackingStoreException if this operation cannot be completed.
+ */
+ protected String[] childrenNamesSpi() throws BackingStoreException
+ {
+ List<String> nodeList = backend.getChildrenNodes(this.node);
+ String[] nodes = new String[nodeList.size()];
+ nodeList.toArray(nodes);
+
+ return nodes;
+ }
+
+ /**
+ * Suggest a flush to the backend. Actually, this is only a suggestion as
+ * GConf handles this for us asynchronously. More over, both sync and flush
+ * have the same meaning in this class, so calling sync has exactly the same
+ * effect.
+ *
+ * @see #sync
+ * @throws BackingStoreException if this operation cannot be completed.
+ */
+ public void flush() throws BackingStoreException
+ {
+ backend.suggestSync();
+ }
+
+ /**
+ * Request a flush.
+ *
+ * @see #flush
+ * @throws BackingStoreException if this operation cannot be completed.
+ */
+ protected void flushSpi() throws BackingStoreException
+ {
+ this.flush();
+ }
+
+ /**
+ * Returns all of the key in this preference node.
+ * If the current node does not have preferences, the returned array will be
+ * of size zero.
+ *
+ * @return A <code>String</code> array of keys stored under the current
+ * node.
+ * @throws BackingStoreException if this operation cannot be completed.
+ */
+ protected String[] keysSpi() throws BackingStoreException
+ {
+ List<String> keyList = backend.getKeys(this.node);
+ String[] keys = new String[keyList.size()];
+ keyList.toArray(keys);
+
+ return keys;
+ }
+
+ /**
+ * Does a recursive postorder traversal of the preference tree, starting from
+ * the given directory invalidating every preference found in the node.
+ *
+ * @param directory The name of the starting directory (node)
+ */
+ private void postorderRemove(String directory)
+ {
+ try
+ {
+ // gets the listing of directories in this node
+ List<String> dirs = backend.getChildrenNodes(directory);
+
+ if (dirs.size() != 0)
+ {
+ for (String currentDir : dirs)
+ {
+ // recursive search inside this directory
+ postorderRemove(currentDir);
+ }
+ }
+
+ // remove all the keys associated to this directory
+ List<String> entries = backend.getKeys(directory);
+
+ if (entries.size() != 0)
+ {
+ for (String key : entries)
+ {
+ this.removeSpi(key);
+ }
+ }
+ }
+ catch (BackingStoreException ex)
+ {
+ /* ignore */
+ }
+ }
+
+ /**
+ * Stores the given key-value pair into this preference node.
+ *
+ * @param key The key of this preference.
+ * @param value The value of this preference.
+ */
+ protected void putSpi(String key, String value)
+ {
+ backend.setString(this.getGConfKey(key), value);
+ }
+
+ /**
+ * Removes this preference node, including all its children.
+ * Also removes the preferences associated.
+ */
+ protected void removeNodeSpi() throws BackingStoreException
+ {
+ this.postorderRemove(this.node);
+ this.flush();
+ }
+
+ /**
+ * Removes the given key from this preference node.
+ * If the key does not exist, no operation is performed.
+ *
+ * @param key The key to remove.
+ */
+ protected void removeSpi(String key)
+ {
+ backend.unset(this.getGConfKey(key));
+ }
+
+ /**
+ * Suggest a sync to the backend. Actually, this is only a suggestion as GConf
+ * handles this for us asynchronously. More over, both sync and flush have the
+ * same meaning in this class, so calling flush has exactly the same effect.
+ *
+ * @see #flush
+ * @throws BackingStoreException if this operation cannot be completed due to
+ * a failure in the backing store, or inability to communicate with
+ * it.
+ */
+ public void sync() throws BackingStoreException
+ {
+ this.flush();
+ }
+
+ /**
+ * Request a sync.
+ *
+ * @see #sync
+ * @throws BackingStoreException if this operation cannot be completed due to
+ * a failure in the backing store, or inability to communicate with
+ * it.
+ */
+ protected void syncSpi() throws BackingStoreException
+ {
+ this.sync();
+ }
+
+ /**
+ * Returns the value of the given key.
+ * If the keys does not have a value, or there is an error in the backing
+ * store, <code>null</code> is returned instead.
+ *
+ * @param key The key to retrieve.
+ * @return The value associated with the given key.
+ */
+ protected String getSpi(String key)
+ {
+ return backend.getKey(this.getGConfKey(key));
+ }
+
+ /**
+ * Returns <code>true</code> if this preference node is a user node,
+ * <code>false</code> if is a system preference node.
+ *
+ * @return <code>true</code> if this preference node is a user node,
+ * <code>false</code> if is a system preference node.
+ */
+ public boolean isUserNode()
+ {
+ return this.isUser;
+ }
+
+ /*
+ * PRIVATE METHODS
+ */
+
+ /**
+ * Builds a GConf key string suitable for operations on the backend.
+ *
+ * @param key The key to convert into a valid GConf key.
+ * @return A valid Gconf key.
+ */
+ private String getGConfKey(String key)
+ {
+ String nodeName = "";
+
+ // strip key
+ // please, note that all names are unescaped into the native peer
+ key = GConfNativePeer.escapeString(key);
+
+ if (this.node.endsWith("/"))
+ {
+ nodeName = this.node + key;
+ }
+ else
+ {
+ nodeName = this.node + "/" + key;
+ }
+
+ return nodeName;
+ }
+
+ /**
+ * Builds the root node to use for this preference.
+ *
+ * @param isUser Defines if this node is a user (<code>true</code>) or system
+ * (<code>false</code>) node.
+ * @return The real root of this preference tree.
+ */
+ private String getRealRoot(boolean isUser)
+ {
+ // not sure about this, we should have already these permissions...
+ SecurityManager security = System.getSecurityManager();
+
+ if (security != null)
+ {
+ security.checkPermission(PERMISSION);
+ }
+
+ String root = null;
+
+ if (isUser)
+ {
+ root = System.getProperty("gnu.java.util.prefs.gconf.user_root",
+ DEFAULT_USER_ROOT);
+ }
+ else
+ {
+ root = System.getProperty("gnu.java.util.prefs.gconf.system_root",
+ DEFAULT_SYSTEM_ROOT);
+ }
+
+ return root;
+ }
+}