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 + -
显示快捷键?