/*
* JBoss, Home of Professional Open Source.
* Copyright 2000 - 2008, Red Hat Middleware LLC, and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.cache;
import net.jcip.annotations.ThreadSafe;
import java.util.Map;
import java.util.Set;
/**
* A Node is a {@link Fqn named} logical grouping of data in the JBoss {@link Cache}.
* A node should be used to contain data for a single data record, for example
* information about a particular person or account.
*
* One purpose of grouping cache data into separate nodes is to minimize transaction
* locking interference, and increase concurrency. So for example, when multiple threads or
* possibly distributed caches are acccessing different accounts simultaneously.
*
* Another is that when making changes to this node, its data might be kept in a single
* database row or file on disk. (Persisted via the use of a {@link org.jboss.cache.loader.CacheLoader}.)
*
* A node has references to its children, parent (each node except the root - defined by {@link Fqn#ROOT} - has
* a single parent) and data contained within the node (as key/value pairs). The
* data access methods are similar to the collections {@link Map} interface,
* but some are read-only or return copies of the underlying the data.
*
*
* @author Manik Surtani (manik AT jboss DOT org)
* @see Cache
* @since 2.0.0
*/
@ThreadSafe
public interface Node
{
/**
* Returns the parent node.
* If this is the root node, this method returns null
.
*
* @return the parent node, or null if this is the root node
*/
Node getParent();
/**
* Returns an immutable set of children nodes.
*
* @return an immutable {@link Set} of child nodes. Empty {@link Set} if there aren't any children.
*/
Set> getChildren();
/**
* Returns an immutable set of children node names.
*
* @return an immutable {@link Set} of child node names. Empty {@link Set} if there aren't any children.
*/
Set getChildrenNames();
/**
* Returns a map containing the data in this {@link Node}.
*
* @return a {@link Map} containing the data in this {@link Node}. If there is no data, an empty {@link Map} is returned. The {@link Map} returned is always immutable.
*/
Map getData();
/**
* Returns a {@link Set} containing the data in this {@link Node}.
*
* @return a {@link Set} containing the data in this {@link Node}. If there is no data, an empty {@link Set} is returned. The {@link Set} returned is always immutable.
*/
Set getKeys();
/**
* Returns the {@link Fqn} which represents the location of this {@link Node} in the cache structure. The {@link Fqn} returned is absolute.
*
* @return The {@link Fqn} which represents the location of this {@link Node} in the cache structure. The {@link Fqn} returned is absolute.
*/
Fqn getFqn();
/**
* Adds a child node with the given {@link Fqn} under the current node. Returns the newly created node.
*
* If the child exists returns the child node anyway. Guaranteed to return a non-null node.
*
* The {@link Fqn} passed in is relative to the current node. The new child node will have an absolute fqn
* calculated as follows: new Fqn(getFqn(), f) . See {@link Fqn} for the operation of this constructor.
*
* @param f {@link Fqn} of the child node, relative to the current node.
* @return the newly created node, or the existing node if one already exists.
*/
Node addChild(Fqn f);
/**
* Removes a child node specified by the given relative {@link Fqn}.
*
* If you wish to remove children based on absolute {@link Fqn}s, use the {@link Cache} interface instead.
*
* @param f {@link Fqn} of the child node, relative to the current node.
* @return true if the node was found and removed, false otherwise
*/
boolean removeChild(Fqn f);
/**
* Removes a child node specified by the given name.
*
* @param childName name of the child node, directly under the current node.
* @return true if the node was found and removed, false otherwise
*/
boolean removeChild(Object childName);
/**
* Returns the child node
*
* @param f {@link Fqn} of the child node
* @return null if the child does not exist.
*/
Node getChild(Fqn f);
/**
* @param name name of the child
* @return a direct child of the current node.
*/
Node getChild(Object name);
/**
* Associates the specified value with the specified key for this node.
* If this node previously contained a mapping for this key, the old value is replaced by the specified value.
*
* @param key key with which the specified value is to be associated.
* @param value value to be associated with the specified key.
* @return Returns the old value contained under this key. Null if key doesn't exist.
*/
V put(K key, V value);
/**
* If the specified key is not already associated with a value, associate it with the given value, and returns the
* Object (if any) that occupied the space, or null.
*
* Equivalent to calling
*
* if (!node.getKeys().contains(key))
* return node.put(key, value);
* else
* return node.get(key);
*
*
* except that this is atomic.
*
* @param key key with which the specified value is to be associated.
* @param value value to be associated with the specified key.
* @return previous value associated with specified key, or null if there was no mapping for key.
*/
V putIfAbsent(K key, V value);
/**
* Replace entry for key only if currently mapped to some value.
* Acts as
*
* if ((node.getKeys().contains(key))
* {
* return node.put(key, value);
* }
* else
* return null;
*
*
* except that this is atomic.
*
* @param key key with which the specified value is associated.
* @param value value to be associated with the specified key.
* @return previous value associated with specified key, or null
* if there was no mapping for key.
*/
V replace(K key, V value);
/**
* Replace entry for key only if currently mapped to given value.
* Acts as
*
* if (node.get(key).equals(oldValue))
* {
* node.put(key, newValue);
* return true;
* }
* else
* return false;
*
*
* except that this is atomic.
*
* @param key key with which the specified value is associated.
* @param oldValue value expected to be associated with the specified key.
* @param newValue value to be associated with the specified key.
* @return true if the value was replaced
*/
boolean replace(K key, V oldValue, V newValue);
/**
* Copies all of the mappings from the specified map to this node's map.
* If any data exists, existing keys are overwritten with the keys in the new map.
* The behavior is equivalent to:
*
* Node node;
* for (Map.Entry me : map.entrySet())
* node.put(me.getKey(), me.getValue());
*
*
* @param map map to copy from
*/
void putAll(Map extends K, ? extends V> map);
/**
* Similar to {@link #putAll(java.util.Map)} except that it removes any entries that exists in
* the data map first. Note that this happens atomically, under a single lock. This is the analogous
* to doing a {@link #clearData()} followed by a {@link #putAll(java.util.Map)} in the same transaction.
*
* @param map map to copy from
*/
void replaceAll(Map extends K, ? extends V> map);
/**
* Returns the value to which this node maps the specified key.
* Returns null
if the node contains no mapping for this key.
*
* @param key key of the data to return
* @return the value to which this node maps the specified key, or null
if the map contains no mapping for this key
*/
V get(K key);
/**
* Removes the mapping for this key from this node if it is present.
* Returns the value to which the node previously associated the key,
* or null
if the node contained no mapping for this key
*
* @param key key whose mapping is to be removed
* @return previous value associated with specified key, or null
* if there was no mapping for key
*/
V remove(K key);
/**
* Removes all mappings from the node's data map.
*/
void clearData();
/**
* @return the number of elements (key/value pairs) in the node's data map.
*/
int dataSize();
/**
* Returns true if the child node denoted by the relative {@link Fqn} passed in exists.
*
* @param f {@link Fqn} relative to the current node of the child you are testing the existence of.
* @return true if the child node denoted by the relative {@link Fqn} passed in exists.
*/
boolean hasChild(Fqn f);
/**
* Returns true if the child node denoted by the Object name passed in exists.
*
* @param o name of the child, relative to the current node
* @return true if the child node denoted by the name passed in exists.
*/
boolean hasChild(Object o);
/**
* Tests if a node reference is still valid. A node reference may become invalid if it has been removed, invalidated
* or moved, either locally or remotely. If a node is invalid, it should be fetched again from the cache or a valid
* parent node. Operations on invalid nodes will throw a {@link org.jboss.cache.NodeNotValidException}.
*
* @return true if the node is valid.
*/
boolean isValid();
/**
* Nodes marked resident would be ignored by the eviction algorithms. E.g. if the algorithm is
* "keep LRU 10 nodes" - the resident nodes won't be counted within those 10 nodes,
* and also won't be evicted when the threshold is reached.
* N.B. calling this method won't have any effect on node's eviction, e.g. we won't consider this node as being
* 'used' in a LRU scenario. If the cache is used in a replicated environment then the resident property is NOT
* replicated across the cluster. Also the property is not transactionable.
*/
boolean isResident();
/**
* @see #isResident()
*/
void setResident(boolean resident);
/**
* Tests whether this node is configured to be exclusively locked when inserting or removing children.
*
* The default
* value for this is what is configured in the LockParentForChildInsertRemove configuration property,
* programatically reachable by querying {@link org.jboss.cache.config.Configuration#isLockParentForChildInsertRemove()}
*
* This can also be configured on a per-node basis using {@link #setLockForChildInsertRemove(boolean)}
*
* @return true if the node is configured to be exclusively locked for child insertions and removal, false otherwise.
* @since 2.1.0
*/
boolean isLockForChildInsertRemove();
/**
* Configures the behaviour of how this node is locked when adding/removing children.
*
* @param lockForChildInsertRemove if true, exclusive locks will be obtained when children are added/removed. If
* false, a shared "read lock" will be obtained instead.
* @since 2.1.0
*/
void setLockForChildInsertRemove(boolean lockForChildInsertRemove);
/**
* Method that releases object references of cached objects held in the cache by serializing them to byte buffers.
* Cached objects are lazily deserialized when accessed again, based on the calling thread's context class loader.
*
* This can be expensive, based on the effort required to serialize cached objects.
*
*
* @param recursive if true, child nodes will have their object references released as well.
*/
void releaseObjectReferences(boolean recursive);
/**
* @return true if the current node is a leaf node (i.e., has no children), or false otherwise.
*/
boolean isLeaf();
}