|
Java example source code file (AbstractPreferences.java)
The AbstractPreferences.java Java example source code/* * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code 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 * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package java.util.prefs; import java.util.*; import java.io.*; import java.security.AccessController; import java.security.PrivilegedAction; // These imports needed only as a workaround for a JavaDoc bug import java.lang.Integer; import java.lang.Long; import java.lang.Float; import java.lang.Double; /** * This class provides a skeletal implementation of the {@link Preferences} * class, greatly easing the task of implementing it. * * <p>This class is for Preferences implementers only. * Normal users of the <tt>Preferences facility should have no need to * consult this documentation. The {@link Preferences} documentation * should suffice.</strong> * * <p>Implementors must override the nine abstract service-provider interface * (SPI) methods: {@link #getSpi(String)}, {@link #putSpi(String,String)}, * {@link #removeSpi(String)}, {@link #childSpi(String)}, {@link * #removeNodeSpi()}, {@link #keysSpi()}, {@link #childrenNamesSpi()}, {@link * #syncSpi()} and {@link #flushSpi()}. All of the concrete methods specify * precisely how they are implemented atop these SPI methods. The implementor * may, at his discretion, override one or more of the concrete methods if the * default implementation is unsatisfactory for any reason, such as * performance. * * <p>The SPI methods fall into three groups concerning exception * behavior. The <tt>getSpi method should never throw exceptions, but it * doesn't really matter, as any exception thrown by this method will be * intercepted by {@link #get(String,String)}, which will return the specified * default value to the caller. The <tt>removeNodeSpi, keysSpi, * childrenNamesSpi, syncSpi</tt> and flushSpi methods are specified * to throw {@link BackingStoreException}, and the implementation is required * to throw this checked exception if it is unable to perform the operation. * The exception propagates outward, causing the corresponding API method * to fail. * * <p>The remaining SPI methods {@link #putSpi(String,String)}, {@link * #removeSpi(String)} and {@link #childSpi(String)} have more complicated * exception behavior. They are not specified to throw * <tt>BackingStoreException, as they can generally obey their contracts * even if the backing store is unavailable. This is true because they return * no information and their effects are not required to become permanent until * a subsequent call to {@link Preferences#flush()} or * {@link Preferences#sync()}. Generally speaking, these SPI methods should not * throw exceptions. In some implementations, there may be circumstances * under which these calls cannot even enqueue the requested operation for * later processing. Even under these circumstances it is generally better to * simply ignore the invocation and return, rather than throwing an * exception. Under these circumstances, however, all subsequent invocations * of <tt>flush() and sync should return false, as * returning <tt>true would imply that all previous operations had * successfully been made permanent. * * <p>There is one circumstance under which putSpi, removeSpi and * childSpi</tt> should throw an exception: if the caller lacks * sufficient privileges on the underlying operating system to perform the * requested operation. This will, for instance, occur on most systems * if a non-privileged user attempts to modify system preferences. * (The required privileges will vary from implementation to * implementation. On some implementations, they are the right to modify the * contents of some directory in the file system; on others they are the right * to modify contents of some key in a registry.) Under any of these * circumstances, it would generally be undesirable to let the program * continue executing as if these operations would become permanent at a later * time. While implementations are not required to throw an exception under * these circumstances, they are encouraged to do so. A {@link * SecurityException} would be appropriate. * * <p>Most of the SPI methods require the implementation to read or write * information at a preferences node. The implementor should beware of the * fact that another VM may have concurrently deleted this node from the * backing store. It is the implementation's responsibility to recreate the * node if it has been deleted. * * <p>Implementation note: In Sun's default Preferences * implementations, the user's identity is inherited from the underlying * operating system and does not change for the lifetime of the virtual * machine. It is recognized that server-side <tt>Preferences * implementations may have the user identity change from request to request, * implicitly passed to <tt>Preferences methods via the use of a * static {@link ThreadLocal} instance. Authors of such implementations are * <i>strongly encouraged to determine the user at the time preferences * are accessed (for example by the {@link #get(String,String)} or {@link * #put(String,String)} method) rather than permanently associating a user * with each <tt>Preferences instance. The latter behavior conflicts * with normal <tt>Preferences usage and would lead to great confusion. * * @author Josh Bloch * @see Preferences * @since 1.4 */ public abstract class AbstractPreferences extends Preferences { /** * Our name relative to parent. */ private final String name; /** * Our absolute path name. */ private final String absolutePath; /** * Our parent node. */ final AbstractPreferences parent; /** * Our root node. */ private final AbstractPreferences root; // Relative to this node /** * This field should be <tt>true if this node did not exist in the * backing store prior to the creation of this object. The field * is initialized to false, but may be set to true by a subclass * constructor (and should not be modified thereafter). This field * indicates whether a node change event should be fired when * creation is complete. */ protected boolean newNode = false; /** * All known unremoved children of this node. (This "cache" is consulted * prior to calling childSpi() or getChild(). */ private Map<String, AbstractPreferences> kidCache = new HashMap<>(); /** * This field is used to keep track of whether or not this node has * been removed. Once it's set to true, it will never be reset to false. */ private boolean removed = false; /** * Registered preference change listeners. */ private PreferenceChangeListener[] prefListeners = new PreferenceChangeListener[0]; /** * Registered node change listeners. */ private NodeChangeListener[] nodeListeners = new NodeChangeListener[0]; /** * An object whose monitor is used to lock this node. This object * is used in preference to the node itself to reduce the likelihood of * intentional or unintentional denial of service due to a locked node. * To avoid deadlock, a node is <i>never locked by a thread that * holds a lock on a descendant of that node. */ protected final Object lock = new Object(); /** * Creates a preference node with the specified parent and the specified * name relative to its parent. * * @param parent the parent of this preference node, or null if this * is the root. * @param name the name of this preference node, relative to its parent, * or <tt>"" if this is the root. * @throws IllegalArgumentException if <tt>name contains a slash * (<tt>'/'), or parent is null and * name isn't <tt>"". */ protected AbstractPreferences(AbstractPreferences parent, String name) { if (parent==null) { if (!name.equals("")) throw new IllegalArgumentException("Root name '"+name+ "' must be \"\""); this.absolutePath = "/"; root = this; } else { if (name.indexOf('/') != -1) throw new IllegalArgumentException("Name '" + name + "' contains '/'"); if (name.equals("")) throw new IllegalArgumentException("Illegal name: empty string"); root = parent.root; absolutePath = (parent==root ? "/" + name : parent.absolutePath() + "/" + name); } this.name = name; this.parent = parent; } /** * Implements the <tt>put method as per the specification in * {@link Preferences#put(String,String)}. * * <p>This implementation checks that the key and value are legal, * obtains this preference node's lock, checks that the node * has not been removed, invokes {@link #putSpi(String,String)}, and if * there are any preference change listeners, enqueues a notification * event for processing by the event dispatch thread. * * @param key key with which the specified value is to be associated. * @param value value to be associated with the specified key. * @throws NullPointerException if key or value is <tt>null. * @throws IllegalArgumentException if <tt>key.length() exceeds * <tt>MAX_KEY_LENGTH or if value.length exceeds * <tt>MAX_VALUE_LENGTH. * @throws IllegalStateException if this node (or an ancestor) has been * removed with the {@link #removeNode()} method. */ public void put(String key, String value) { if (key==null || value==null) throw new NullPointerException(); if (key.length() > MAX_KEY_LENGTH) throw new IllegalArgumentException("Key too long: "+key); if (value.length() > MAX_VALUE_LENGTH) throw new IllegalArgumentException("Value too long: "+value); synchronized(lock) { if (removed) throw new IllegalStateException("Node has been removed."); putSpi(key, value); enqueuePreferenceChangeEvent(key, value); } } /** * Implements the <tt>get method as per the specification in * {@link Preferences#get(String,String)}. * * <p>This implementation first checks to see if key is * <tt>null throwing a NullPointerException if this is * the case. Then it obtains this preference node's lock, * checks that the node has not been removed, invokes {@link * #getSpi(String)}, and returns the result, unless the <tt>getSpi * invocation returns <tt>null or throws an exception, in which case * this invocation returns <tt>def. * * @param key key whose associated value is to be returned. * @param def the value to be returned in the event that this * preference node has no value associated with <tt>key. * @return the value associated with <tt>key, or def * if no value is associated with <tt>key. * @throws IllegalStateException if this node (or an ancestor) has been * removed with the {@link #removeNode()} method. * @throws NullPointerException if key is <tt>null. (A * <tt>null default is permitted.) */ public String get(String key, String def) { if (key==null) throw new NullPointerException("Null key"); synchronized(lock) { if (removed) throw new IllegalStateException("Node has been removed."); String result = null; try { result = getSpi(key); } catch (Exception e) { // Ignoring exception causes default to be returned } return (result==null ? def : result); } } /** * Implements the <tt>remove(String) method as per the specification * in {@link Preferences#remove(String)}. * * <p>This implementation obtains this preference node's lock, * checks that the node has not been removed, invokes * {@link #removeSpi(String)} and if there are any preference * change listeners, enqueues a notification event for processing by the * event dispatch thread. * * @param key key whose mapping is to be removed from the preference node. * @throws IllegalStateException if this node (or an ancestor) has been * removed with the {@link #removeNode()} method. * @throws NullPointerException {@inheritDoc}. */ public void remove(String key) { Objects.requireNonNull(key, "Specified key cannot be null"); synchronized(lock) { if (removed) throw new IllegalStateException("Node has been removed."); removeSpi(key); enqueuePreferenceChangeEvent(key, null); } } /** * Implements the <tt>clear method as per the specification in * {@link Preferences#clear()}. * * <p>This implementation obtains this preference node's lock, * invokes {@link #keys()} to obtain an array of keys, and * iterates over the array invoking {@link #remove(String)} on each key. * * @throws BackingStoreException if this operation cannot be completed * due to a failure in the backing store, or inability to * communicate with it. * @throws IllegalStateException if this node (or an ancestor) has been * removed with the {@link #removeNode()} method. */ public void clear() throws BackingStoreException { synchronized(lock) { String[] keys = keys(); for (int i=0; i<keys.length; i++) remove(keys[i]); } } /** * Implements the <tt>putInt method as per the specification in * {@link Preferences#putInt(String,int)}. * * <p>This implementation translates value to a string with * {@link Integer#toString(int)} and invokes {@link #put(String,String)} * on the result. * * @param key key with which the string form of value is to be associated. * @param value value whose string form is to be associated with key. * @throws NullPointerException if key is <tt>null. * @throws IllegalArgumentException if <tt>key.length() exceeds * <tt>MAX_KEY_LENGTH. * @throws IllegalStateException if this node (or an ancestor) has been * removed with the {@link #removeNode()} method. */ public void putInt(String key, int value) { put(key, Integer.toString(value)); } /** * Implements the <tt>getInt method as per the specification in * {@link Preferences#getInt(String,int)}. * * <p>This implementation invokes {@link #get(String,String) get(key, * null)</tt>}. If the return value is non-null, the implementation * attempts to translate it to an <tt>int with * {@link Integer#parseInt(String)}. If the attempt succeeds, the return * value is returned by this method. Otherwise, <tt>def is returned. * * @param key key whose associated value is to be returned as an int. * @param def the value to be returned in the event that this * preference node has no value associated with <tt>key * or the associated value cannot be interpreted as an int. * @return the int value represented by the string associated with * <tt>key in this preference node, or def if the * associated value does not exist or cannot be interpreted as * an int. * @throws IllegalStateException if this node (or an ancestor) has been * removed with the {@link #removeNode()} method. * @throws NullPointerException if <tt>key is null. */ public int getInt(String key, int def) { int result = def; try { String value = get(key, null); if (value != null) result = Integer.parseInt(value); } catch (NumberFormatException e) { // Ignoring exception causes specified default to be returned } return result; } /** * Implements the <tt>putLong method as per the specification in * {@link Preferences#putLong(String,long)}. * * <p>This implementation translates value to a string with * {@link Long#toString(long)} and invokes {@link #put(String,String)} * on the result. * * @param key key with which the string form of value is to be associated. * @param value value whose string form is to be associated with key. * @throws NullPointerException if key is <tt>null. * @throws IllegalArgumentException if <tt>key.length() exceeds * <tt>MAX_KEY_LENGTH. * @throws IllegalStateException if this node (or an ancestor) has been * removed with the {@link #removeNode()} method. */ public void putLong(String key, long value) { put(key, Long.toString(value)); } /** * Implements the <tt>getLong method as per the specification in * {@link Preferences#getLong(String,long)}. * * <p>This implementation invokes {@link #get(String,String) get(key, * null)</tt>}. If the return value is non-null, the implementation * attempts to translate it to a <tt>long with * {@link Long#parseLong(String)}. If the attempt succeeds, the return * value is returned by this method. Otherwise, <tt>def is returned. * * @param key key whose associated value is to be returned as a long. * @param def the value to be returned in the event that this * preference node has no value associated with <tt>key * or the associated value cannot be interpreted as a long. * @return the long value represented by the string associated with * <tt>key in this preference node, or def if the * associated value does not exist or cannot be interpreted as * a long. * @throws IllegalStateException if this node (or an ancestor) has been * removed with the {@link #removeNode()} method. * @throws NullPointerException if <tt>key is null. */ public long getLong(String key, long def) { long result = def; try { String value = get(key, null); if (value != null) result = Long.parseLong(value); } catch (NumberFormatException e) { // Ignoring exception causes specified default to be returned } return result; } /** * Implements the <tt>putBoolean method as per the specification in * {@link Preferences#putBoolean(String,boolean)}. * * <p>This implementation translates value to a string with * {@link String#valueOf(boolean)} and invokes {@link #put(String,String)} * on the result. * * @param key key with which the string form of value is to be associated. * @param value value whose string form is to be associated with key. * @throws NullPointerException if key is <tt>null. * @throws IllegalArgumentException if <tt>key.length() exceeds * <tt>MAX_KEY_LENGTH. * @throws IllegalStateException if this node (or an ancestor) has been * removed with the {@link #removeNode()} method. */ public void putBoolean(String key, boolean value) { put(key, String.valueOf(value)); } /** * Implements the <tt>getBoolean method as per the specification in * {@link Preferences#getBoolean(String,boolean)}. * * <p>This implementation invokes {@link #get(String,String) get(key, * null)</tt>}. If the return value is non-null, it is compared with * <tt>"true" using {@link String#equalsIgnoreCase(String)}. If the * comparison returns <tt>true, this invocation returns * <tt>true. Otherwise, the original return value is compared with * <tt>"false", again using {@link String#equalsIgnoreCase(String)}. * If the comparison returns <tt>true, this invocation returns * <tt>false. Otherwise, this invocation returns def. * * @param key key whose associated value is to be returned as a boolean. * @param def the value to be returned in the event that this * preference node has no value associated with <tt>key * or the associated value cannot be interpreted as a boolean. * @return the boolean value represented by the string associated with * <tt>key in this preference node, or def if the * associated value does not exist or cannot be interpreted as * a boolean. * @throws IllegalStateException if this node (or an ancestor) has been * removed with the {@link #removeNode()} method. * @throws NullPointerException if <tt>key is null. */ public boolean getBoolean(String key, boolean def) { boolean result = def; String value = get(key, null); if (value != null) { if (value.equalsIgnoreCase("true")) result = true; else if (value.equalsIgnoreCase("false")) result = false; } return result; } /** * Implements the <tt>putFloat method as per the specification in * {@link Preferences#putFloat(String,float)}. * * <p>This implementation translates value to a string with * {@link Float#toString(float)} and invokes {@link #put(String,String)} * on the result. * * @param key key with which the string form of value is to be associated. * @param value value whose string form is to be associated with key. * @throws NullPointerException if key is <tt>null. * @throws IllegalArgumentException if <tt>key.length() exceeds * <tt>MAX_KEY_LENGTH. * @throws IllegalStateException if this node (or an ancestor) has been * removed with the {@link #removeNode()} method. */ public void putFloat(String key, float value) { put(key, Float.toString(value)); } /** * Implements the <tt>getFloat method as per the specification in * {@link Preferences#getFloat(String,float)}. * * <p>This implementation invokes {@link #get(String,String) get(key, * null)</tt>}. If the return value is non-null, the implementation * attempts to translate it to an <tt>float with * {@link Float#parseFloat(String)}. If the attempt succeeds, the return * value is returned by this method. Otherwise, <tt>def is returned. * * @param key key whose associated value is to be returned as a float. * @param def the value to be returned in the event that this * preference node has no value associated with <tt>key * or the associated value cannot be interpreted as a float. * @return the float value represented by the string associated with * <tt>key in this preference node, or def if the * associated value does not exist or cannot be interpreted as * a float. * @throws IllegalStateException if this node (or an ancestor) has been * removed with the {@link #removeNode()} method. * @throws NullPointerException if <tt>key is null. */ public float getFloat(String key, float def) { float result = def; try { String value = get(key, null); if (value != null) result = Float.parseFloat(value); } catch (NumberFormatException e) { // Ignoring exception causes specified default to be returned } return result; } /** * Implements the <tt>putDouble method as per the specification in * {@link Preferences#putDouble(String,double)}. * * <p>This implementation translates value to a string with * {@link Double#toString(double)} and invokes {@link #put(String,String)} * on the result. * * @param key key with which the string form of value is to be associated. * @param value value whose string form is to be associated with key. * @throws NullPointerException if key is <tt>null. * @throws IllegalArgumentException if <tt>key.length() exceeds * <tt>MAX_KEY_LENGTH. * @throws IllegalStateException if this node (or an ancestor) has been * removed with the {@link #removeNode()} method. */ public void putDouble(String key, double value) { put(key, Double.toString(value)); } /** * Implements the <tt>getDouble method as per the specification in * {@link Preferences#getDouble(String,double)}. * * <p>This implementation invokes {@link #get(String,String) get(key, * null)</tt>}. If the return value is non-null, the implementation * attempts to translate it to an <tt>double with * {@link Double#parseDouble(String)}. If the attempt succeeds, the return * value is returned by this method. Otherwise, <tt>def is returned. * * @param key key whose associated value is to be returned as a double. * @param def the value to be returned in the event that this * preference node has no value associated with <tt>key * or the associated value cannot be interpreted as a double. * @return the double value represented by the string associated with * <tt>key in this preference node, or def if the * associated value does not exist or cannot be interpreted as * a double. * @throws IllegalStateException if this node (or an ancestor) has been * removed with the {@link #removeNode()} method. * @throws NullPointerException if <tt>key is null. */ public double getDouble(String key, double def) { double result = def; try { String value = get(key, null); if (value != null) result = Double.parseDouble(value); } catch (NumberFormatException e) { // Ignoring exception causes specified default to be returned } return result; } /** * Implements the <tt>putByteArray method as per the specification in * {@link Preferences#putByteArray(String,byte[])}. * * @param key key with which the string form of value is to be associated. * @param value value whose string form is to be associated with key. * @throws NullPointerException if key or value is <tt>null. * @throws IllegalArgumentException if key.length() exceeds MAX_KEY_LENGTH * or if value.length exceeds MAX_VALUE_LENGTH*3/4. * @throws IllegalStateException if this node (or an ancestor) has been * removed with the {@link #removeNode()} method. */ public void putByteArray(String key, byte[] value) { put(key, Base64.byteArrayToBase64(value)); } /** * Implements the <tt>getByteArray method as per the specification in * {@link Preferences#getByteArray(String,byte[])}. * * @param key key whose associated value is to be returned as a byte array. * @param def the value to be returned in the event that this * preference node has no value associated with <tt>key * or the associated value cannot be interpreted as a byte array. * @return the byte array value represented by the string associated with * <tt>key in this preference node, or def if the * associated value does not exist or cannot be interpreted as * a byte array. * @throws IllegalStateException if this node (or an ancestor) has been * removed with the {@link #removeNode()} method. * @throws NullPointerException if <tt>key is null. (A * <tt>null value for def is permitted.) */ public byte[] getByteArray(String key, byte[] def) { byte[] result = def; String value = get(key, null); try { if (value != null) result = Base64.base64ToByteArray(value); } catch (RuntimeException e) { // Ignoring exception causes specified default to be returned } return result; } /** * Implements the <tt>keys method as per the specification in * {@link Preferences#keys()}. * * <p>This implementation obtains this preference node's lock, checks that * the node has not been removed and invokes {@link #keysSpi()}. * * @return an array of the keys that have an associated value in this * preference node. * @throws BackingStoreException if this operation cannot be completed * due to a failure in the backing store, or inability to * communicate with it. * @throws IllegalStateException if this node (or an ancestor) has been * removed with the {@link #removeNode()} method. */ public String[] keys() throws BackingStoreException { synchronized(lock) { if (removed) throw new IllegalStateException("Node has been removed."); return keysSpi(); } } /** * Implements the <tt>children method as per the specification in * {@link Preferences#childrenNames()}. * * <p>This implementation obtains this preference node's lock, checks that * the node has not been removed, constructs a <tt>TreeSet initialized * to the names of children already cached (the children in this node's * "child-cache"), invokes {@link #childrenNamesSpi()}, and adds all of the * returned child-names into the set. The elements of the tree set are * dumped into a <tt>String array using the toArray method, * and this array is returned. * * @return the names of the children of this preference node. * @throws BackingStoreException if this operation cannot be completed * due to a failure in the backing store, or inability to * communicate with it. * @throws IllegalStateException if this node (or an ancestor) has been * removed with the {@link #removeNode()} method. * @see #cachedChildren() */ public String[] childrenNames() throws BackingStoreException { synchronized(lock) { if (removed) throw new IllegalStateException("Node has been removed."); Set<String> s = new TreeSet<>(kidCache.keySet()); for (String kid : childrenNamesSpi()) s.add(kid); return s.toArray(EMPTY_STRING_ARRAY); } } private static final String[] EMPTY_STRING_ARRAY = new String[0]; /** * Returns all known unremoved children of this node. * * @return all known unremoved children of this node. */ protected final AbstractPreferences[] cachedChildren() { return kidCache.values().toArray(EMPTY_ABSTRACT_PREFS_ARRAY); } private static final AbstractPreferences[] EMPTY_ABSTRACT_PREFS_ARRAY = new AbstractPreferences[0]; /** * Implements the <tt>parent method as per the specification in * {@link Preferences#parent()}. * * <p>This implementation obtains this preference node's lock, checks that * the node has not been removed and returns the parent value that was * passed to this node's constructor. * * @return the parent of this preference node. * @throws IllegalStateException if this node (or an ancestor) has been * removed with the {@link #removeNode()} method. */ public Preferences parent() { synchronized(lock) { if (removed) throw new IllegalStateException("Node has been removed."); return parent; } } /** * Implements the <tt>node method as per the specification in * {@link Preferences#node(String)}. * * <p>This implementation obtains this preference node's lock and checks * that the node has not been removed. If <tt>path is "", * this node is returned; if <tt>path is "/", this node's * root is returned. If the first character in <tt>path is * not <tt>'/', the implementation breaks path into * tokens and recursively traverses the path from this node to the * named node, "consuming" a name and a slash from <tt>path at * each step of the traversal. At each step, the current node is locked * and the node's child-cache is checked for the named node. If it is * not found, the name is checked to make sure its length does not * exceed <tt>MAX_NAME_LENGTH. Then the {@link #childSpi(String)} * method is invoked, and the result stored in this node's child-cache. * If the newly created <tt>Preferences object's {@link #newNode} * field is <tt>true and there are any node change listeners, * a notification event is enqueued for processing by the event dispatch * thread. * * <p>When there are no more tokens, the last value found in the * child-cache or returned by <tt>childSpi is returned by this * method. If during the traversal, two <tt>"/" tokens occur * consecutively, or the final token is <tt>"/" (rather than a name), * an appropriate <tt>IllegalArgumentException is thrown. * * <p> If the first character of path is '/' * (indicating an absolute path name) this preference node's * lock is dropped prior to breaking <tt>path into tokens, and * this method recursively traverses the path starting from the root * (rather than starting from this node). The traversal is otherwise * identical to the one described for relative path names. Dropping * the lock on this node prior to commencing the traversal at the root * node is essential to avoid the possibility of deadlock, as per the * {@link #lock locking invariant}. * * @param path the path name of the preference node to return. * @return the specified preference node. * @throws IllegalArgumentException if the path name is invalid (i.e., * it contains multiple consecutive slash characters, or ends * with a slash character and is more than one character long). * @throws IllegalStateException if this node (or an ancestor) has been * removed with the {@link #removeNode()} method. */ public Preferences node(String path) { synchronized(lock) { if (removed) throw new IllegalStateException("Node has been removed."); if (path.equals("")) return this; if (path.equals("/")) return root; if (path.charAt(0) != '/') return node(new StringTokenizer(path, "/", true)); } // Absolute path. Note that we've dropped our lock to avoid deadlock return root.node(new StringTokenizer(path.substring(1), "/", true)); } /** * tokenizer contains <name> {'/' Other Java examples (source code examples)Here is a short list of links related to this Java AbstractPreferences.java source code file: |
... this post is sponsored by my books ... | |
#1 New Release! |
FP Best Seller |
Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.
A percentage of advertising revenue from
pages under the /java/jwarehouse
URI on this website is
paid back to open source projects.