abstractpreferences.java

来自「纯java操作系统jnode,安装简单和操作简单的个人使用的Java操作系统」· Java 代码 · 共 1,237 行 · 第 1/3 页

JAVA
1,237
字号
			for (int j = 0; j < 4; j++) {
				if (c[j] < 26) {
					c[j] += 'A';
				} else if (c[j] < 52) {
					c[j] = (char) (c[j] - 26 + 'a');
				} else if (c[j] < 62) {
					c[j] = (char) (c[j] - 52 + '0');
				} else if (c[j] == 62) {
					c[j] = '+';
				} else if (c[j] == 63) {
					c[j] = '/';
				} else {
					c[j] = '=';
				}
			}

			sb.append(c);
			i += 3;
			remaining -= 3;
		}

		return sb.toString();
	}

	/**
	 * Convenience method for setting the given entry as a double.
	 * The double is converted with <code>Double.toString(double)</code>
	 * and then stored in the preference entry as that string.
	 *
	 * @exception NullPointerException if the key is null
	 * @exception IllegalArgumentException if the key length is to large
	 * @exception IllegalStateException when this node has been removed
	 */
	public void putDouble(String key, double value) {
		put(key, Double.toString(value));
	}

	/**
	 * Convenience method for setting the given entry as a float.
	 * The float is converted with <code>Float.toString(float)</code>
	 * and then stored in the preference entry as that string.
	 *
	 * @exception NullPointerException if the key is null
	 * @exception IllegalArgumentException if the key length is to large
	 * @exception IllegalStateException when this node has been removed
	 */
	public void putFloat(String key, float value) {
		put(key, Float.toString(value));
	}

	/**
	 * Convenience method for setting the given entry as an integer.
	 * The integer is converted with <code>Integer.toString(int)</code>
	 * and then stored in the preference entry as that string.
	 *
	 * @exception NullPointerException if the key is null
	 * @exception IllegalArgumentException if the key length is to large
	 * @exception IllegalStateException when this node has been removed
	 */
	public void putInt(String key, int value) {
		put(key, Integer.toString(value));
	}

	/**
	 * Convenience method for setting the given entry as a long.
	 * The long is converted with <code>Long.toString(long)</code>
	 * and then stored in the preference entry as that string.
	 *
	 * @exception NullPointerException if the key is null
	 * @exception IllegalArgumentException if the key length is to large
	 * @exception IllegalStateException when this node has been removed
	 */
	public void putLong(String key, long value) {
		put(key, Long.toString(value));
	}

	/**
	 * Removes the preferences entry from this preferences node.
	 * <p>     
	 * The result will be immediatly visible in this VM, but may not be
	 * immediatly written to the backing store.
	 * <p>
	 * This implementation checks that the key is not larger then 80
	 * characters, gets the lock of this node, checks that the node has
	 * not been removed and calls <code>removeSpi</code> with the given key.
	 *
	 * @exception NullPointerException if the key is null
	 * @exception IllegalArgumentException if the key length is to large
	 * @exception IllegalStateException when this node has been removed
	 */
	public void remove(String key) {
		if (key.length() > MAX_KEY_LENGTH)
			throw new IllegalArgumentException(key);

		synchronized (lock) {
			if (isRemoved())
				throw new IllegalStateException("Node removed");

			removeSpi(key);
		}
	}

	/**
	 * Removes all entries from this preferences node. May need access to the
	 * backing store to get and clear all entries.
	 * <p>
	 * The result will be immediatly visible in this VM, but may not be
	 * immediatly written to the backing store.
	 * <p>
	 * This implementation locks this node, checks that the node has not been
	 * removed and calls <code>keys()</code> to get a complete array of keys
	 * for this node. For every key found <code>removeSpi()</code> is called.
	 *
	 * @exception BackingStoreException when the backing store cannot be
	 *            reached
	 * @exception IllegalStateException if this node has been removed
	 */
	public void clear() throws BackingStoreException {
		synchronized (lock) {
			if (isRemoved())
				throw new IllegalStateException("Node Removed");

			String[] keys = keys();
			for (int i = 0; i < keys.length; i++) {
				removeSpi(keys[i]);
			}
		}
	}

	/**
	 * Writes all preference changes on this and any subnode that have not
	 * yet been written to the backing store. This has no effect on the
	 * preference entries in this VM, but it makes sure that all changes
	 * are visible to other programs (other VMs might need to call the
	 * <code>sync()</code> method to actually see the changes to the backing
	 * store.
	 * <p>
	 * Locks this node, calls the <code>flushSpi()</code> method, gets all
	 * the (cached - already existing in this VM) subnodes and then calls
	 * <code>flushSpi()</code> on every subnode with this node unlocked and
	 * only that particular subnode locked.
	 *
	 * @exception BackingStoreException when the backing store cannot be
	 *            reached
	 */
	public void flush() throws BackingStoreException {
		flushNode(false);
	}

	/**
	 * Writes and reads all preference changes to and from this and any
	 * subnodes. This makes sure that all local changes are written to the
	 * backing store and that all changes to the backing store are visible
	 * in this preference node (and all subnodes).
	 * <p>
	 * Checks that this node is not removed, locks this node, calls the
	 * <code>syncSpi()</code> method, gets all the subnodes and then calls
	 * <code>syncSpi()</code> on every subnode with this node unlocked and
	 * only that particular subnode locked.
	 *
	 * @exception BackingStoreException when the backing store cannot be
	 *            reached
	 * @exception IllegalStateException if this node has been removed
	 */
	public void sync() throws BackingStoreException {
		flushNode(true);
	}

	/**
	 * Private helper method that locks this node and calls either
	 * <code>flushSpi()</code> if <code>sync</code> is false, or
	 * <code>flushSpi()</code> if <code>sync</code> is true. Then it gets all
	 * the currently cached subnodes. For every subnode it calls this method
	 * recursively with this node no longer locked.
	 * <p>
	 * Called by either <code>flush()</code> or <code>sync()</code>
	 */
	private void flushNode(boolean sync) throws BackingStoreException {
		String[] keys = null;
		synchronized (lock) {
			if (sync) {
				syncSpi();
			} else {
				flushSpi();
			}
			keys = (String[]) childCache.keySet().toArray();
		}

		if (keys != null) {
			for (int i = 0; i < keys.length; i++) {
				// Have to lock this node again to access the childCache
				AbstractPreferences subNode;
				synchronized (this) {
					subNode = (AbstractPreferences) childCache.get(keys[i]);
				}

				// The child could already have been removed from the cache
				if (subNode != null) {
					subNode.flushNode(sync);
				}
			}
		}
	}

	/**
	 * Removes this and all subnodes from the backing store and clears all
	 * entries. After removal this instance will not be useable (except for
	 * a few methods that don't throw a <code>InvalidStateException</code>),
	 * even when a new node with the same path name is created this instance
	 * will not be usable again.
	 * <p>
	 * Checks that this is not a root node. If not it locks the parent node,
	 * then locks this node and checks that the node has not yet been removed.
	 * Then it makes sure that all subnodes of this node are in the child cache,
	 * by calling <code>childSpi()</code> on any children not yet in the cache.
	 * Then for all children it locks the subnode and removes it. After all
	 * subnodes have been purged the child cache is cleared, this nodes removed
	 * flag is set and any listeners are called. Finally this node is removed
	 * from the child cache of the parent node.
	 *
	 * @exception BackingStoreException when the backing store cannot be
	 *            reached
	 * @exception IllegalStateException if this node has already been removed
	 * @exception UnsupportedOperationException if this is a root node
	 */
	public void removeNode() throws BackingStoreException {
		// Check if it is a root node
		if (parent == null)
			throw new UnsupportedOperationException("Cannot remove root node");

		synchronized (parent) {
			synchronized (this) {
				if (isRemoved())
					throw new IllegalStateException("Node Removed");

				purge();
			}
			parent.childCache.remove(name);
		}
	}

	/**
	 * Private helper method used to completely remove this node.
	 * Called by <code>removeNode</code> with the parent node and this node
	 * locked.
	 * <p>
	 * Makes sure that all subnodes of this node are in the child cache,
	 * by calling <code>childSpi()</code> on any children not yet in the
	 * cache. Then for all children it locks the subnode and calls this method
	 * on that node. After all subnodes have been purged the child cache is
	 * cleared, this nodes removed flag is set and any listeners are called.
	 */
	private void purge() throws BackingStoreException {
		// Make sure all children have an AbstractPreferences node in cache
		String children[] = childrenNamesSpi();
		for (int i = 0; i < children.length; i++) {
			if (childCache.get(children[i]) == null)
				childCache.put(children[i], childSpi(children[i]));
		}

		// purge all children
		Iterator i = childCache.values().iterator();
		while (i.hasNext()) {
			AbstractPreferences node = (AbstractPreferences) i.next();
			synchronized (node) {
				node.purge();
			}
		}

		// Cache is empty now
		childCache.clear();

		// remove this node
		removeNodeSpi();
		removed = true;

		// XXX - check for listeners
	}

	// listener methods

	/**
	 * XXX
	 */
	public void addNodeChangeListener(NodeChangeListener listener) {
		// XXX
	}

	public void addPreferenceChangeListener(PreferenceChangeListener listener) {
		// XXX
	}

	public void removeNodeChangeListener(NodeChangeListener listener) {
		// XXX
	}

	public void removePreferenceChangeListener(PreferenceChangeListener listener) {
		// XXX
	}

	// abstract spi methods

	/**
	 * Returns the names of the sub nodes of this preference node.
	 * This method only has to return any not yet cached child names,
	 * but may return all names if that is easier. It must not return
	 * null when there are no children, it has to return an empty array
	 * in that case. Since this method must consult the backing store to
	 * get all the sub node names it may throw a BackingStoreException.
	 * <p>
	 * Called by <code>childrenNames()</code> with this node locked.
	 */
	protected abstract String[] childrenNamesSpi() throws BackingStoreException;

	/**
	 * Returns a child note with the given name.
	 * This method is called by the <code>node()</code> method (indirectly
	 * through the <code>getNode()</code> helper method) with this node locked
	 * if a sub node with this name does not already exist in the child cache.
	 * If the child node did not aleady exist in the backing store the boolean
	 * field <code>newNode</code> of the returned node should be set.
	 * <p>
	 * Note that this method should even return a non-null child node if the
	 * backing store is not available since it may not throw a
	 * <code>BackingStoreException</code>.
	 */
	protected abstract AbstractPreferences childSpi(String name);

	/**
	 * Returns an (possibly empty) array with all the keys of the preference
	 * entries of this node.
	 * <p>
	 * Called by <code>keys()</code> with this node locked if this node has
	 * not been removed. May throw an exception when the backing store cannot
	 * be accessed.
	 *
	 * @exception BackingStoreException when the backing store cannot be     
	 *            reached
	 */
	abstract protected String[] keysSpi() throws BackingStoreException;

	/**
	 * Returns the value associated with the key in this preferences node or
	 * null when the key does not exist in this preferences node.
	 * <p>
	 * Called by <code>key()</code> with this node locked after checking that
	 * key is valid, not null and that the node has not been removed.
	 * <code>key()</code> will catch any exceptions that this method throws.
	 */
	abstract protected String getSpi(String key);

	/**
	 * Sets the value of the given preferences entry for this node.
	 * The implementation is not required to propagate the change to the
	 * backing store immediatly. It may not throw an exception when it tries
	 * to write to the backing store and that operation fails, the failure
	 * should be registered so a later invocation of <code>flush()</code>
	 * or <code>sync()</code> can signal the failure.
	 * <p>
	 * Called by <code>put()</code> with this node locked after checking that
	 * key and value are valid and non-null.
	 */
	abstract protected void putSpi(String key, String value);

	/**
	 * Removes the given key entry from this preferences node.
	 * The implementation is not required to propagate the change to the
	 * backing store immediatly.  It may not throw an exception when it tries
	 * to write to the backing store and that operation fails, the failure
	 * should be registered so a later invocation of <code>flush()</code>
	 * or <code>sync()</code> can signal the failure.
	 * <p>
	 * Called by <code>remove()</code> with this node locked after checking
	 * that the key is valid and non-null.
	 */
	abstract protected void removeSpi(String key);

	/**
	 * Writes all entries of this preferences node that have not yet been
	 * written to the backing store and possibly creates this node in the
	 * backing store, if it does not yet exist. Should only write changes to
	 * this node and not write changes to any subnodes.
	 * Note that the node can be already removed in this VM. To check if
	 * that is the case the implementation can call <code>isRemoved()</code>.
	 * <p>
	 * Called (indirectly) by <code>flush()</code> with this node locked.
	 */
	abstract protected void flushSpi() throws BackingStoreException;

	/**
	 * Writes all entries of this preferences node that have not yet been
	 * written to the backing store and reads any entries that have changed
	 * in the backing store but that are not yet visible in this VM.
	 * Should only sync this node and not change any of the subnodes.
	 * Note that the node can be already removed in this VM. To check if
	 * that is the case the implementation can call <code>isRemoved()</code>.
	 * <p>
	 * Called (indirectly) by <code>sync()</code> with this node locked.
	 */
	abstract protected void syncSpi() throws BackingStoreException;

	/**
	 * Clears this node from this VM and removes it from the backing store.
	 * After this method has been called the node is marked as removed.
	 * <p>
	 * Called (indirectly) by <code>removeNode()</code> with this node locked
	 * after all the sub nodes of this node have already been removed.
	 */
	abstract protected void removeNodeSpi() throws BackingStoreException;
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?