abstractpreferences.java
来自「linux下建立JAVA虚拟机的源码KAFFE」· Java 代码 · 共 1,385 行 · 第 1/4 页
JAVA
1,385 行
* <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(new String[]{}); } if (keys != null) { for (int i = 0; i < keys.length; i++) { // Have to lock this node again to access the childCache AbstractPreferences subNode; synchronized(lock) { 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.lock) { synchronized(this.lock) { 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.lock) { node.purge(); } } // Cache is empty now childCache.clear(); // remove this node removeNodeSpi(); removed = true; if (nodeListeners != null) fire(new NodeChangeEvent(parent, this), false); } // listener methods /** * Add a listener which is notified when a sub-node of this node * is added or removed. * @param listener the listener to add */ public void addNodeChangeListener(NodeChangeListener listener) { synchronized (lock) { if (isRemoved()) throw new IllegalStateException("node has been removed"); if (listener == null) throw new NullPointerException("listener is null"); if (nodeListeners == null) nodeListeners = new ArrayList(); nodeListeners.add(listener); } } /** * Add a listener which is notified when a value in this node * is added, changed, or removed. * @param listener the listener to add */ public void addPreferenceChangeListener(PreferenceChangeListener listener) { synchronized (lock) { if (isRemoved()) throw new IllegalStateException("node has been removed"); if (listener == null) throw new NullPointerException("listener is null"); if (preferenceListeners == null) preferenceListeners = new ArrayList(); preferenceListeners.add(listener); } } /** * Remove the indicated node change listener from the list of * listeners to notify. * @param listener the listener to remove */ public void removeNodeChangeListener(NodeChangeListener listener) { synchronized (lock) { if (isRemoved()) throw new IllegalStateException("node has been removed"); if (listener == null) throw new NullPointerException("listener is null"); if (nodeListeners != null) nodeListeners.remove(listener); } } /** * Remove the indicated preference change listener from the list of * listeners to notify. * @param listener the listener to remove */ public void removePreferenceChangeListener (PreferenceChangeListener listener) { synchronized (lock) { if (isRemoved()) throw new IllegalStateException("node has been removed"); if (listener == null) throw new NullPointerException("listener is null"); if (preferenceListeners != null) preferenceListeners.remove(listener); } } /** * Send a preference change event to all listeners. Note that * the caller is responsible for holding the node's lock, and * for checking that the list of listeners is not null. * @param event the event to send */ private void fire(final PreferenceChangeEvent event) { Iterator it = preferenceListeners.iterator(); while (it.hasNext()) { final PreferenceChangeListener l = (PreferenceChangeListener) it.next(); EventDispatcher.dispatch(new Runnable() { public void run() { l.preferenceChange(event); } }); } } /** * Send a node change event to all listeners. Note that * the caller is responsible for holding the node's lock, and * for checking that the list of listeners is not null. * @param event the event to send */ private void fire(final NodeChangeEvent event, final boolean added) { Iterator it = nodeListeners.iterator(); while (it.hasNext()) { final NodeChangeListener l = (NodeChangeListener) it.next(); EventDispatcher.dispatch(new Runnable() { public void run() { if (added) l.childAdded(event); else l.childRemoved(event); } }); } } // 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 */ protected abstract 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. */ protected abstract 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 immediately. 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. */ protected abstract 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 immediately. 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. */ protected abstract 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. */ protected abstract 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. */ protected abstract 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. */ protected abstract void removeNodeSpi() throws BackingStoreException;}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?