[jbosscache-commits] JBoss Cache SVN: r4252 - in core/trunk: src/main/java/org/jboss/cache and 1 other directories.
jbosscache-commits at lists.jboss.org
jbosscache-commits at lists.jboss.org
Tue Aug 14 18:38:45 EDT 2007
Author: jason.greene at jboss.com
Date: 2007-08-14 18:38:44 -0400 (Tue, 14 Aug 2007)
New Revision: 4252
Added:
core/trunk/src/main/java/org/jboss/cache/AbstractNode.java
core/trunk/src/main/java/org/jboss/cache/Cache.java
core/trunk/src/main/java/org/jboss/cache/CacheException.java
core/trunk/src/main/java/org/jboss/cache/CacheFactory.java
core/trunk/src/main/java/org/jboss/cache/CacheImpl.java
core/trunk/src/main/java/org/jboss/cache/CacheSPI.java
core/trunk/src/main/java/org/jboss/cache/CacheStatus.java
core/trunk/src/main/java/org/jboss/cache/ConsoleListener.java
core/trunk/src/main/java/org/jboss/cache/DefaultCacheFactory.java
core/trunk/src/main/java/org/jboss/cache/Fqn.java
core/trunk/src/main/java/org/jboss/cache/FqnComparator.java
core/trunk/src/main/java/org/jboss/cache/InvocationContext.java
core/trunk/src/main/java/org/jboss/cache/Modification.java
core/trunk/src/main/java/org/jboss/cache/Node.java
core/trunk/src/main/java/org/jboss/cache/NodeFactory.java
core/trunk/src/main/java/org/jboss/cache/NodeNotExistsException.java
core/trunk/src/main/java/org/jboss/cache/NodeSPI.java
core/trunk/src/main/java/org/jboss/cache/RPCManager.java
core/trunk/src/main/java/org/jboss/cache/RPCManagerImpl.java
core/trunk/src/main/java/org/jboss/cache/Region.java
core/trunk/src/main/java/org/jboss/cache/RegionImpl.java
core/trunk/src/main/java/org/jboss/cache/RegionManager.java
core/trunk/src/main/java/org/jboss/cache/RegionNotEmptyException.java
core/trunk/src/main/java/org/jboss/cache/ReplicationException.java
core/trunk/src/main/java/org/jboss/cache/ReplicationQueue.java
core/trunk/src/main/java/org/jboss/cache/SuspectException.java
core/trunk/src/main/java/org/jboss/cache/TreeCacheViewMBean.java
core/trunk/src/main/java/org/jboss/cache/UnversionedNode.java
core/trunk/src/main/java/org/jboss/cache/Version.java
core/trunk/src/main/java/org/jboss/cache/VersionedNode.java
core/trunk/src/main/java/org/jboss/cache/buddyreplication/
core/trunk/src/main/java/org/jboss/cache/config/
core/trunk/src/main/java/org/jboss/cache/demo/
core/trunk/src/main/java/org/jboss/cache/eviction/
core/trunk/src/main/java/org/jboss/cache/factories/
core/trunk/src/main/java/org/jboss/cache/interceptors/
core/trunk/src/main/java/org/jboss/cache/jmx/
core/trunk/src/main/java/org/jboss/cache/loader/
core/trunk/src/main/java/org/jboss/cache/lock/
core/trunk/src/main/java/org/jboss/cache/marshall/
core/trunk/src/main/java/org/jboss/cache/notifications/
core/trunk/src/main/java/org/jboss/cache/optimistic/
core/trunk/src/main/java/org/jboss/cache/statetransfer/
core/trunk/src/main/java/org/jboss/cache/transaction/
core/trunk/src/main/java/org/jboss/cache/util/
core/trunk/src/main/java/org/jboss/cache/xml/
Removed:
core/trunk/src-old/org/jboss/cache/AbstractNode.java
core/trunk/src-old/org/jboss/cache/Cache.java
core/trunk/src-old/org/jboss/cache/CacheException.java
core/trunk/src-old/org/jboss/cache/CacheFactory.java
core/trunk/src-old/org/jboss/cache/CacheImpl.java
core/trunk/src-old/org/jboss/cache/CacheSPI.java
core/trunk/src-old/org/jboss/cache/CacheStatus.java
core/trunk/src-old/org/jboss/cache/ConsoleListener.java
core/trunk/src-old/org/jboss/cache/DefaultCacheFactory.java
core/trunk/src-old/org/jboss/cache/Fqn.java
core/trunk/src-old/org/jboss/cache/FqnComparator.java
core/trunk/src-old/org/jboss/cache/InvocationContext.java
core/trunk/src-old/org/jboss/cache/Modification.java
core/trunk/src-old/org/jboss/cache/Node.java
core/trunk/src-old/org/jboss/cache/NodeFactory.java
core/trunk/src-old/org/jboss/cache/NodeNotExistsException.java
core/trunk/src-old/org/jboss/cache/NodeSPI.java
core/trunk/src-old/org/jboss/cache/RPCManager.java
core/trunk/src-old/org/jboss/cache/RPCManagerImpl.java
core/trunk/src-old/org/jboss/cache/Region.java
core/trunk/src-old/org/jboss/cache/RegionImpl.java
core/trunk/src-old/org/jboss/cache/RegionManager.java
core/trunk/src-old/org/jboss/cache/RegionNotEmptyException.java
core/trunk/src-old/org/jboss/cache/ReplicationException.java
core/trunk/src-old/org/jboss/cache/ReplicationQueue.java
core/trunk/src-old/org/jboss/cache/SuspectException.java
core/trunk/src-old/org/jboss/cache/TreeCacheViewMBean.java
core/trunk/src-old/org/jboss/cache/UnversionedNode.java
core/trunk/src-old/org/jboss/cache/Version.java
core/trunk/src-old/org/jboss/cache/VersionedNode.java
core/trunk/src-old/org/jboss/cache/buddyreplication/
core/trunk/src-old/org/jboss/cache/config/
core/trunk/src-old/org/jboss/cache/demo/
core/trunk/src-old/org/jboss/cache/eviction/
core/trunk/src-old/org/jboss/cache/factories/
core/trunk/src-old/org/jboss/cache/interceptors/
core/trunk/src-old/org/jboss/cache/jmx/
core/trunk/src-old/org/jboss/cache/loader/
core/trunk/src-old/org/jboss/cache/lock/
core/trunk/src-old/org/jboss/cache/marshall/
core/trunk/src-old/org/jboss/cache/notifications/
core/trunk/src-old/org/jboss/cache/optimistic/
core/trunk/src-old/org/jboss/cache/statetransfer/
core/trunk/src-old/org/jboss/cache/transaction/
core/trunk/src-old/org/jboss/cache/util/
core/trunk/src-old/org/jboss/cache/xml/
Modified:
core/trunk/pom.xml
Log:
Relocate source files
Modified: core/trunk/pom.xml
===================================================================
--- core/trunk/pom.xml 2007-08-14 19:09:32 UTC (rev 4251)
+++ core/trunk/pom.xml 2007-08-14 22:38:44 UTC (rev 4252)
@@ -44,6 +44,21 @@
<version>1.7.0</version>
</dependency>
<dependency>
+ <groupId>net.jcip</groupId>
+ <artifactId>jcip-annotations</artifactId>
+ <version>1.0</version>
+ </dependency>
+ <dependency>
+ <groupId>beanshell</groupId>
+ <artifactId>bsh</artifactId>
+ <version>2.0b4</version>
+ </dependency>
+ <dependency>
+ <groupId>jboss</groupId>
+ <artifactId>jboss-j2ee</artifactId>
+ <version>4.2.0.GA</version>
+ </dependency>
+ <dependency>
<groupId>org.jboss.microcontainer</groupId>
<artifactId>jboss-aop-mc-int</artifactId>
<version>2.0.0-SNAPSHOT</version>
Copied: core/trunk/src/main/java/org/jboss/cache/AbstractNode.java (from rev 4250, core/trunk/src-old/org/jboss/cache/AbstractNode.java)
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/AbstractNode.java (rev 0)
+++ core/trunk/src/main/java/org/jboss/cache/AbstractNode.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -0,0 +1,58 @@
+/**
+ *
+ */
+package org.jboss.cache;
+
+import java.util.Map;
+
+/**
+ * Base class for {@link UnversionedNode}.
+ *
+ * @author manik
+ */
+public abstract class AbstractNode<K, V> implements Node<K, V>
+{
+ protected boolean deleted;
+ protected Map<Object, Node<K, V>> children;
+ protected Fqn fqn;
+
+ public boolean isDeleted()
+ {
+ return deleted;
+ }
+
+ public void markAsDeleted(boolean marker)
+ {
+ markAsDeleted(marker, false);
+ }
+
+ public void markAsDeleted(boolean marker, boolean recursive)
+ {
+ deleted = marker;
+ if (recursive && children != null)
+ {
+ synchronized (this)
+ {
+ for (Node child : children.values())
+ {
+ ((AbstractNode) child).markAsDeleted(marker, true);
+ }
+ }
+ }
+ }
+
+ public boolean equals(Object another)
+ {
+ if (another instanceof AbstractNode)
+ {
+ AbstractNode anotherNode = (AbstractNode) another;
+ return fqn == null && anotherNode.fqn == null || !(fqn == null || anotherNode.fqn == null) && fqn.equals(anotherNode.fqn);
+ }
+ return false;
+ }
+
+ public int hashCode()
+ {
+ return fqn.hashCode();
+ }
+}
Copied: core/trunk/src/main/java/org/jboss/cache/Cache.java (from rev 4250, core/trunk/src-old/org/jboss/cache/Cache.java)
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/Cache.java (rev 0)
+++ core/trunk/src/main/java/org/jboss/cache/Cache.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -0,0 +1,373 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package org.jboss.cache;
+
+import net.jcip.annotations.ThreadSafe;
+import org.jboss.cache.config.Configuration;
+import org.jgroups.Address;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Interface for a Cache where data mappings are grouped and stored in a tree data
+ * structure consisting of {@link Node}s.
+ * <p/>
+ * This is the central construct and basic client API of JBoss Cache and is used for
+ * cache-wide operations.
+ * <p/>
+ * The cache is constructed using a {@link CacheFactory} and is started
+ * using {@link #start}, if not already started by the CacheFactory.
+ * <p/>
+ * Once constructed, the Cache interface can be used to create or access {@link Node}s, which contain data. Once references
+ * to {@link Node}s are obtained, data can be stored in them,
+ * <p/>
+ * As a convenience (and mainly to provide a familiar API to the older JBoss Cache 1.x.x releases) methods are provided that
+ * operate directly on nodes.
+ * <ul>
+ * <li>{@link #put(Fqn,Object,Object)} </li>
+ * <li>{@link #put(Fqn,java.util.Map)} </li>
+ * <li>{@link #get(Fqn,Object)} </li>
+ * <li>{@link #remove(Fqn,Object)} </li>
+ * <li>{@link #removeNode(Fqn)} </li>
+ * </ul>
+ * <p/>
+ * A simple example of usage:
+ * <pre>
+ * // creates with default settings and starts the cache
+ * Cache cache = DefaultCacheFactory.getInstance().createCache();
+ * Fqn personRecords = Fqn.fromString("/org/mycompany/personRecords");
+ * <p/>
+ * Node rootNode = cache.getRoot();
+ * Node personRecordsNode = rootNode.addChild(personRecords);
+ * <p/>
+ * // now add some person records.
+ * Fqn peterGriffin = Fqn.fromString("/peterGriffin");
+ * Fqn stewieGriffin = Fqn.fromString("/stewieGriffin");
+ * <p/>
+ * // the addChild() API uses relative Fqns
+ * Node peter = personRecordsNode.addChild(peterGriffin);
+ * Node stewie = personRecordsNode.addChild(stewieGriffin);
+ * <p/>
+ * peter.put("name", "Peter Griffin");
+ * peter.put("ageGroup", "MidLifeCrisis");
+ * peter.put("homicidal", Boolean.FALSE);
+ * <p/>
+ * stewie.put("name", "Stewie Griffin");
+ * stewie.put("ageGroup", "Infant");
+ * stewie.put("homicidal", Boolean.TRUE);
+ * <p/>
+ * peter.getFqn().toString(); // will print out /org/mycompany/personRecords/peterGriffin
+ * stewie.getFqn().toString(); // will print out /org/mycompany/personRecords/stewieGriffin
+ * <p/>
+ * peter.getFqn().getParent().equals(stewie.getFqn().getParent()); // will return true
+ * <p/>
+ * </pre>
+ * <p/>
+ * For more information, please read the JBoss Cache user guide and tutorial, available on <a href="http://labs.jboss.com/portal/jbosscache/docs/index.html" target="_BLANK">the JBoss Cache documentation site</a>,
+ * and look through the examples <a href="http://labs.jboss.com/portal/jbosscache/download/index.html" target="_BLANK">shipped with the JBoss Cache distribution</a>.
+ *
+ * @author <a href="mailto:manik at jboss.org">Manik Surtani (manik at jboss.org)</a>
+ * @see Node
+ * @see CacheFactory
+ * @since 2.0.0
+ */
+ at ThreadSafe
+public interface Cache<K, V>
+{
+ /**
+ * Retrieves the configuration of this cache.
+ *
+ * @return the configuration.
+ */
+ Configuration getConfiguration();
+
+ /**
+ * Returns the root node of this cache.
+ *
+ * @return the root node
+ */
+ Node<K, V> getRoot();
+
+ /**
+ * Adds a {@link @org.jboss.cache.notifications.annotation.CacheListener}-annotated object to the entire cache. The object passed in needs to be properly annotated with the
+ * {@link @org.jboss.cache.notifications.annotation.CacheListener} annotation otherwise an {@link org.jboss.cache.notifications.IncorrectCacheListenerException} will be thrown.
+ *
+ * @param listener listener to add
+ */
+ void addCacheListener(Object listener);
+
+ /**
+ * Adds a {@link @org.jboss.cache.notifications.annotation.CacheListener}-annotated object to a given region. The object passed in needs to be properly annotated with the
+ * {@link @org.jboss.cache.notifications.annotation.CacheListener} annotation otherwise an {@link org.jboss.cache.notifications.IncorrectCacheListenerException} will be thrown.
+ *
+ * @param region region to add listener to
+ * @param listener listener to add
+ */
+ void addCacheListener(Fqn<?> region, Object listener);
+
+ /**
+ * Removes a {@link @org.jboss.cache.notifications.annotation.CacheListener}-annotated object from the cache. The object passed in needs to be properly annotated with the
+ * {@link @org.jboss.cache.notifications.annotation.CacheListener} annotation otherwise an {@link org.jboss.cache.notifications.IncorrectCacheListenerException} will be thrown.
+ *
+ * @param listener listener to remove
+ */
+ void removeCacheListener(Object listener);
+
+ /**
+ * Removes a {@link @org.jboss.cache.notifications.annotation.CacheListener}-annotated object from a given region. The object passed in needs to be properly annotated with the
+ * {@link @org.jboss.cache.notifications.annotation.CacheListener} annotation otherwise an {@link org.jboss.cache.notifications.IncorrectCacheListenerException} will be thrown.
+ *
+ * @param region region from which to remove listener
+ * @param listener listener to remove
+ */
+ void removeCacheListener(Fqn<?> region, Object listener);
+
+ /**
+ * Retrieves an immutable {@link List} of objects annotated as {@link org.jboss.cache.notifications.annotation.CacheListener}s attached to the cache.
+ *
+ * @return an immutable {@link List} of objects annotated as {@link org.jboss.cache.notifications.annotation.CacheListener}s attached to the cache.
+ */
+ Set<Object> getCacheListeners();
+
+ /**
+ * Retrieves an immutable {@link List} of objects annotated as {@link org.jboss.cache.notifications.annotation.CacheListener}s attached to a specific region.
+ *
+ * @return an immutable {@link List} of objects annotated as {@link org.jboss.cache.notifications.annotation.CacheListener}s attached to a specific region.
+ */
+ Set<Object> getCacheListeners(Fqn<?> region);
+
+ /**
+ * Associates the specified value with the specified key for a {@link Node} in this cache.
+ * If the {@link Node} previously contained a mapping for this key, the old value is replaced by the specified value.
+ *
+ * @param fqn <b><i>absolute</i></b> {@link Fqn} to the {@link Node} to be accessed.
+ * @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 <code>null</code> if there was no mapping for key.
+ * A <code>null</code> return can also indicate that the Node previously associated <code>null</code> with the specified key, if the implementation supports null values.
+ */
+ V put(Fqn<?> fqn, K key, V value);
+
+ /**
+ * Under special operating behavior, associates the value with the specified key for a node identified by the Fqn passed in.
+ * <ul>
+ * <li> Only goes through if the node specified does not exist; no-op otherwise.</i>
+ * <li> Force asynchronous mode for replication or invalidation to prevent any blocking.</li>
+ * <li> 0ms lock timeout to prevent any blocking here either. If the lock is not acquired, this method is a no-op, and swallows the timeout exception.</li>
+ * <li> Ongoing transactions are suspended before this call, so failures here will not affect any ongoing transactions.</li>
+ * <li> Errors and exceptions are 'silent' - logged at a much lower level than normal, and this method does not throw exceptions</li>
+ * </ul>
+ * This method is for caching data that has an external representation in storage, where, concurrent modification and
+ * transactions are not a consideration, and failure to put the data in the cache should be treated as a 'suboptimal outcome'
+ * rather than a 'failing outcome'.
+ * <p/>
+ * An example of when this method is useful is when data is read from, for example, a legacy datastore, and is cached before
+ * returning the data to the caller. Subsequent calls would prefer to get the data from the cache and if the data doesn't exist
+ * in the cache, fetch again from the legacy datastore.
+ * <p/>
+ * See <a href="http://jira.jboss.com/jira/browse/JBCACHE-848">JBCACHE-848</a> for details around this feature.
+ * <p/>
+ *
+ * @param fqn <b><i>absolute</i></b> {@link Fqn} to the {@link Node} to be accessed.
+ * @param key key with which the specified value is to be associated.
+ * @param value value to be associated with the specified key.
+ */
+ void putForExternalRead(Fqn<?> fqn, K key, V value);
+
+ /**
+ * Copies all of the mappings from the specified map to a {@link Node}.
+ *
+ * @param fqn <b><i>absolute</i></b> {@link Fqn} to the {@link Node} to copy the data to
+ * @param data mappings to copy
+ */
+ void put(Fqn<?> fqn, Map<K, V> data);
+
+ /**
+ * Removes the mapping for this key from a Node.
+ * Returns the value to which the Node previously associated the key, or
+ * <code>null</code> if the Node contained no mapping for this key.
+ *
+ * @param fqn <b><i>absolute</i></b> {@link Fqn} to the {@link Node} to be accessed.
+ * @param key key whose mapping is to be removed from the Node
+ * @return previous value associated with specified Node's key
+ */
+ V remove(Fqn<?> fqn, K key);
+
+ /**
+ * Removes a {@link Node} indicated by absolute {@link Fqn}.
+ *
+ * @param fqn {@link Node} to remove
+ * @return true if the node was removed, false if the node was not found
+ */
+ boolean removeNode(Fqn<?> fqn);
+
+ /**
+ * Convenience method that allows for direct access to the data in a {@link Node}.
+ *
+ * @param fqn <b><i>absolute</i></b> {@link Fqn} to the {@link Node} to be accessed.
+ * @param key key under which value is to be retrieved.
+ * @return returns data held under specified key in {@link Node} denoted by specified Fqn.
+ */
+ V get(Fqn<?> fqn, K key);
+
+ /**
+ * Eviction call that evicts the specified {@link Node} from memory.
+ *
+ * @param fqn <b><i>absolute</i></b> {@link Fqn} to the {@link Node} to be evicted.
+ * @param recursive evicts children as well
+ */
+ void evict(Fqn<?> fqn, boolean recursive);
+
+ /**
+ * Retrieves a {@link Region} for a given {@link Fqn}. If the region does not exist,
+ * and <li>createIfAbsent</li> is true, then one is created.
+ * <p/>
+ * If not, parent Fqns will be consulted in turn for registered regions, gradually working up to
+ * Fqn.ROOT. If no regions are defined in any of the parents either, a null is returned.
+ *
+ * @param fqn Fqn that is contained in a region.
+ * @param createIfAbsent If true, will create a new associated region if not found.
+ * @return a MarshRegion. Null if none is found.
+ * @throws UnsupportedOperationException if the region cannot be defined.
+ * @see Region
+ */
+ Region getRegion(Fqn<?> fqn, boolean createIfAbsent);
+
+ /**
+ * Removes a region denoted by the Fqn passed in.
+ *
+ * @param fqn of the region to remove
+ * @return true if a region did exist and was removed; false otherwise.
+ */
+ boolean removeRegion(Fqn<?> fqn);
+
+ /**
+ * Lifecycle method that initializes configuration state, the root node, etc.
+ *
+ * @throws CacheException if there are creation problems
+ */
+ void create() throws CacheException;
+
+ /**
+ * Lifecycle method that starts the cache loader,
+ * starts cache replication, starts the region manager, etc., and (if configured) warms the cache using a
+ * state transfer or cache loader preload.
+ *
+ * @throws CacheException if there are startup problems
+ */
+ void start() throws CacheException;
+
+ /**
+ * Lifecycle method that stops the cache, including replication,
+ * clustering, cache loading, notifications, etc., and clears all cache in-memory state.
+ * <p/>
+ * State can be reconstituted by using either a cache loader or state transfer when the cache starts again.
+ */
+ void stop();
+
+ /**
+ * Lifecycle method that destroys the cache and removes any interceptors/configuration elements.
+ * Cache can then be restarted (potentially after reconfiguring) using {@link #create()} and {@link #start()}.
+ */
+ void destroy();
+
+ /**
+ * Gets where the cache currently is its lifecycle transitions.
+ *
+ * @return the CacheStatus. Will not return <code>null</code>.
+ */
+ CacheStatus getCacheStatus();
+
+ /**
+ * @return the current invocation context for the current invocation and cache instance.
+ * @see org.jboss.cache.InvocationContext
+ */
+ InvocationContext getInvocationContext();
+
+ /**
+ * Sets the passed in {@link org.jboss.cache.InvocationContext} as current.
+ *
+ * @param ctx invocation context to use
+ */
+ void setInvocationContext(InvocationContext ctx);
+
+ /**
+ * Returns the local address of this cache in a cluster, or <code>null</code>
+ * if running in local mode.
+ *
+ * @return the local address of this cache in a cluster, or <code>null</code>
+ * if running in local mode.
+ */
+ Address getLocalAddress();
+
+ /**
+ * Returns a list of members in the cluster, or <code>null</code>
+ * if running in local mode.
+ *
+ * @return a {@link List} of members in the cluster, or <code>null</code>
+ * if running in local mode.
+ */
+ List<Address> getMembers();
+
+ /**
+ * Moves a part of the cache to a different subtree.
+ * <p/>
+ * E.g.:
+ * <p/>
+ * assume a cache structure such as:
+ * <p/>
+ * <pre>
+ * /a/b/c
+ * /a/b/d
+ * /a/b/e
+ * <p/>
+ * <p/>
+ * Fqn f1 = Fqn.fromString("/a/b/c");
+ * Fqn f2 = Fqn.fromString("/a/b/d");
+ * <p/>
+ * cache.move(f1, f2);
+ * </pre>
+ * <p/>
+ * Will result in:
+ * <pre>
+ * <p/>
+ * /a/b/d/c
+ * /a/b/e
+ * <p/>
+ * </pre>
+ * <p/>
+ * and now
+ * <p/>
+ * <pre>
+ * Fqn f3 = Fqn.fromString("/a/b/e");
+ * Fqn f4 = Fqn.fromString("/a");
+ * cache.move(f3, f4);
+ * </pre>
+ * <p/>
+ * will result in:
+ * <pre>
+ * /a/b/d/c
+ * /a/e
+ * </pre>
+ * No-op if the node to be moved is the root node.
+ *
+ * @param nodeToMove the Fqn of the node to move.
+ * @param newParent new location under which to attach the node being moved.
+ * @throws NodeNotExistsException may throw one of these if the target node does not exist or if a different thread has moved this node elsewhere already.
+ */
+ void move(Fqn<?> nodeToMove, Fqn<?> newParent) throws NodeNotExistsException;
+
+ /**
+ * Returns the version of the cache as a string.
+ *
+ * @return the version string of the cache.
+ * @see Version#printVersion
+ */
+ String getVersion();
+}
Copied: core/trunk/src/main/java/org/jboss/cache/CacheException.java (from rev 4250, core/trunk/src-old/org/jboss/cache/CacheException.java)
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/CacheException.java (rev 0)
+++ core/trunk/src/main/java/org/jboss/cache/CacheException.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -0,0 +1,45 @@
+// $Id$
+
+/*
+ * JBoss, the OpenSource J2EE webOS
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+
+package org.jboss.cache;
+
+/**
+ * Thrown when operations on {@link org.jboss.cache.Cache} or {@link org.jboss.cache.Node} fail unexpectedly.
+ * <p/>
+ * Specific subclasses such as {@link org.jboss.cache.lock.TimeoutException}, {@link org.jboss.cache.config.ConfigurationException} and {@link org.jboss.cache.lock.LockingException}
+ * have more specific uses.
+ *
+ * @author <a href="mailto:bela at jboss.org">Bela Ban</a>
+ * @author <a href="mailto:manik at jboss.org">Manik Surtani</a>
+ */
+public class CacheException extends RuntimeException
+{
+
+ private static final long serialVersionUID = -4386393072593859164L;
+
+ public CacheException()
+ {
+ super();
+ }
+
+ public CacheException(Throwable cause)
+ {
+ super(cause);
+ }
+
+ public CacheException(String msg)
+ {
+ super(msg);
+ }
+
+ public CacheException(String msg, Throwable cause)
+ {
+ super(msg, cause);
+ }
+}
Copied: core/trunk/src/main/java/org/jboss/cache/CacheFactory.java (from rev 4250, core/trunk/src-old/org/jboss/cache/CacheFactory.java)
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/CacheFactory.java (rev 0)
+++ core/trunk/src/main/java/org/jboss/cache/CacheFactory.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -0,0 +1,112 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package org.jboss.cache;
+
+import net.jcip.annotations.ThreadSafe;
+import org.jboss.cache.config.Configuration;
+import org.jboss.cache.config.ConfigurationException;
+
+/**
+ * This factory constructs a cache from a given or default configuration set.
+ * <p/>
+ * Typical usage would be:
+ * <p/>
+ * <pre>
+ * CacheFactory factory = DefaultCacheFactory.getInstance();
+ * Cache cache = factory.createCache("replSync-service.xml"); // expects this file to be in classpath
+ * cache.stop();
+ * </pre>
+ * Factory methods provide options for creating a cache using
+ * <ul>
+ * <li>default configuration settings</li>
+ * <li>an XML file containing the configuration</li>
+ * <li>a constructed and populated {@link org.jboss.cache.config.Configuration} object</li>
+ * </ul>
+ * In addition, methods provide anadditional option to create and return a cache without starting it.
+ *
+ * @author <a href="mailto:manik at jboss.org">Manik Surtani (manik at jboss.org)</a>
+ * @see org.jboss.cache.Cache
+ * @see org.jboss.cache.DefaultCacheFactory
+ * @see org.jboss.cache.pojo.PojoCacheFactory
+ * @since 2.0.0
+ */
+ at ThreadSafe
+public interface CacheFactory<K, V>
+{
+ /**
+ * Creates and starts a {@link Cache} instance using default configuration settings. See {@link Configuration} for default values.
+ *
+ * @return a cache
+ * @throws ConfigurationException if there are problems with the default configuration
+ */
+ Cache<K, V> createCache() throws ConfigurationException;
+
+ /**
+ * Creates and optionally starts a {@link Cache} instance using default configuration settings. See {@link Configuration} for default values.
+ *
+ * @param start if true, starts the cache
+ * @return a cache
+ * @throws ConfigurationException if there are problems with the default configuration
+ */
+ Cache<K, V> createCache(boolean start) throws ConfigurationException;
+
+ /**
+ * Creates and starts a {@link org.jboss.cache.Cache} instance. The following are all valid calls:
+ * <pre>
+ * factory.createCache("myCacheService.xml"); // file is in class path
+ * factory.createCache("etc/myCacheService.xml"); // file is in etc/ relative to the directory you started the JVM
+ * factory.createCache("/home/jbosscache/myCacheService.xml"); // file is in the /home/jbosscache directory
+ * </pre>
+ *
+ * @param configFileName the named XML file should exist in the classpath or should be a fully qualified or relative (to your JVM working directory) path to a file on the local file system. Note that the classpath is checked first for the existence of this file.
+ * @return a running {@link org.jboss.cache.Cache} instance
+ * @throws org.jboss.cache.config.ConfigurationException
+ * if there are problems with the configuration
+ */
+ Cache<K, V> createCache(String configFileName) throws ConfigurationException;
+
+ /**
+ * Creates {@link Cache} instance, and optionally starts it.
+ *
+ * @param configFileName the named XML file should exist in the classpath or should be a fully qualified or relative (to your JVM working directory) path to a file on the local file system. Note that the classpath is checked first for the existence of this file.
+ * @param start if true, the cache is started before returning.
+ * @return an optionally running {@link Cache} instance
+ * @throws org.jboss.cache.config.ConfigurationException
+ * if there are problems with the configuration
+ * @see #createCache(String) for examples on valid config file names.
+ */
+ Cache<K, V> createCache(String configFileName, boolean start) throws ConfigurationException;
+
+ /**
+ * Creates a {@link Cache} instance based on a {@link org.jboss.cache.config.Configuration} passed in.
+ * <p/>
+ * Ensure that the Configuration you pass in is not used by another cache instance in the same JVM,
+ * as it may be concurrently modified. Clone the configuration, if shared, using
+ * {@link org.jboss.cache.config.Configuration#clone()}.
+ *
+ * @param configuration the {@link Configuration} object that is passed in to setCache the {@link Cache}.
+ * @return a running {@link Cache} instance
+ * @throws org.jboss.cache.config.ConfigurationException
+ * if there are problems with the configuration
+ */
+ Cache<K, V> createCache(Configuration configuration) throws ConfigurationException;
+
+ /**
+ * Creates {@link Cache} instance, and optionally starts it, based on a {@link org.jboss.cache.config.Configuration} passed in.
+ * <p/>
+ * Ensure that the Configuration you pass in is not used by another cache instance in the same JVM,
+ * as it may be concurrently modified. Clone the configuration, if shared, using
+ * {@link org.jboss.cache.config.Configuration#clone()}.
+ *
+ * @param configuration the {@link Configuration} object that is passed in to setCache the {@link Cache}.
+ * @param start if true, the cache is started before returning.
+ * @return an optionally running {@link Cache} instance
+ * @throws org.jboss.cache.config.ConfigurationException
+ * if there are problems with the configuration
+ */
+ Cache<K, V> createCache(Configuration configuration, boolean start) throws ConfigurationException;
+}
Copied: core/trunk/src/main/java/org/jboss/cache/CacheImpl.java (from rev 4250, core/trunk/src-old/org/jboss/cache/CacheImpl.java)
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/CacheImpl.java (rev 0)
+++ core/trunk/src/main/java/org/jboss/cache/CacheImpl.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -0,0 +1,4411 @@
+/*
+ * JBoss, the OpenSource J2EE webOS
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package org.jboss.cache;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.jboss.cache.buddyreplication.BuddyGroup;
+import org.jboss.cache.buddyreplication.BuddyManager;
+import org.jboss.cache.buddyreplication.BuddyNotInitException;
+import org.jboss.cache.buddyreplication.GravitateResult;
+import org.jboss.cache.config.BuddyReplicationConfig;
+import org.jboss.cache.config.Configuration;
+import org.jboss.cache.config.Configuration.NodeLockingScheme;
+import org.jboss.cache.config.Option;
+import org.jboss.cache.config.RuntimeConfig;
+import org.jboss.cache.factories.InterceptorChainFactory;
+import org.jboss.cache.interceptors.Interceptor;
+import org.jboss.cache.loader.CacheLoader;
+import org.jboss.cache.loader.CacheLoaderManager;
+import org.jboss.cache.lock.IsolationLevel;
+import org.jboss.cache.lock.LockStrategyFactory;
+import org.jboss.cache.lock.LockUtil;
+import org.jboss.cache.lock.LockingException;
+import org.jboss.cache.lock.NodeLock;
+import org.jboss.cache.lock.TimeoutException;
+import org.jboss.cache.marshall.InactiveRegionAwareRpcDispatcher;
+import org.jboss.cache.marshall.Marshaller;
+import org.jboss.cache.marshall.MethodCall;
+import org.jboss.cache.marshall.MethodCallFactory;
+import org.jboss.cache.marshall.MethodDeclarations;
+import org.jboss.cache.marshall.NodeData;
+import org.jboss.cache.marshall.VersionAwareMarshaller;
+import org.jboss.cache.notifications.Notifier;
+import org.jboss.cache.notifications.event.NodeModifiedEvent;
+import org.jboss.cache.optimistic.DataVersion;
+import org.jboss.cache.statetransfer.StateTransferManager;
+import org.jboss.cache.transaction.GlobalTransaction;
+import org.jboss.cache.transaction.OptimisticTransactionEntry;
+import org.jboss.cache.transaction.TransactionEntry;
+import org.jboss.cache.transaction.TransactionManagerLookup;
+import org.jboss.cache.transaction.TransactionTable;
+import org.jboss.cache.util.ExposedByteArrayOutputStream;
+import org.jboss.cache.util.ThreadGate;
+import org.jboss.cache.util.concurrent.ConcurrentHashSet;
+import org.jboss.util.stream.MarshalledValueInputStream;
+import org.jboss.util.stream.MarshalledValueOutputStream;
+import org.jgroups.Address;
+import org.jgroups.Channel;
+import org.jgroups.ChannelClosedException;
+import org.jgroups.ChannelException;
+import org.jgroups.ChannelFactory;
+import org.jgroups.ChannelNotConnectedException;
+import org.jgroups.ExtendedMembershipListener;
+import org.jgroups.ExtendedMessageListener;
+import org.jgroups.JChannel;
+import org.jgroups.Message;
+import org.jgroups.View;
+import org.jgroups.blocks.GroupRequest;
+import org.jgroups.blocks.RpcDispatcher;
+import org.jgroups.util.Rsp;
+import org.jgroups.util.RspList;
+import org.jgroups.util.Util;
+
+import javax.transaction.Status;
+import javax.transaction.SystemException;
+import javax.transaction.Transaction;
+import javax.transaction.TransactionManager;
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.io.NotSerializableException;
+import java.io.OutputStream;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.Vector;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * The default implementation class of {@link org.jboss.cache.Cache} and {@link org.jboss.cache.CacheSPI}. This class
+ * has its roots in the legacy (JBoss Cache 1.x.x) org.jboss.cache.TreeCache class.
+ * <p/>
+ * You should not use this class directly, or attempt to cast {@link org.jboss.cache.Cache} or {@link org.jboss.cache.CacheSPI}
+ * interfaces directly to this class.
+ *
+ * @author Bela Ban
+ * @author Ben Wang
+ * @author <a href="mailto:manik at jboss.org">Manik Surtani (manik at jboss.org)</a>
+ * @author Brian Stansberry
+ * @author Daniel Huang (dhuang at jboss.org)
+ * @see org.jboss.cache.Cache
+ */
+public class CacheImpl<K, V> implements CacheSPI<K, V>
+{
+
+ /**
+ * CacheImpl log.
+ */
+ private Log log = LogFactory.getLog(CacheImpl.class);
+
+ /**
+ * Thread gate used to block Dispatcher during JGroups FLUSH protocol
+ */
+ private final ThreadGate flushBlockGate = new ThreadGate();
+
+ /**
+ * Root node.
+ */
+ private NodeSPI<K, V> root;
+
+ /**
+ * Cache's region manager.
+ */
+ private RegionManager regionManager = null;
+
+ /**
+ * The JGroups JChannel in use.
+ */
+ protected Channel channel = null;
+
+ /**
+ * True if this CacheImpl is the coordinator.
+ */
+ private boolean coordinator = false;
+
+ /**
+ * List of cluster group members.
+ */
+ private final Vector<Address> members = new Vector<Address>();
+
+ /**
+ * JGroups RpcDispatcher in use.
+ */
+ private RpcDispatcher disp = null;
+
+ /**
+ * JGroups message listener.
+ */
+ private MessageListenerAdaptor ml = new MessageListenerAdaptor();
+
+ /**
+ * Maintains mapping of transactions (keys) and Modifications/Undo-Operations
+ */
+ private final TransactionTable tx_table = new TransactionTable();
+
+ /**
+ * HashMap<Thread, List<Lock>, maintains locks acquired by threads (used when no TXs are used)
+ */
+ private Map<Thread, List<NodeLock>> lock_table;
+
+ /**
+ * Set<Fqn> of Fqns of the topmost node of internal regions that should
+ * not included in standard state transfers.
+ */
+ private Set<Fqn> internalFqns = new ConcurrentHashSet<Fqn>();
+
+ /**
+ * True if state was initialized during start-up.
+ */
+ private volatile boolean isStateSet = false;
+
+ /**
+ * Class name used to handle evictions.
+ */
+ private String evictionInterceptorClass = "org.jboss.cache.interceptors.EvictionInterceptor";
+
+ /**
+ * Marshaller if register to handle marshalling
+ */
+ private Marshaller marshaller_ = null;
+
+ /**
+ * {@link #invokeMethod(org.jboss.cache.marshall.MethodCall,boolean)} will dispatch to this chain of interceptors.
+ * In the future, this will be replaced with JBossAop. This is a first step towards refactoring JBossCache.
+ */
+ private Interceptor interceptor_chain = null;
+
+ /**
+ * Method to acquire a TransactionManager. By default we use JBossTransactionManagerLookup. Has
+ * to be set before calling {@link #start()}
+ */
+ private TransactionManagerLookup tm_lookup = null;
+
+ /**
+ * Used to get the Transaction associated with the current thread
+ */
+ private TransactionManager tm = null;
+
+ /**
+ * Cache loader manager.
+ */
+ private CacheLoaderManager cacheLoaderManager;
+
+ /**
+ * Queue used to replicate updates when mode is repl-async
+ */
+ private ReplicationQueue repl_queue = null;
+
+ /**
+ * The current lifecycle state.
+ */
+ CacheStatus cacheStatus;
+
+ /**
+ * Buddy Manager
+ */
+ private BuddyManager buddyManager;
+
+ /**
+ * State transfer manager. Do not access this field directly -- use the getter
+ */
+ private StateTransferManager stateTransferManager;
+
+ /**
+ * Cache notifier handler class.
+ */
+ private Notifier notifier;
+
+ private ThreadLocal<InvocationContext> invocationContextContainer = new ThreadLocal<InvocationContext>()
+ {
+ @Override
+ protected InvocationContext initialValue()
+ {
+ return new InvocationContext();
+ }
+ };
+
+ private Configuration configuration;
+
+ /**
+ * Constructs an uninitialized CacheImpl.
+ */
+ protected CacheImpl() throws Exception
+ {
+ configuration = new Configuration(this);
+ notifier = new Notifier(this);
+ regionManager = new RegionManager(this);
+ cacheStatus = CacheStatus.INSTANTIATED;
+ }
+
+ public StateTransferManager getStateTransferManager()
+ {
+ if (stateTransferManager == null)
+ {
+ stateTransferManager = new StateTransferManager(this);
+ }
+ return stateTransferManager;
+ }
+
+ public void setStateTransferManager(StateTransferManager manager)
+ {
+ this.stateTransferManager = manager;
+ }
+
+ public Configuration getConfiguration()
+ {
+ return configuration;
+ }
+
+ /**
+ * Returns the CacheImpl implementation version.
+ */
+ public String getVersion()
+ {
+ return Version.printVersion();
+ }
+
+ /**
+ * Returns the root node.
+ */
+ public NodeSPI<K, V> getRoot()
+ {
+ return root;
+ }
+
+ /**
+ * Returns the local channel address.
+ */
+ public Address getLocalAddress()
+ {
+ return channel != null ? channel.getLocalAddress() : null;
+ }
+
+ /**
+ * Returns the members as a List.
+ * This list may be concurrently modified.
+ */
+ public List<Address> getMembers()
+ {
+ synchronized (members)
+ {
+ return new ArrayList<Address>(members);
+ }
+ }
+
+ /**
+ * Returns <code>true</code> if this node is the group coordinator.
+ */
+ public boolean isCoordinator()
+ {
+ return coordinator;
+ }
+
+ /**
+ * Returns the transaction table.
+ */
+ public TransactionTable getTransactionTable()
+ {
+ return tx_table;
+ }
+
+ /**
+ * Returns the lock table.
+ */
+ public Map<Thread, List<NodeLock>> getLockTable()
+ {
+ if (lock_table == null)
+ {
+ lock_table = new ConcurrentHashMap<Thread, List<NodeLock>>();
+ }
+ return lock_table;
+ }
+
+ /**
+ * Returns the contents of the TransactionTable as a string.
+ */
+ public String dumpTransactionTable()
+ {
+ return tx_table.toString(true);
+ }
+
+ /**
+ * Used for testing only - sets the interceptor chain.
+ */
+ public void setInterceptorChain(Interceptor i)
+ {
+ interceptor_chain = i;
+ }
+
+ /**
+ * @return the list of interceptors.
+ */
+ public List<Interceptor> getInterceptors()
+ {
+ return InterceptorChainFactory.getInstance().asList(interceptor_chain);
+ }
+
+ /**
+ * Returns the underlying cache loader in use.
+ */
+ public CacheLoader getCacheLoader()
+ {
+ if (cacheLoaderManager == null)
+ return null;
+ return cacheLoaderManager.getCacheLoader();
+ }
+
+ public String getEvictionInterceptorClass()
+ {
+ return this.evictionInterceptorClass;
+ }
+
+ private void setUseReplQueue(boolean flag)
+ {
+ if (flag)
+ {
+ if (repl_queue == null)
+ {
+ repl_queue = new ReplicationQueue(this, configuration.getReplQueueInterval(), configuration.getReplQueueMaxElements());
+ if (configuration.getReplQueueInterval() >= 0)
+ {
+ repl_queue.start();
+ }
+ }
+ }
+ else
+ {
+ if (repl_queue != null)
+ {
+ repl_queue.stop();
+ repl_queue = null;
+ }
+ }
+ }
+
+
+ /**
+ * Returns the replication queue.
+ */
+ public ReplicationQueue getReplicationQueue()
+ {
+ return repl_queue;
+ }
+
+ /**
+ * Sets the cache locking isolation level.
+ */
+ private void setIsolationLevel(IsolationLevel level)
+ {
+ LockStrategyFactory.setIsolationLevel(level);
+ }
+
+ /**
+ * Sets the TransactionManagerLookup object
+ */
+ public void setTransactionManagerLookup(TransactionManagerLookup l)
+ {
+ this.tm_lookup = l;
+ }
+
+ /**
+ * Returns the transaction manager in use.
+ */
+ public TransactionManager getTransactionManager()
+ {
+ return tm;
+ }
+
+ /**
+ * Fetches the group state from the current coordinator. If successful, this
+ * will trigger JChannel setState() call.
+ */
+ public void fetchState(long timeout) throws ChannelClosedException, ChannelNotConnectedException
+ {
+ if (channel == null)
+ {
+ throw new ChannelNotConnectedException();
+ }
+ boolean rc = channel.getState(null, timeout);
+ if (rc)
+ {
+ log.debug("fetchState(): state was retrieved successfully");
+ }
+ else
+ {
+ log.debug("fetchState(): state could not be retrieved (first member)");
+ }
+ }
+
+ void fetchPartialState(List<Address> sources, Fqn sourceTarget, Fqn integrationTarget) throws Exception
+ {
+ String encodedStateId = sourceTarget + StateTransferManager.PARTIAL_STATE_DELIMITER + integrationTarget;
+ fetchPartialState(sources, encodedStateId);
+ }
+
+ void fetchPartialState(List<Address> sources, Fqn subtree) throws Exception
+ {
+ if (subtree == null)
+ {
+ throw new IllegalArgumentException("Cannot fetch partial state. Null subtree.");
+ }
+ fetchPartialState(sources, subtree.toString());
+ }
+
+ private void fetchPartialState(List<Address> sources, String stateId) throws Exception
+ {
+ if (sources == null || sources.isEmpty() || stateId == null)
+ {
+ // should this really be throwing an exception? Are there valid use cases where partial state may not be available? - Manik
+ // Yes -- cache is configured LOCAL but app doesn't know it -- Brian
+ //throw new IllegalArgumentException("Cannot fetch partial state, targets are " + sources + " and stateId is " + stateId);
+ if (log.isWarnEnabled())
+ {
+ log.warn("Cannot fetch partial state, targets are " + sources +
+ " and stateId is " + stateId);
+ }
+ return;
+ }
+
+ List<Address> targets = new LinkedList<Address>(sources);
+
+ //skip *this* node as a target
+ targets.remove(getLocalAddress());
+
+ if (targets.isEmpty())
+ {
+ // Definitely no exception here -- this happens every time the 1st node in the
+ // cluster activates a region!! -- Brian
+ log.debug("Cannot fetch partial state. There are no target members specified");
+ return;
+ }
+
+ log.debug("Node " + getLocalAddress() + " fetching partial state " + stateId + " from members " + targets);
+ boolean successfulTransfer = false;
+ for (Address target : targets)
+ {
+ log.debug("Node " + getLocalAddress() + " fetching partial state " + stateId + " from member " + target);
+ isStateSet = false;
+ successfulTransfer = channel.getState(target, stateId, configuration.getStateRetrievalTimeout());
+ if (successfulTransfer)
+ {
+ try
+ {
+ ml.waitForState();
+ }
+ catch (Exception transferFailed)
+ {
+ successfulTransfer = false;
+ }
+ }
+ log.debug("Node " + getLocalAddress() + " fetching partial state " + stateId + " from member " + target + (successfulTransfer ? " successful" : " failed"));
+ if (successfulTransfer)
+ break;
+ }
+
+ if (!successfulTransfer)
+ {
+ log.debug("Node " + getLocalAddress() + " could not fetch partial state " + stateId + " from any member " + targets);
+ }
+ }
+
+ /**
+ * Lifecycle method. This is like initialize.
+ *
+ * @throws Exception
+ */
+ public void create() throws CacheException
+ {
+ if (!cacheStatus.createAllowed())
+ {
+ if (cacheStatus.needToDestroyFailedCache())
+ destroy();
+ else
+ return;
+ }
+
+ try
+ {
+ internalCreate();
+ }
+ catch (Throwable t)
+ {
+ handleLifecycleTransitionFailure(t);
+ }
+ }
+
+ /**
+ * Sets the cacheStatus to FAILED and rethrows the problem as one
+ * of the declared types. Converts any non-RuntimeException Exception
+ * to CacheException.
+ *
+ * @param t
+ * @throws CacheException
+ * @throws RuntimeException
+ * @throws Error
+ */
+ private void handleLifecycleTransitionFailure(Throwable t)
+ throws CacheException, RuntimeException, Error
+ {
+ cacheStatus = CacheStatus.FAILED;
+ if (t instanceof CacheException)
+ throw (CacheException) t;
+ else if (t instanceof RuntimeException)
+ throw (RuntimeException) t;
+ else if (t instanceof Error)
+ throw (Error) t;
+ else
+ throw new CacheException(t);
+ }
+
+ /**
+ * The actual create implementation.
+ *
+ * @throws CacheException
+ */
+ private void internalCreate() throws CacheException
+ {
+ // Include our clusterName in our log category
+ configureLogCategory();
+
+ // initialise the node factory and set this in the runtime.
+ NodeFactory<K, V> nf;
+ if ((nf = configuration.getRuntimeConfig().getNodeFactory()) == null)
+ {
+ nf = new NodeFactory<K, V>(this);
+ configuration.getRuntimeConfig().setNodeFactory(nf);
+ }
+ else
+ {
+ // don't create a new one each and every time. After stopping and starting the cache, the old NodeFactory may still be valid.
+ nf.init();
+ }
+
+ if (notifier == null)
+ notifier = new Notifier(this);
+
+ // create a new root temporarily.
+ NodeSPI<K, V> tempRoot = nf.createRootDataNode();
+ // if we don't already have a root or the new (temp) root is of a different class (optimistic vs pessimistic) to
+ // the current root, then we use the new one. Helps preserve data between cache restarts.
+ if (root == null || !root.getClass().equals(tempRoot.getClass()))
+ root = tempRoot;
+
+ if (configuration.getCacheLoaderConfig() != null && cacheLoaderManager == null)
+ {
+ initialiseCacheLoaderManager();
+ }
+ // first set up the Buddy Manager and an RPCManager
+ if (configuration.getCacheMode() != Configuration.CacheMode.LOCAL)
+ {
+ getConfiguration().getRuntimeConfig().setRPCManager(new RPCManagerImpl(this));
+ setBuddyReplicationConfig(configuration.getBuddyReplicationConfig());
+ }
+ // build interceptor chain
+ try
+ {
+ interceptor_chain = InterceptorChainFactory.getInstance().buildInterceptorChain(this);
+ }
+ catch (Exception e)
+ {
+ throw new CacheException("Unable to build interceptor chain", e);
+ }
+
+
+ setUseReplQueue(configuration.isUseReplQueue());
+ setIsolationLevel(configuration.getIsolationLevel());
+
+ getRegionManager();// make sure we create one
+ createEvictionPolicy();
+
+ getRegionManager().setDefaultInactive(configuration.isInactiveOnStartup());
+
+ cacheStatus = CacheStatus.CREATED;
+ }
+
+ private void createTransactionManager()
+ {
+ // See if we had a TransactionManager injected into our config
+ this.tm = configuration.getRuntimeConfig().getTransactionManager();
+ if (tm == null)
+ {
+ // Nope. See if we can look it up from JNDI
+ if (this.tm_lookup == null && configuration.getTransactionManagerLookupClass() != null)
+ {
+ try
+ {
+ Class clazz = Thread.currentThread().getContextClassLoader().loadClass(configuration.getTransactionManagerLookupClass());
+ this.tm_lookup = (TransactionManagerLookup) clazz.newInstance();
+ }
+ catch (Exception e)
+ {
+ throw new CacheException("Problems creating the cache", e);
+ }
+ }
+
+ try
+ {
+ if (tm_lookup != null)
+ {
+ tm = tm_lookup.getTransactionManager();
+ configuration.getRuntimeConfig().setTransactionManager(tm);
+ }
+ else
+ {
+ if (configuration.getNodeLockingScheme() == NodeLockingScheme.OPTIMISTIC)
+ {
+ log.fatal("No transaction manager lookup class has been defined. Transactions cannot be used and thus OPTIMISTIC locking cannot be used");
+ }
+ else
+ {
+ log.info("No transaction manager lookup class has been defined. Transactions cannot be used");
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ log.debug("failed looking up TransactionManager, will not use transactions", e);
+ }
+ }
+ }
+
+ protected boolean shouldFetchStateOnStartup()
+ {
+ boolean loaderFetch = cacheLoaderManager != null && cacheLoaderManager.isFetchPersistentState();
+ return !configuration.isInactiveOnStartup() && buddyManager == null && (configuration.isFetchInMemoryState() || loaderFetch);
+ }
+
+ /**
+ * Lifecyle method.
+ *
+ * @throws CacheException
+ */
+ public void start() throws CacheException
+ {
+ if (!cacheStatus.startAllowed())
+ {
+ if (cacheStatus.needToDestroyFailedCache())
+ destroy(); // this will take us back to DESTROYED
+
+ if (cacheStatus.needCreateBeforeStart())
+ create();
+ else
+ return;
+ }
+
+ try
+ {
+ internalStart();
+ }
+ catch (Throwable t)
+ {
+ handleLifecycleTransitionFailure(t);
+ }
+ }
+
+ /**
+ * The actual start implementation.
+ *
+ * @throws CacheException
+ * @throws IllegalArgumentException
+ */
+ private void internalStart() throws CacheException, IllegalArgumentException
+ {
+ cacheStatus = CacheStatus.STARTING;
+
+ createTransactionManager();
+
+ // cache loaders should be initialised *before* any state transfers take place to prevent
+ // exceptions involving cache loaders not being started. - Manik
+ // create cache loader
+ if (cacheLoaderManager != null)
+ {
+ cacheLoaderManager.startCacheLoader();
+ }
+ // now that we have a TM we can init the interceptor chain
+ InterceptorChainFactory.getInstance().initialiseInterceptors(interceptor_chain, this);
+
+ switch (configuration.getCacheMode())
+ {
+ case LOCAL:
+ log.debug("cache mode is local, will not create the channel");
+ break;
+ case REPL_SYNC:
+ case REPL_ASYNC:
+ case INVALIDATION_ASYNC:
+ case INVALIDATION_SYNC:
+ if (log.isDebugEnabled()) log.debug("cache mode is " + configuration.getCacheMode());
+ initialiseChannelAndRpcDispatcher();
+
+ try
+ {
+ channel.connect(configuration.getClusterName());
+ }
+ catch (ChannelException e)
+ {
+ throw new CacheException("Unable to connect to JGroups channel", e);
+ }
+
+ if (log.isInfoEnabled())
+ {
+ log.info("CacheImpl local address is " + channel.getLocalAddress());
+ }
+ if (shouldFetchStateOnStartup())
+ {
+ try
+ {
+ fetchStateOnStartup();
+ }
+ catch (Exception e)
+ {
+ // make sure we disconnect from the channel before we throw this exception!
+ // JBCACHE-761
+ channel.disconnect();
+ channel.close();
+ throw new CacheException("Unable to fetch state on startup", e);
+ }
+ }
+ if (buddyManager != null)
+ {
+ buddyManager.init(this);
+ if (configuration.isUseReplQueue())
+ {
+ log.warn("Replication queue not supported when using buddy replication. Disabling repliction queue.");
+ configuration.setUseReplQueue(false);
+ repl_queue = null;
+ }
+ }
+ break;
+ default:
+ throw new IllegalArgumentException("cache mode " + configuration.getCacheMode() + " is invalid");
+ }
+
+ //now attempt to preload the cache from the loader - Manik
+ if (cacheLoaderManager != null)
+ {
+ cacheLoaderManager.preloadCache();
+ }
+
+ // Find out if we are coordinator (blocks until view is received)
+ determineCoordinator();
+
+ // start any eviction threads.
+ if (regionManager.isUsingEvictions())
+ {
+ regionManager.startEvictionThread();
+ }
+
+ notifier.notifyCacheStarted(this, getInvocationContext());
+
+ // install a VM shutdown hook
+ Thread shutdownHook = new Thread()
+ {
+ public void run()
+ {
+ CacheImpl.this.stop();
+ }
+ };
+
+ Runtime.getRuntime().addShutdownHook(shutdownHook);
+
+ log.info("JBoss Cache version: " + getVersion());
+
+ cacheStatus = CacheStatus.STARTED;
+ }
+
+ /**
+ * Lifecycle method.
+ */
+ public void destroy()
+ {
+ if (!cacheStatus.destroyAllowed())
+ {
+ if (cacheStatus.needStopBeforeDestroy())
+ {
+ try
+ {
+ stop();
+ }
+ catch (CacheException e)
+ {
+ log.warn("Needed to call stop() before destroying but stop() " +
+ "threw exception. Proceeding to destroy", e);
+ }
+ }
+ else
+ return;
+ }
+
+ try
+ {
+ internalDestroy();
+ }
+ finally
+ {
+ // We always progress to destroyed
+ cacheStatus = CacheStatus.DESTROYED;
+ }
+ }
+
+ /**
+ * The actual destroy implementation.
+ */
+ private void internalDestroy()
+ {
+ cacheStatus = CacheStatus.DESTROYING;
+ regionManager = null;
+ notifier = null;
+
+ // The rest of these should have already been taken care of in stop,
+ // but we do it here as well in case stop failed.
+
+ if (channel != null)
+ {
+ if (channel.isOpen())
+ {
+ try
+ {
+ channel.close();
+ channel.disconnect();
+ }
+ catch (Exception toLog)
+ {
+ log.error("Problem closing channel; setting it to null", toLog);
+ }
+ }
+ channel = null;
+ configuration.getRuntimeConfig().setChannel(null);
+ }
+ disp = null;
+ tm = null;
+ }
+
+ /**
+ * Lifecycle method.
+ */
+ public void stop()
+ {
+ if (!cacheStatus.stopAllowed())
+ {
+ return;
+ }
+
+ // Trying to stop() from FAILED is valid, but may not work
+ boolean failed = cacheStatus == CacheStatus.FAILED;
+
+ try
+ {
+ internalStop();
+ }
+ catch (Throwable t)
+ {
+ if (failed)
+ {
+ log.warn("Attempted to stop() from FAILED state, " +
+ "but caught exception; try calling destroy()", t);
+ }
+ handleLifecycleTransitionFailure(t);
+ }
+ }
+
+ /**
+ * The actual stop implementation.
+ */
+ private void internalStop()
+ {
+ cacheStatus = CacheStatus.STOPPING;
+
+ // before closing the channel stop the buddy manager
+ if (buddyManager != null && buddyManager.isEnabled())
+ {
+ log.debug("stop(): stopping buddy manager");
+ buddyManager.stop();
+ }
+
+ if (channel != null)
+ {
+ log.info("stop(): closing the channel");
+ killChannel();
+ channel = null;
+ configuration.getRuntimeConfig().setChannel(null);
+ }
+
+ if (disp != null)
+ {
+ log.info("stop(): stopping the dispatcher");
+ disp.stop();
+ disp = null;
+ }
+ if (members != null)
+ {
+ synchronized (members)
+ {
+ members.clear();
+ }
+ }
+
+ coordinator = false;
+
+ if (repl_queue != null)
+ {
+ repl_queue.stop();
+ }
+
+ if (cacheLoaderManager != null)
+ {
+ log.debug("stop(): stopping cache loader manager");
+ cacheLoaderManager.stopCacheLoader();
+ }
+
+ if (regionManager.isUsingEvictions()) regionManager.stopEvictionThread();
+
+ if (notifier != null)
+ {
+ notifier.notifyCacheStopped(this, getInvocationContext());
+ notifier.removeAllCacheListeners();
+ }
+
+ // unset transaction manager reference
+ tm = null;
+
+ cacheStatus = CacheStatus.STOPPED;
+
+ // empty in-memory state
+ root.clearDataDirect();
+ root.removeChildrenDirect();
+ }
+
+ public CacheStatus getCacheStatus()
+ {
+ return cacheStatus;
+ }
+
+ /* ----------------------- End of MBeanSupport ----------------------- */
+
+ /* ----------------------- Start of buddy replication specific methods ------------*/
+
+ /**
+ * Sets the buddy replication configuration element
+ *
+ * @param config
+ */
+ private void setBuddyReplicationConfig(BuddyReplicationConfig config)
+ {
+ if (config != null)
+ {
+ buddyManager = new BuddyManager(config);
+ if (!buddyManager.isEnabled())
+ {
+ buddyManager = null;
+ }
+ else
+ {
+ internalFqns.add(BuddyManager.BUDDY_BACKUP_SUBTREE_FQN);
+ }
+ }
+ }
+
+ /**
+ * Retrieves the Buddy Manager configured.
+ *
+ * @return null if buddy replication is not enabled.
+ */
+ public BuddyManager getBuddyManager()
+ {
+ return buddyManager;
+ }
+
+ /**
+ * Returns a Set<Fqn> of Fqns of the topmost node of internal regions that
+ * should not included in standard state transfers. Will include
+ * {@link BuddyManager#BUDDY_BACKUP_SUBTREE} if buddy replication is
+ * enabled.
+ *
+ * @return an unmodifiable Set<Fqn>. Will not return <code>null</code>.
+ */
+ public Set<Fqn> getInternalFqns()
+ {
+ return Collections.unmodifiableSet(internalFqns);
+ }
+
+ /* ----------------------- End of buddy replication specific methods ------------*/
+
+ protected void createEvictionPolicy()
+ {
+ if (configuration.getEvictionConfig() != null
+ && configuration.getEvictionConfig().isValidConfig())
+ {
+ regionManager.setEvictionConfig(configuration.getEvictionConfig());
+ regionManager.setUsingEvictions(true);
+ }
+ else
+ {
+ regionManager.setUsingEvictions(false);
+ log.debug("Not using an EvictionPolicy");
+ }
+ }
+
+ /**
+ * Loads the indicated Fqn, plus all parents recursively from the
+ * CacheLoader. If no CacheLoader is present, this is a no-op
+ *
+ * @param fqn
+ * @throws Exception
+ */
+ public void load(String fqn) throws Exception
+ {
+ if (cacheLoaderManager != null)
+ {
+ cacheLoaderManager.preload(Fqn.fromString(fqn), true, true);
+ }
+ }
+
+ private void determineCoordinator()
+ {
+ // Synchronize on members to make the answer atomic for the current view
+ synchronized (members)
+ {
+ Address coord = getCoordinator();
+ coordinator = (coord == null ? false : coord.equals(getLocalAddress()));
+ }
+ }
+
+ /**
+ * Returns the address of the coordinator or null if there is no
+ * coordinator.
+ * Waits until the membership view is updated.
+ */
+ public Address getCoordinator()
+ {
+ if (channel == null)
+ {
+ return null;
+ }
+
+ synchronized (members)
+ {
+ while (members.isEmpty())
+ {
+ log.debug("getCoordinator(): waiting on viewAccepted()");
+ try
+ {
+ members.wait();
+ }
+ catch (InterruptedException e)
+ {
+ log.error("getCoordinator(): Interrupted while waiting for members to be set", e);
+ break;
+ }
+ }
+ return members.size() > 0 ? members.get(0) : null;
+ }
+ }
+
+ // ----------- Marshalling and State Transfer -----------------------
+
+ /**
+ * Creates a subtree in the local cache.
+ * Returns the DataNode created.
+ */
+ protected Node createSubtreeRootNode(Fqn<?> subtree) throws CacheException
+ {
+ NodeSPI<K, V> parent = root;
+ NodeSPI<K, V> child = null;
+ Object owner = getOwnerForLock();
+ Object name;
+ NodeFactory<K, V> factory = configuration.getRuntimeConfig().getNodeFactory();
+
+ for (int i = 0; i < subtree.size(); i++)
+ {
+ name = subtree.get(i);
+ child = parent.getChildDirect(name);
+ if (child == null)
+ {
+ // Lock the parent, create and add the child
+ try
+ {
+ parent.getLock().acquire(owner, configuration.getSyncReplTimeout(), NodeLock.LockType.WRITE);
+ }
+ catch (InterruptedException e)
+ {
+ log.error("Interrupted while locking" + parent.getFqn(), e);
+ throw new CacheException(e.getLocalizedMessage(), e);
+ }
+
+ try
+ {
+ child = factory.createDataNode(name,
+ subtree.getAncestor(i + 1),
+ parent, null, true);
+ parent.addChild(name, child);
+ }
+ finally
+ {
+ if (log.isDebugEnabled())
+ {
+ log.debug("forcing release of locks in " + parent.getFqn());
+ }
+ try
+ {
+ parent.getLock().releaseAll();
+ }
+ catch (Throwable t)
+ {
+ log.error("failed releasing locks", t);
+ }
+ }
+ }
+
+ parent = child;
+ }
+
+ return child;
+ }
+
+ /**
+ * Evicts the node at <code>subtree</code> along with all descendant nodes.
+ *
+ * @param subtree Fqn indicating the uppermost node in the
+ * portion of the cache that should be evicted.
+ * @throws CacheException
+ */
+ protected void _evictSubtree(Fqn subtree) throws CacheException
+ {
+
+ if (!exists(subtree))
+ {
+ return;// node does not exist. Maybe it has been recursively removed.
+ }
+
+ if (log.isTraceEnabled())
+ {
+ log.trace("_evictSubtree(" + subtree + ")");
+ }
+
+ // Recursively remove any children
+ Set children = getChildrenNames(subtree);
+ if (children != null)
+ {
+ for (Object s : children)
+ {
+
+ Fqn<Object> tmp = new Fqn<Object>(subtree, s);
+ _remove(null, // no tx
+ tmp,
+ false, // no undo ops
+ false, // no nodeEvent
+ true);// is an eviction
+ }
+ }
+
+ // Remove the root node of the subtree
+ _remove(null, subtree, false, false, true);
+
+ }
+
+ private void removeLocksForDeadMembers(NodeSPI<K, V> node, List deadMembers)
+ {
+ Set<GlobalTransaction> deadOwners = new HashSet<GlobalTransaction>();
+ NodeLock lock = node.getLock();
+ Object owner = lock.getWriterOwner();
+
+ if (isLockOwnerDead(owner, deadMembers))
+ {
+ deadOwners.add((GlobalTransaction) owner);
+ }
+
+ for (Object readOwner : lock.getReaderOwners())
+ {
+ if (isLockOwnerDead(readOwner, deadMembers))
+ {
+ deadOwners.add((GlobalTransaction) readOwner);
+ }
+ }
+
+ for (GlobalTransaction deadOwner : deadOwners)
+ {
+ boolean localTx = deadOwner.getAddress().equals(getLocalAddress());
+ boolean broken = LockUtil.breakTransactionLock(lock, deadOwner, localTx, this);
+
+ if (broken && log.isTraceEnabled())
+ {
+ log.trace("Broke lock for node " + node.getFqn() +
+ " held by " + deadOwner);
+ }
+ }
+
+ // Recursively unlock children
+ for (NodeSPI<K, V> child : node.getChildrenDirect())
+ {
+ removeLocksForDeadMembers(child, deadMembers);
+ }
+ }
+
+ private boolean isLockOwnerDead(Object owner, List deadMembers)
+ {
+ boolean result = false;
+ if (owner != null && owner instanceof GlobalTransaction)
+ {
+ Object addr = ((GlobalTransaction) owner).getAddress();
+ result = deadMembers.contains(addr);
+ }
+ return result;
+ }
+
+ protected void fetchStateOnStartup() throws Exception
+ {
+ long start, stop;
+ isStateSet = false;
+ start = System.currentTimeMillis();
+ boolean rc = channel.getState(null, configuration.getStateRetrievalTimeout());
+ if (rc)
+ {
+ ml.waitForState();
+ stop = System.currentTimeMillis();
+ if (log.isDebugEnabled())
+ {
+ log.debug("state was retrieved successfully (in " + (stop - start) + " milliseconds)");
+ }
+ }
+ else
+ {
+ // No one provided us with state. We need to find out if that's because
+ // we are the coordinator. But we don't know if the viewAccepted() callback
+ // has been invoked, so call determineCoordinator(), which will block until
+ // viewAccepted() is called at least once
+ determineCoordinator();
+
+ if (isCoordinator())
+ {
+ log.debug("State could not be retrieved (we are the first member in group)");
+ }
+ else
+ {
+ throw new CacheException("Initial state transfer failed: " +
+ "Channel.getState() returned false");
+ }
+ }
+ }
+
+ // ----------- End Marshalling and State Transfer -----------------------
+
+ /**
+ * @param fqn fqn String name to retrieve from cache
+ * @return DataNode corresponding to the fqn. Null if does not exist. No guarantees wrt replication,
+ * cache loading are given if the underlying node is modified
+ */
+ public Node get(String fqn) throws CacheException
+ {
+ return get(Fqn.fromString(fqn));
+ }
+
+ /**
+ * Returns a DataNode corresponding to the fully qualified name or null if
+ * does not exist.
+ * No guarantees wrt replication, cache loading are given if the underlying node is modified
+ *
+ * @param fqn name of the DataNode to retreive
+ */
+ public Node<K, V> get(Fqn<?> fqn) throws CacheException
+ {
+ MethodCall m = MethodCallFactory.create(MethodDeclarations.getNodeMethodLocal, fqn);
+ return (Node<K, V>) invokeMethod(m, true);
+ }
+
+ /**
+ * Returns the raw data of the node; called externally internally.
+ */
+ public Node<K, V> _get(Fqn<?> fqn) throws CacheException
+ {
+ return findNode(fqn);
+ }
+
+ /**
+ * Returns the raw data of the node; called externally internally.
+ */
+ public Map _getData(Fqn<?> fqn)
+ {
+ NodeSPI n = findNode(fqn);
+ if (n == null) return null;
+ return n.getDataDirect();
+ }
+
+ /**
+ * Returns a set of attribute keys for the Fqn.
+ * Returns null if the node is not found, otherwise a Set.
+ * The set is a copy of the actual keys for this node.
+ *
+ * @param fqn name of the node
+ */
+ public Set getKeys(String fqn) throws CacheException
+ {
+ return getKeys(Fqn.fromString(fqn));
+ }
+
+ /**
+ * Returns a set of attribute keys for the Fqn.
+ * Returns null if the node is not found, otherwise a Set.
+ * The set is a copy of the actual keys for this node.
+ *
+ * @param fqn name of the node
+ */
+ public Set<K> getKeys(Fqn<?> fqn) throws CacheException
+ {
+ MethodCall m = MethodCallFactory.create(MethodDeclarations.getKeysMethodLocal, fqn);
+ return (Set<K>) invokeMethod(m, true);
+ }
+
+
+ /**
+ * Retrieves a defensively copied data map of the underlying node.
+ *
+ * @param fqn
+ * @return map of data, or an empty map
+ * @throws CacheException
+ */
+ public Map<K, V> getData(Fqn<?> fqn) throws CacheException
+ {
+ MethodCall m = MethodCallFactory.create(MethodDeclarations.getDataMapMethodLocal, fqn);
+ return (Map<K, V>) invokeMethod(m, true);
+ }
+
+ public Set _getKeys(Fqn<?> fqn) throws CacheException
+ {
+ NodeSPI<K, V> n = findNode(fqn);
+ if (n == null)
+ {
+ return null;
+ }
+ Set<K> keys = n.getKeysDirect();
+ return new HashSet<K>(keys);
+ }
+
+ /**
+ * Finds a node given its name and returns the value associated with a given key in its <code>data</code>
+ * map. Returns null if the node was not found in the cache or the key was not found in the hashmap.
+ *
+ * @param fqn The fully qualified name of the node.
+ * @param key The key.
+ */
+ public V get(String fqn, K key) throws CacheException
+ {
+ return get(Fqn.fromString(fqn), key);
+ }
+
+
+ /**
+ * Finds a node given its name and returns the value associated with a given key in its <code>data</code>
+ * map. Returns null if the node was not found in the cache or the key was not found in the hashmap.
+ *
+ * @param fqn The fully qualified name of the node.
+ * @param key The key.
+ */
+ public V get(Fqn<?> fqn, K key) throws CacheException
+ {
+ return get(fqn, key, true);
+ }
+
+ public V _get(Fqn<?> fqn, K key, boolean sendNodeEvent) throws CacheException
+ {
+ InvocationContext ctx = getInvocationContext();
+ if (log.isTraceEnabled())
+ {
+ log.trace(new StringBuffer("_get(").append("\"").append(fqn).append("\", \"").append(key).append("\", \"").
+ append(sendNodeEvent).append("\")"));
+ }
+ if (sendNodeEvent) notifier.notifyNodeVisited(fqn, true, ctx);
+ NodeSPI<K, V> n = findNode(fqn);
+ if (n == null)
+ {
+ log.trace("node not found");
+ return null;
+ }
+ if (sendNodeEvent) notifier.notifyNodeVisited(fqn, false, ctx);
+ return n.getDirect(key);
+ }
+
+
+ protected V get(Fqn<?> fqn, K key, boolean sendNodeEvent) throws CacheException
+ {
+ MethodCall m = MethodCallFactory.create(MethodDeclarations.getKeyValueMethodLocal, fqn, key, sendNodeEvent);
+ return (V) invokeMethod(m, true);
+ }
+
+ /**
+ * Checks whether a given node exists in current in-memory state of the cache.
+ * Does not acquire any locks in doing so (result may be dirty read). Does
+ * not attempt to load nodes from a cache loader (may return false if a
+ * node has been evicted).
+ *
+ * @param fqn The fully qualified name of the node
+ * @return boolean Whether or not the node exists
+ */
+ public boolean exists(String fqn)
+ {
+ return exists(Fqn.fromString(fqn));
+ }
+
+
+ /**
+ * Checks whether a given node exists in current in-memory state of the cache.
+ * Does not acquire any locks in doing so (result may be dirty read). Does
+ * not attempt to load nodes from a cache loader (may return false if a
+ * node has been evicted).
+ *
+ * @param fqn The fully qualified name of the node
+ * @return boolean Whether or not the node exists
+ */
+ public boolean exists(Fqn<?> fqn)
+ {
+ Node n = peek(fqn, false);
+ return n != null;
+ }
+
+ /**
+ * Gets node without attempt to load it from CacheLoader if not present
+ *
+ * @param fqn
+ */
+ public NodeSPI<K, V> peek(Fqn<?> fqn, boolean includeDeletedNodes)
+ {
+ if (fqn == null || fqn.size() == 0) return root;
+ NodeSPI<K, V> n = root;
+ int fqnSize = fqn.size();
+ for (int i = 0; i < fqnSize; i++)
+ {
+ Object obj = fqn.get(i);
+ n = n.getChildDirect(obj);
+ if (n == null)
+ {
+ return null;
+ }
+ else if (!includeDeletedNodes && n.isDeleted())
+ {
+ return null;
+ }
+ }
+ return n;
+ }
+
+
+ /**
+ * @param fqn
+ * @param key
+ */
+ public boolean exists(String fqn, Object key)
+ {
+ return exists(Fqn.fromString(fqn), key);
+ }
+
+
+ /**
+ * Checks whether a given key exists in the given node. Does not interact with CacheLoader, so the behavior is
+ * different from {@link #get(Fqn,Object)}
+ *
+ * @param fqn The fully qualified name of the node
+ * @param key
+ * @return boolean Whether or not the node exists
+ */
+ public boolean exists(Fqn<?> fqn, Object key)
+ {
+ NodeSPI n = peek(fqn, false);
+ return n != null && n.getKeysDirect().contains(key);
+ }
+
+
+ /**
+ * Adds a new node to the cache and sets its data. If the node doesn not yet exist, it will be created.
+ * Also, parent nodes will be created if not existent. If the node already has data, then the new data
+ * will override the old one. If the node already existed, a nodeModified() notification will be generated.
+ * Otherwise a nodeCreated() motification will be emitted.
+ *
+ * @param fqn The fully qualified name of the new node
+ * @param data The new data. May be null if no data should be set in the node.
+ */
+ public void put(String fqn, Map data) throws CacheException
+ {
+ put(Fqn.fromString(fqn), data);
+ }
+
+ /**
+ * Sets a node's data. If the node does not yet exist, it will be created.
+ * Also, parent nodes will be created if not existent. If the node already has data, then the new data
+ * will override the old one. If the node already existed, a nodeModified() notification will be generated.
+ * Otherwise a nodeCreated() motification will be emitted.
+ *
+ * @param fqn The fully qualified name of the new node
+ * @param data The new data. May be null if no data should be set in the node.
+ */
+ public void put(Fqn<?> fqn, Map<K, V> data) throws CacheException
+ {
+ put(fqn, data, false);
+ }
+
+ public void put(Fqn<?> fqn, Map<K, V> data, boolean erase) throws CacheException
+ {
+ GlobalTransaction tx = getCurrentTransaction();
+ MethodCall m;
+ if (erase)
+ {
+ m = MethodCallFactory.create(MethodDeclarations.putDataEraseMethodLocal, tx, fqn, data, true, true);
+ }
+ else
+ {
+ m = MethodCallFactory.create(MethodDeclarations.putDataMethodLocal, tx, fqn, data, true);
+ }
+ invokeMethod(m, true);
+ }
+
+ /**
+ * Adds a key and value to a given node. If the node doesn't exist, it will be created. If the node
+ * already existed, a nodeModified() notification will be generated. Otherwise a
+ * nodeCreated() motification will be emitted.
+ *
+ * @param fqn The fully qualified name of the node
+ * @param key The key
+ * @param value The value
+ * @return Object The previous value (if any), if node was present
+ */
+ public V put(String fqn, K key, V value) throws CacheException
+ {
+ return put(Fqn.fromString(fqn), key, value);
+ }
+
+ /**
+ * Adds a key and value to a given node. If the node doesn't exist, it will be created. If the node
+ * already existed, a nodeModified() notification will be generated. Otherwise a
+ * nodeCreated() motification will be emitted.
+ *
+ * @param fqn The fully qualified name of the node
+ * @param key The key
+ * @param value The value
+ * @return Object The previous value (if any), if node was present
+ */
+ public V put(Fqn<?> fqn, K key, V value) throws CacheException
+ {
+ GlobalTransaction tx = getCurrentTransaction();
+ MethodCall m = MethodCallFactory.create(MethodDeclarations.putKeyValMethodLocal, tx, fqn, key, value, true);
+ return (V) invokeMethod(m, true);
+ }
+
+ /**
+ * Removes the node from the cache.
+ *
+ * @param fqn The fully qualified name of the node.
+ */
+ public void remove(String fqn) throws CacheException
+ {
+ remove(Fqn.fromString(fqn));
+ }
+
+ /**
+ * Removes the node from the cache.
+ *
+ * @param fqn The fully qualified name of the node.
+ */
+ public boolean remove(Fqn fqn) throws CacheException
+ {
+ GlobalTransaction tx = getCurrentTransaction();
+ // special case if we are removing the root. Remove all children instead.
+ if (fqn.isRoot())
+ {
+ boolean result = true;
+ // we need to preserve options
+ InvocationContext ctx = getInvocationContext();
+ Option o = ctx.getOptionOverrides();
+ for (Object childName : _getChildrenNames(fqn))
+ {
+ ctx.setOptionOverrides(o);
+ result = remove(new Fqn<Object>(fqn, childName)) && result;
+ }
+
+ return result;
+ }
+ else
+ {
+ MethodCall m = MethodCallFactory.create(MethodDeclarations.removeNodeMethodLocal, tx, fqn, true);
+ Object retval = invokeMethod(m, true);
+ return retval != null && (Boolean) retval;
+ }
+ }
+
+ /**
+ * Called by eviction policy provider. Note that eviction is done only in
+ * local mode, that is, it doesn't replicate the node removal. This will
+ * cause the replication nodes to not be synchronizing, which is fine since
+ * the value will be fetched again when {@link #get} returns null. After
+ * that, the contents will be in sync.
+ *
+ * @param fqn Will remove everythign assoicated with this fqn.
+ * @throws CacheException
+ */
+ public void evict(Fqn fqn) throws CacheException
+ {
+ if (fqn.isRoot())
+ {
+ // special treatment for root eviction
+ // we need to preserve options
+ InvocationContext ctx = getInvocationContext();
+ Option o = ctx.getOptionOverrides();
+ for (Object childName : _getChildrenNames(fqn))
+ {
+ ctx.setOptionOverrides(o);
+ evict(new Fqn<Object>(fqn, childName));
+ }
+ }
+ else
+ {
+ MethodCall m = MethodCallFactory.create(MethodDeclarations.evictNodeMethodLocal, fqn);
+ invokeMethod(m, true);
+ }
+ }
+
+ /**
+ * Removes <code>key</code> from the node's hashmap
+ *
+ * @param fqn The fullly qualified name of the node
+ * @param key The key to be removed
+ * @return The previous value, or null if none was associated with the given key
+ */
+ public V remove(String fqn, K key) throws CacheException
+ {
+ return remove(Fqn.fromString(fqn), key);
+ }
+
+ /**
+ * Removes <code>key</code> from the node's hashmap
+ *
+ * @param fqn The fullly qualified name of the node
+ * @param key The key to be removed
+ * @return The previous value, or null if none was associated with the given key
+ */
+ public V remove(Fqn<?> fqn, K key) throws CacheException
+ {
+ GlobalTransaction tx = getCurrentTransaction();
+ MethodCall m = MethodCallFactory.create(MethodDeclarations.removeKeyMethodLocal, tx, fqn, key, true);
+ return (V) invokeMethod(m, true);
+ }
+
+ /**
+ * Removes the keys and properties from a node.
+ */
+ public void removeData(String fqn) throws CacheException
+ {
+ removeData(Fqn.fromString(fqn));
+ }
+
+ /**
+ * Removes the keys and properties from a named node.
+ */
+ public void removeData(Fqn fqn) throws CacheException
+ {
+ GlobalTransaction tx = getCurrentTransaction();
+ MethodCall m = MethodCallFactory.create(MethodDeclarations.removeDataMethodLocal, tx, fqn, true);
+ invokeMethod(m, true);
+ }
+
+ /**
+ * Lock a given node (or the entire subtree starting at this node)
+ * @param fqn The FQN of the node
+ * @param owner The owner. This is simply a key into a hashtable, and can be anything, e.g.
+ * a GlobalTransaction, the current thread, or a special object. If null, it is set to Thread.currentThread()
+ * @param lock_type The type of lock (RO, RW). Needs to be of type DataNode.LOCK_TYPE_READ or DataNode.LOCK_TYPE_WRITE
+ * @param lock_recursive If true, the entire subtree is locked, else only the given node
+ * @throws CacheException If node doesn't exist, a NodeNotExistsException is throw. Other exceptions are
+ * LockingException, TimeoutException and UpgradeException
+ */
+ // public void lock(Fqn fqn, Object owner, int lock_type, boolean lock_recursive) throws CacheException {
+ //
+ // }
+
+ /**
+ * Unlock a given node (or the entire subtree starting at this node)
+ * @param fqn The FQN of the node
+ * @param owner The owner. This is simply a key into a hashtable, and can be anything, e.g.
+ * a GlobalTransaction, the current thread, or a special object. If null, it is set to Thread.currentThread()
+ * @param unlock_recursive If true, the entire subtree is unlocked, else only the given node
+ * @param force Release the lock even if we're not the owner
+ */
+ // public void unlock(Fqn fqn, Object owner, boolean unlock_recursive, boolean force) {
+ //
+ // }
+
+ /**
+ * Releases all locks for this node and the entire node subtree.
+ */
+ public void releaseAllLocks(String fqn)
+ {
+ releaseAllLocks(Fqn.fromString(fqn));
+ }
+
+ /**
+ * Releases all locks for this node and the entire node subtree.
+ */
+ public void releaseAllLocks(Fqn fqn)
+ {
+ MethodCall m = MethodCallFactory.create(MethodDeclarations.releaseAllLocksMethodLocal, fqn);
+ try
+ {
+ invokeMethod(m, true);
+ }
+ catch (CacheException e)
+ {
+ log.error("failed releasing all locks for " + fqn, e);
+ }
+ }
+
+ /**
+ * Prints a representation of the node defined by <code>fqn</code>.
+ * Output includes name, fqn and data.
+ */
+ public String print(String fqn)
+ {
+ return print(Fqn.fromString(fqn));
+ }
+
+ /**
+ * Prints a representation of the node defined by <code>fqn</code>.
+ * Output includes name, fqn and data.
+ */
+ public String print(Fqn fqn)
+ {
+ MethodCall m = MethodCallFactory.create(MethodDeclarations.printMethodLocal, fqn);
+ Object retval = null;
+ try
+ {
+ retval = invokeMethod(m, true);
+ }
+ catch (Throwable e)
+ {
+ retval = e;
+ }
+ if (retval != null)
+ {
+ return retval.toString();
+ }
+ else
+ {
+ return "";
+ }
+ }
+
+
+ /**
+ * Returns all children of a given node.
+ * Returns null of the parent node was not found, or if there are no
+ * children.
+ * The set is unmodifiable.
+ *
+ * @param fqn The fully qualified name of the node
+ * @return Set A list of child names (as Strings)
+ * @see #getChildrenNames(Fqn)
+ */
+ public Set getChildrenNames(String fqn) throws CacheException
+ {
+ return getChildrenNames(Fqn.fromString(fqn));
+ }
+
+ /**
+ * Returns all children of a given node. Returns an empty set if there are no children.
+ * The set is unmodifiable.
+ *
+ * @param fqn The fully qualified name of the node
+ * @return Set an unmodifiable set of children names, Object.
+ */
+ public <E> Set<E> getChildrenNames(Fqn<E> fqn) throws CacheException
+ {
+ MethodCall m = MethodCallFactory.create(MethodDeclarations.getChildrenNamesMethodLocal, fqn);
+ Set<E> retval = null;
+ retval = (Set<E>) invokeMethod(m, true);
+ if (retval != null)
+ retval = Collections.unmodifiableSet(new HashSet<E>(retval));
+ else
+ retval = Collections.emptySet();
+ return retval;
+ }
+
+ public <E> Set<E> _getChildrenNames(Fqn<E> fqn) throws CacheException
+ {
+ NodeSPI<K, V> n = findNode(fqn);
+ if (n == null) return null;
+ Set childNames = new HashSet();
+ Map childrenMap = n.getChildrenMapDirect();
+ if (childrenMap == null || childrenMap.isEmpty()) return Collections.emptySet();
+ Collection s = childrenMap.values();
+ // prune deleted children - JBCACHE-1136
+ for (Object c : s)
+ {
+ NodeSPI child = (NodeSPI) c;
+ if (!child.isDeleted()) childNames.add(child.getFqn().getLastElement());
+ }
+ return childNames;
+ }
+
+ /**
+ * Returns true if the FQN exists and the node has children.
+ */
+ public boolean hasChild(Fqn fqn)
+ {
+ if (fqn == null) return false;
+
+ NodeSPI n = findNode(fqn);
+ return n != null && n.hasChildrenDirect();
+ }
+
+ /**
+ * Returns a debug string with few details.
+ */
+ public String toString()
+ {
+ return toString(true);
+ }
+
+
+ /**
+ * Returns a debug string with optional details of contents.
+ */
+ public String toString(boolean details)
+ {
+ StringBuffer sb = new StringBuffer();
+ int indent = 0;
+
+ if (!details)
+ {
+ sb.append(getClass().getName()).append(" [").append(getNumberOfNodes()).append(" nodes, ");
+ sb.append(getNumberOfLocksHeld()).append(" locks]");
+ }
+ else
+ {
+ if (root == null)
+ return sb.toString();
+ for (NodeSPI n : root.getChildrenDirect())
+ {
+ n.print(sb, indent);
+ sb.append("\n");
+ }
+ }
+ return sb.toString();
+ }
+
+
+ /**
+ * Prints information about the contents of the nodes in the cache's current
+ * in-memory state. Does not load any previously evicted nodes from a
+ * cache loader, so evicted nodes will not be included.
+ */
+ public String printDetails()
+ {
+ StringBuffer sb = new StringBuffer();
+ root.printDetails(sb, 0);
+ sb.append("\n");
+ return sb.toString();
+ }
+
+ /**
+ * Returns lock information.
+ */
+ public String printLockInfo()
+ {
+ StringBuffer sb = new StringBuffer("\n");
+ int indent = 0;
+
+ for (NodeSPI n : root.getChildrenDirect())
+ {
+ n.getLock().printLockInfo(sb, indent);
+ sb.append("\n");
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Returns the number of read or write locks held across the entire cache.
+ */
+ public int getNumberOfLocksHeld()
+ {
+ return numLocks(root);
+ }
+
+ private int numLocks(NodeSPI<K, V> n)
+ {
+ int num = 0;
+ if (n.getLock().isLocked())
+ {
+ num++;
+ }
+ for (NodeSPI<K, V> cn : n.getChildrenDirect(true))
+ {
+ num += numLocks(cn);
+ }
+ return num;
+ }
+
+ /**
+ * Returns an <em>approximation</em> of the total number of nodes in the
+ * cache. Since this method doesn't acquire any locks, the number might be
+ * incorrect, or the method might even throw a
+ * ConcurrentModificationException
+ */
+ public int getNumberOfNodes()
+ {
+ return numNodes(root) - 1;
+ }
+
+ private int numNodes(NodeSPI<K, V> n)
+ {
+ int count = 1;// for n
+ for (NodeSPI<K, V> child : n.getChildrenDirect())
+ {
+ count += numNodes(child);
+ }
+ return count;
+ }
+
+ /**
+ * Returns an <em>approximation</em> of the total number of attributes in
+ * the cache. Since this method doesn't acquire any locks, the number might
+ * be incorrect, or the method might even throw a
+ * ConcurrentModificationException
+ */
+ public int getNumberOfAttributes()
+ {
+ return numAttributes(root);
+ }
+
+ /**
+ * Returns an <em>approximation</em> of the total number of attributes in
+ * this sub cache.
+ *
+ * @see #getNumberOfAttributes
+ */
+ public int getNumberOfAttributes(Fqn fqn)
+ {
+ return numAttributes(findNode(fqn));
+ }
+
+ private int numAttributes(NodeSPI<K, V> n)
+ {
+ int count = 0;
+ for (NodeSPI<K, V> child : n.getChildrenDirect())
+ {
+ count += numAttributes(child);
+ }
+ count += n.getDataDirect().size();
+ return count;
+ }
+
+ /* ---------------------- Remote method calls -------------------- */
+
+ /**
+ * @param mbrs
+ * @param method_call
+ * @param synchronous
+ * @param exclude_self
+ * @param timeout
+ * @return
+ * @throws Exception
+ * @deprecated Note this is due to be moved to an interceptor.
+ */
+ @Deprecated
+ public List callRemoteMethods(List<Address> mbrs, MethodCall method_call,
+ boolean synchronous, boolean exclude_self, long timeout)
+ throws Exception
+ {
+ return callRemoteMethods(mbrs, method_call, synchronous ? GroupRequest.GET_ALL : GroupRequest.GET_NONE, exclude_self, timeout);
+ }
+
+
+ /**
+ * Overloaded to allow a finer grained control over JGroups mode
+ *
+ * @param mbrs
+ * @param method_call
+ * @param mode
+ * @param exclude_self
+ * @param timeout
+ * @return
+ * @throws Exception
+ * @deprecated Note this is due to be moved to an interceptor.
+ */
+ @Deprecated
+ public List callRemoteMethods(List<Address> mbrs, MethodCall method_call, int mode, boolean exclude_self, long timeout)
+ throws Exception
+ {
+ RspList rsps = null;
+ Rsp rsp;
+ List retval;
+ Vector<Address> validMembers;
+
+ if (disp == null)
+ {
+ return null;
+ }
+
+ validMembers = null;
+ if (mbrs != null)
+ validMembers = new Vector<Address>(mbrs);
+ else
+ {
+ synchronized (members)
+ {
+ validMembers = new Vector<Address>(this.members);
+ }
+ }
+
+ if (exclude_self && !validMembers.isEmpty())
+ {
+ Object local_addr = getLocalAddress();
+ if (local_addr != null)
+ {
+ validMembers.remove(local_addr);
+ }
+ }
+ if (validMembers.isEmpty())
+ {
+ if (log.isTraceEnabled())
+ {
+ log.trace("destination list is empty, discarding call");
+ }
+ return null;
+ }
+
+ if (log.isTraceEnabled())
+ {
+ log.trace("callRemoteMethods(): valid members are " + validMembers + " methods: " + method_call.getArgs()[0]);
+ }
+
+ if (channel.flushSupported())
+ {
+ flushBlockGate.await(configuration.getStateRetrievalTimeout());
+ rsps = disp.callRemoteMethods(validMembers, method_call, mode, timeout, buddyManager != null && buddyManager.isEnabled());
+ }
+ else
+ {
+ rsps = disp.callRemoteMethods(validMembers, method_call, mode, timeout, buddyManager != null && buddyManager.isEnabled());
+ }
+
+ // a null response is 99% likely to be due to a marshalling problem - we throw a NSE, this needs to be changed when
+ // JGroups supports http://jira.jboss.com/jira/browse/JGRP-193
+ if (rsps == null)
+ {
+ // return null;
+ throw new NotSerializableException("RpcDispatcher returned a null. This is most often caused by args for " + method_call + " not being serializable.");
+ }
+ if (mode == GroupRequest.GET_NONE)
+ {
+ return Collections.EMPTY_LIST;// async case
+ }
+
+ if (log.isTraceEnabled())
+ {
+ log.trace("(" + getLocalAddress() + "): responses for method " + method_call.getName() + ":\n" + rsps);
+ }
+
+ retval = new ArrayList(rsps.size());
+ for (int i = 0; i < rsps.size(); i++)
+ {
+ rsp = (Rsp) rsps.elementAt(i);
+ if (rsp.wasSuspected() || !rsp.wasReceived())
+ {
+ CacheException ex;
+ if (rsp.wasSuspected())
+ {
+ ex = new SuspectException("Suspected member: " + rsp.getSender());
+ }
+ else
+ {
+ ex = new TimeoutException("Replication timeout for " + rsp.getSender());
+ }
+ retval.add(new ReplicationException("rsp=" + rsp, ex));
+ }
+ else
+ {
+ retval.add(rsp.getValue());
+ }
+ }
+ return retval;
+ }
+
+ /**
+ * @param members
+ * @param method
+ * @param args
+ * @param synchronous
+ * @param exclude_self
+ * @param timeout
+ * @return
+ * @throws Exception
+ * @deprecated Note this is due to be moved to an interceptor.
+ */
+ @Deprecated
+ public List callRemoteMethods(List<Address> members, Method method, Object[] args,
+ boolean synchronous, boolean exclude_self, long timeout)
+ throws Exception
+ {
+ return callRemoteMethods(members, MethodCallFactory.create(method, args), synchronous, exclude_self, timeout);
+ }
+
+ /**
+ * @param members
+ * @param method_name
+ * @param types
+ * @param args
+ * @param synchronous
+ * @param exclude_self
+ * @param timeout
+ * @return
+ * @throws Exception
+ * @deprecated Note this is due to be moved to an interceptor.
+ */
+ @Deprecated
+ public List callRemoteMethods(Vector<Address> members, String method_name,
+ Class[] types, Object[] args,
+ boolean synchronous, boolean exclude_self, long timeout)
+ throws Exception
+ {
+ Method method = getClass().getDeclaredMethod(method_name, types);
+ return callRemoteMethods(members, method, args, synchronous, exclude_self, timeout);
+ }
+
+ /* -------------------- End Remote method calls ------------------ */
+
+ /* --------------------- Callbacks -------------------------- */
+
+ /* ----- These are VERSIONED callbacks to facilitate JBCACHE-843. Also see docs/design/DataVersion.txt --- */
+
+ public void _putForExternalRead(GlobalTransaction gtx, Fqn fqn, K key, V value, DataVersion dv) throws CacheException
+ {
+ _putForExternalRead(gtx, fqn, key, value);
+ }
+
+ public void _put(GlobalTransaction tx, Fqn fqn, Map<K, V> data, boolean create_undo_ops, DataVersion dv) throws CacheException
+ {
+ _put(tx, fqn, data, create_undo_ops, false, dv);
+ }
+
+ public void _put(GlobalTransaction tx, Fqn fqn, Map<K, V> data, boolean create_undo_ops, boolean erase_contents, DataVersion dv) throws CacheException
+ {
+ _put(tx, fqn, data, create_undo_ops, erase_contents);
+ }
+
+ public Object _put(GlobalTransaction tx, Fqn fqn, K key, V value, boolean create_undo_ops, DataVersion dv) throws CacheException
+ {
+ return _put(tx, fqn, key, value, create_undo_ops);
+ }
+
+ public boolean _remove(GlobalTransaction tx, Fqn fqn, boolean create_undo_ops, DataVersion dv) throws CacheException
+ {
+ return _remove(tx, fqn, create_undo_ops, true);
+ }
+
+ public Object _remove(GlobalTransaction tx, Fqn fqn, K key, boolean create_undo_ops, DataVersion dv) throws CacheException
+ {
+ return _remove(tx, fqn, key, create_undo_ops);
+ }
+
+ public void _removeData(GlobalTransaction tx, Fqn fqn, boolean create_undo_ops, DataVersion dv) throws CacheException
+ {
+
+ _removeData(tx, fqn, create_undo_ops, true);
+ }
+
+ /* ----- End VERSIONED callbacks - Now for the NORMAL callbacks. -------- */
+
+ /**
+ * Internal put method.
+ * Does the real work. Needs to acquire locks if accessing nodes, depending on
+ * the value of <tt>locking</tt>. If run inside a transaction, needs to (a) add
+ * newly acquired locks to {@link TransactionEntry}'s lock list, (b) add nodes
+ * that were created to {@link TransactionEntry}'s node list and (c) create
+ * {@link Modification}s and add them to {@link TransactionEntry}'s modification
+ * list and (d) create compensating modifications to undo the changes in case
+ * of a rollback
+ *
+ * @param fqn
+ * @param data
+ * @param create_undo_ops If true, undo operations will be created (default is true).
+ * Otherwise they will not be created (used by rollback()).
+ */
+ public void _put(GlobalTransaction tx, String fqn, Map<K, V> data, boolean create_undo_ops)
+ throws CacheException
+ {
+ _put(tx, Fqn.fromString(fqn), data, create_undo_ops);
+ }
+
+
+ /**
+ * Internal put method.
+ * Does the real work. Needs to acquire locks if accessing nodes, depending on
+ * the value of <tt>locking</tt>. If run inside a transaction, needs to (a) add
+ * newly acquired locks to {@link TransactionEntry}'s lock list, (b) add nodes
+ * that were created to {@link TransactionEntry}'s node list and (c) create
+ * {@link Modification}s and add them to {@link TransactionEntry}'s modification
+ * list and (d) create compensating modifications to undo the changes in case
+ * of a rollback
+ *
+ * @param fqn
+ * @param data
+ * @param create_undo_ops If true, undo operations will be created (default is true).
+ * Otherwise they will not be created (used by rollback()).
+ */
+ public void _put(GlobalTransaction tx, Fqn fqn, Map<K, V> data, boolean create_undo_ops)
+ throws CacheException
+ {
+ _put(tx, fqn, data, create_undo_ops, false);
+ }
+
+ /**
+ * Internal put method.
+ * Does the real work. Needs to acquire locks if accessing nodes, depending on
+ * the value of <tt>locking</tt>. If run inside a transaction, needs to (a) add
+ * newly acquired locks to {@link TransactionEntry}'s lock list, (b) add nodes
+ * that were created to {@link TransactionEntry}'s node list and (c) create
+ * {@link Modification}s and add them to {@link TransactionEntry}'s modification
+ * list and (d) create compensating modifications to undo the changes in case
+ * of a rollback
+ *
+ * @param fqn
+ * @param data
+ * @param create_undo_ops If true, undo operations will be created (default is true).
+ * @param erase_contents Clear the existing hashmap before putting the new data into it
+ * Otherwise they will not be created (used by rollback()).
+ */
+ public void _put(GlobalTransaction tx, Fqn fqn, Map<K, V> data, boolean create_undo_ops, boolean erase_contents)
+ throws CacheException
+ {
+ if (log.isTraceEnabled())
+ {
+ log.trace("_put(" + tx + ", \"" + fqn + "\", " + data + " undo=" + create_undo_ops + " erase=" + erase_contents + ")");
+ }
+ InvocationContext ctx = getInvocationContext();
+ boolean isRollback = checkIsRollingBack(ctx.getTransaction());
+ NodeSPI<K, V> n = findNodeCheck(tx, fqn);
+ Map<K, V> rawData = n.getDataDirect();
+ if (!isRollback) notifier.notifyNodeModified(fqn, true, NodeModifiedEvent.ModificationType.PUT_MAP, rawData, ctx);
+
+ // create a compensating method call (reverting the effect of
+ // this modification) and put it into the TX's undo list.
+ if (tx != null && create_undo_ops)
+ {
+ // erase and set to previous hashmap contents
+ MethodCall undo_op = MethodCallFactory.create(MethodDeclarations.putDataEraseMethodLocal, tx, fqn, new HashMap(rawData), false, true);
+ tx_table.addUndoOperation(tx, undo_op);
+ }
+
+ if (erase_contents)
+ n.clearDataDirect();
+ n.putAllDirect(data);
+
+ if (!isRollback)
+ notifier.notifyNodeModified(fqn, false, NodeModifiedEvent.ModificationType.PUT_MAP, n.getDataDirect(), ctx);
+ }
+
+ /**
+ * Internal put method.
+ *
+ * @return Previous value (if any)
+ */
+ public Object _put(GlobalTransaction tx, String fqn, K key, V value, boolean create_undo_ops)
+ throws CacheException
+ {
+ return _put(tx, Fqn.fromString(fqn), key, value, create_undo_ops);
+ }
+
+ private boolean checkIsRollingBack(Transaction tx)
+ {
+ try
+ {
+ return tx != null && (
+ tx.getStatus() == javax.transaction.Status.STATUS_ROLLEDBACK ||
+ tx.getStatus() == javax.transaction.Status.STATUS_ROLLING_BACK ||
+ tx.getStatus() == javax.transaction.Status.STATUS_MARKED_ROLLBACK);
+ }
+ catch (Exception e)
+ {
+ // can't get a hold of a transaction - probably no tx rolling back
+ return false;
+ }
+ }
+
+ /**
+ * Internal put method.
+ *
+ * @return Previous value (if any)
+ */
+ public Object _put(GlobalTransaction tx, Fqn fqn, K key, V value, boolean create_undo_ops)
+ throws CacheException
+ {
+ if (log.isTraceEnabled())
+ {
+ log.trace(new StringBuffer("_put(").append(tx).append(", \"").
+ append(fqn).append("\", k=").append(key).append(", v=").append(value).append(")"));
+ }
+
+
+ InvocationContext ctx = getInvocationContext();
+ // if this is a rollback then don't fire notifications.
+ boolean isRollback = checkIsRollingBack(ctx.getTransaction());
+
+ NodeSPI<K, V> n = findNodeCheck(tx, fqn);
+ Map<K, V> rawData = n.getDataDirect();
+ if (!isRollback)
+ notifier.notifyNodeModified(fqn, true, NodeModifiedEvent.ModificationType.PUT_DATA, rawData, ctx);
+
+ V old_value = n.putDirect(key, value);
+
+ // create a compensating method call (reverting the effect of
+ // this modification) and put it into the TX's undo list.
+ if (tx != null && create_undo_ops)
+ {
+ MethodCall undo_op;
+ if (old_value == null)
+ {
+ undo_op = MethodCallFactory.create(MethodDeclarations.removeKeyMethodLocal, tx, fqn, key, false);
+ }
+ else
+ {
+ undo_op = MethodCallFactory.create(MethodDeclarations.putKeyValMethodLocal, tx, fqn, key, old_value, false);
+ }
+ // 1. put undo-op in TX' undo-operations list (needed to rollback TX)
+ tx_table.addUndoOperation(tx, undo_op);
+ }
+
+ Map<K, V> newData = Collections.singletonMap(key, value);
+ if (!isRollback)
+ notifier.notifyNodeModified(fqn, false, NodeModifiedEvent.ModificationType.PUT_DATA, newData, ctx);
+ return old_value;
+ }
+
+ /**
+ * Internal remove method.
+ */
+ public void _remove(GlobalTransaction tx, String fqn, boolean create_undo_ops) throws CacheException
+ {
+ _remove(tx, Fqn.fromString(fqn), create_undo_ops);
+ }
+
+ /**
+ * Internal remove method.
+ */
+ public boolean _remove(GlobalTransaction tx, Fqn fqn, boolean create_undo_ops) throws CacheException
+ {
+ return _remove(tx, fqn, create_undo_ops, true);
+ }
+
+ public boolean _remove(GlobalTransaction tx, Fqn fqn, boolean create_undo_ops, boolean sendNodeEvent)
+ throws CacheException
+ {
+ return _remove(tx, fqn, create_undo_ops, sendNodeEvent, false);
+ }
+
+ /**
+ * Internal method to remove a node.
+ *
+ * @param tx
+ * @param fqn
+ * @param create_undo_ops
+ * @param sendNodeEvent
+ */
+ public boolean _remove(GlobalTransaction tx, Fqn fqn, boolean create_undo_ops, boolean sendNodeEvent, boolean eviction)
+ throws CacheException
+ {
+ return _remove(tx, fqn, create_undo_ops, sendNodeEvent, eviction, null);
+ }
+
+ /**
+ * Internal method to remove a node.
+ * Performs a remove on a node, passing in a {@link DataVersion} which is used with optimistically locked nodes. Pass
+ * in a null if optimistic locking is not used.
+ *
+ * @param tx
+ * @param fqn
+ * @param create_undo_ops
+ * @param sendNodeEvent
+ * @param eviction
+ * @param version
+ * @return true if the node was removed, false if not found
+ * @throws CacheException
+ */
+ public boolean _remove(GlobalTransaction tx, Fqn fqn, boolean create_undo_ops, boolean sendNodeEvent, boolean eviction, DataVersion version)
+ throws CacheException
+ {
+
+ NodeSPI<K, V> n;
+ NodeSPI<K, V> parent_node;
+ MethodCall undo_op = null;
+
+ if (log.isTraceEnabled())
+ {
+ log.trace("_remove(" + tx + ", \"" + fqn + "\", undo=" + create_undo_ops + ")");
+ }
+ InvocationContext ctx = getInvocationContext();
+ // check if this is triggered by a rollback operation ...
+ boolean isRollback = checkIsRollingBack(ctx.getTransaction());
+ if (tx != null)
+ {
+ try
+ {
+ if (isRollback)
+ {
+ log.trace("This remove call is triggered by a transaction rollback, as a compensation operation. Do a realRemove() instead.");
+ return realRemove(fqn, true);
+ }
+ }
+ catch (Exception e)
+ {
+ // what do we do here?
+ log.warn("Unable to get a hold of the transaction for a supposedly transactional call! This *may* result in stale locks!", e);
+ }
+ }
+
+ // Find the node. This will add the temporarily created parent nodes to the TX's node list if tx != null)
+ n = findNode(fqn, version);
+ if (n == null)
+ {
+ if (log.isTraceEnabled())
+ {
+ log.trace("node " + fqn + " not found");
+ }
+ return false;
+ }
+
+ if (!isRollback)
+ {
+ if (eviction)
+ {
+ notifier.notifyNodeEvicted(fqn, true, ctx);
+ }
+ else
+ {
+ notifier.notifyNodeRemoved(fqn, true, n.getDataDirect(), ctx);
+ }
+ }
+
+ parent_node = n.getParent();
+ boolean found;
+
+ // remove subtree from parent
+ if (eviction || configuration.isNodeLockingOptimistic())
+ {
+ // if there is no parent node and the fqn is root, found == true otherwise found == false.
+ found = parent_node == null ? fqn.isRoot() : parent_node.removeChildDirect(n.getFqn().getLastElement());
+ }
+ else
+ {
+ found = !n.isDeleted();
+ n.markAsDeleted(true);
+ }
+
+ if (eviction && parent_node != null)
+ {
+ parent_node.setChildrenLoaded(false);
+ }
+
+ // release all locks for the entire subtree
+ // n.getNodeSPI().getLock().releaseAll(tx != null ? tx : (Object) Thread.currentThread());
+
+ // create a compensating method call (reverting the effect of
+ // this modification) and put it into the TX's undo list.
+ if (tx != null && create_undo_ops && !eviction)
+ {
+ undo_op = MethodCallFactory.create(MethodDeclarations.addChildMethodLocal, tx, parent_node.getFqn(), n.getFqn().getLastElement(), n, false);
+
+ // 1. put undo-op in TX' undo-operations list (needed to rollback TX)
+ tx_table.addUndoOperation(tx, undo_op);
+ }
+
+ if (!isRollback)
+ {
+ if (eviction)
+ {
+ notifier.notifyNodeEvicted(fqn, false, ctx);
+ }
+ else
+ {
+ notifier.notifyNodeRemoved(fqn, false, null, ctx);
+ }
+ }
+
+ return found;
+ }
+
+ /**
+ * Internal method to remove a key.
+ *
+ * @param fqn
+ * @param key
+ * @return Object
+ */
+ public V _remove(GlobalTransaction tx, String fqn, K key, boolean create_undo_ops)
+ throws CacheException
+ {
+ return _remove(tx, Fqn.fromString(fqn), key, create_undo_ops);
+ }
+
+ /**
+ * Internal method to remove a key.
+ *
+ * @param fqn
+ * @param key
+ * @return Object
+ */
+ public V _remove(GlobalTransaction tx, Fqn fqn, K key, boolean create_undo_ops)
+ throws CacheException
+ {
+ MethodCall undo_op = null;
+ V old_value = null;
+
+ if (log.isTraceEnabled())
+ {
+ log.trace("_remove(" + tx + ", \"" + fqn + "\", key=" + key + ")");
+ }
+
+ // Find the node. This will lock it (if <tt>locking</tt> is true) and
+ // add the temporarily created parent nodes to the TX's node list if tx != null)
+ NodeSPI<K, V> n = findNode(fqn);
+ if (n == null)
+ {
+ log.warn("node " + fqn + " not found");
+ return null;
+ }
+ InvocationContext ctx = getInvocationContext();
+ boolean isRollback = checkIsRollingBack(ctx.getTransaction());
+ if (!isRollback)
+ notifier.notifyNodeModified(fqn, true, NodeModifiedEvent.ModificationType.REMOVE_DATA, n.getDataDirect(), ctx);
+
+ old_value = n.removeDirect(key);
+
+ // create a compensating method call (reverting the effect of
+ // this modification) and put it into the TX's undo list.
+ if (tx != null && create_undo_ops && old_value != null)
+ {
+ undo_op = MethodCallFactory.create(MethodDeclarations.putKeyValMethodLocal, tx, fqn, key, old_value, false);
+ // 1. put undo-op in TX' undo-operations list (needed to rollback TX)
+ tx_table.addUndoOperation(tx, undo_op);
+ }
+
+ Map<K, V> removedData = Collections.singletonMap(key, old_value);
+ if (!isRollback)
+ notifier.notifyNodeModified(fqn, false, NodeModifiedEvent.ModificationType.REMOVE_DATA, removedData, ctx);
+
+ return old_value;
+ }
+
+ /**
+ * Internal method to remove data from a node.
+ */
+ public void _removeData(GlobalTransaction tx, String fqn, boolean create_undo_ops)
+ throws CacheException
+ {
+ _removeData(tx, Fqn.fromString(fqn), create_undo_ops);
+ }
+
+ /**
+ * Internal method to remove data from a node.
+ */
+ public void _removeData(GlobalTransaction tx, Fqn fqn, boolean create_undo_ops)
+ throws CacheException
+ {
+ _removeData(tx, fqn, create_undo_ops, true);
+ }
+
+ /**
+ * Internal method to remove data from a node.
+ */
+ public void _removeData(GlobalTransaction tx, Fqn fqn, boolean create_undo_ops, boolean sendNodeEvent)
+ throws CacheException
+ {
+ _removeData(tx, fqn, create_undo_ops, sendNodeEvent, false);
+ }
+
+ /**
+ * Internal method to remove data from a node.
+ */
+ public void _removeData(GlobalTransaction tx, Fqn fqn, boolean create_undo_ops, boolean sendNodeEvent, boolean eviction)
+ throws CacheException
+ {
+ _removeData(tx, fqn, create_undo_ops, sendNodeEvent, eviction, null);
+ }
+
+ /**
+ * Internal method to remove data from a node.
+ */
+ public void _removeData(GlobalTransaction tx, Fqn fqn, boolean create_undo_ops, boolean sendNodeEvent, boolean eviction, DataVersion version)
+ throws CacheException
+ {
+ MethodCall undo_op = null;
+
+ if (log.isTraceEnabled())
+ {
+ log.trace("_removeData(" + tx + ", \"" + fqn + "\")");
+ }
+
+ // Find the node. This will lock it (if <tt>locking</tt> is true) and
+ // add the temporarily created parent nodes to the TX's node list if tx != null)
+ NodeSPI n = findNode(fqn, version);
+ if (n == null)
+ {
+ log.warn("node " + fqn + " not found");
+ return;
+ }
+
+ Map<K, V> data = n.getDataDirect();
+ InvocationContext ctx = getInvocationContext();
+ boolean isRollback = checkIsRollingBack(ctx.getTransaction());
+ // create a compensating method call (reverting the effect of
+ // this modification) and put it into the TX's undo list.
+ if (tx != null && create_undo_ops && !eviction)
+ {
+ if (!data.isEmpty())
+ {
+ undo_op = MethodCallFactory.create(MethodDeclarations.putDataMethodLocal,
+ tx, fqn, new HashMap<K,V>(data), false);
+ }
+ }
+
+ if (!isRollback)
+ {
+ if (eviction)
+ {
+ notifier.notifyNodeEvicted(fqn, true, ctx);
+ }
+ else
+ {
+ notifier.notifyNodeModified(fqn, true, NodeModifiedEvent.ModificationType.REMOVE_DATA, data, ctx);
+ }
+ }
+
+ n.clearDataDirect();
+ if (eviction)
+ {
+ n.setDataLoaded(false);
+ }
+
+ if (!isRollback)
+ {
+ if (sendNodeEvent)
+ {
+ notifier.notifyNodeVisited(fqn, false, ctx);
+ }
+ else
+ {// FIXME Bela did this so GUI view can refresh the view after node is evicted. But this breaks eviction policy, especially AOP!!!!
+ if (eviction)
+ {
+ notifier.notifyNodeEvicted(fqn, false, ctx);
+ }
+ else
+ {
+ notifier.notifyNodeModified(fqn, false, NodeModifiedEvent.ModificationType.REMOVE_DATA, data, ctx);
+ }
+ }
+ }
+
+ // put undo-op in TX' undo-operations list (needed to rollback TX)
+ if (tx != null && create_undo_ops)
+ {
+ tx_table.addUndoOperation(tx, undo_op);
+ }
+ }
+
+
+ /**
+ * Internal evict method called by eviction policy provider.
+ *
+ * @param fqn removes everything assoicated with this FQN
+ * @return <code>true</code> if the node has been completely removed,
+ * <code>false</code> if only the data map was removed, due
+ * to the presence of children
+ * @throws CacheException
+ */
+ public boolean _evict(Fqn fqn) throws CacheException
+ {
+ if (!exists(fqn))
+ return true;// node does not exist. Maybe it has been recursively removed.
+ // use remove method now if there is a child node. Otherwise, it is removed
+ boolean create_undo_ops = false;
+ boolean sendNodeEvent = false;
+ boolean eviction = true;
+ if (log.isTraceEnabled())
+ {
+ log.trace("_evict(" + fqn + ")");
+ }
+ if (hasChild(fqn))
+ {
+ _removeData(null, fqn, create_undo_ops, sendNodeEvent, eviction);
+ return false;
+ }
+ else
+ {
+ _remove(null, fqn, create_undo_ops, sendNodeEvent, eviction);
+ return true;
+ }
+ }
+
+ /**
+ * Internal evict method called by eviction policy provider.
+ *
+ * @param fqn
+ * @param version
+ * @return <code>true</code> if the node has been completely removed,
+ * <code>false</code> if only the data map was removed, due
+ * to the presence of children
+ * @throws CacheException
+ */
+ public boolean _evict(Fqn fqn, DataVersion version) throws CacheException
+ {
+ if (!exists(fqn))
+ return true;// node does not exist
+
+ boolean create_undo_ops = false;
+ boolean sendNodeEvent = false;
+ boolean eviction = true;
+ if (log.isTraceEnabled())
+ {
+ log.trace("_evict(" + fqn + ", " + version + ")");
+ }
+ if (hasChild(fqn))
+ {
+ _removeData(null, fqn, create_undo_ops, sendNodeEvent, eviction, version);
+ return false;
+ }
+ else
+ {
+ _remove(null, fqn, create_undo_ops, sendNodeEvent, eviction, version);
+ return true;
+ }
+ }
+
+ /**
+ * Evicts a key/value pair from a node's attributes. Note that this is <em>local</em>, will not be replicated.
+ * @param fqn
+ * @param key
+ * @throws CacheException
+ */
+ // public void _evict(Fqn fqn, Object key) throws CacheException {
+ // if(!exists(fqn)) return;
+ // boolean create_undo_ops = false;
+ // boolean sendNodeEvent = false;
+ // boolean eviction=true;
+ // _removeData(null, fqn, create_undo_ops, sendNodeEvent, eviction);
+ // }
+
+
+ /**
+ * Compensating method to {@link #_remove(GlobalTransaction,Fqn,boolean)}.
+ */
+ public void _addChild(GlobalTransaction gtx, Fqn parent_fqn, Object child_name, Node cn, boolean undoOps)
+ throws CacheException
+ {
+ NodeSPI childNode = (NodeSPI) cn;
+ if (log.isTraceEnabled())
+ {
+ log.trace("_addChild(\"" + parent_fqn + "\", \"" + child_name + "\", node=" + childNode + ")");
+ }
+
+ if (parent_fqn == null || child_name == null || childNode == null)
+ {
+ log.error("parent_fqn or child_name or childNode was null");
+ return;
+ }
+ NodeSPI parentNode = findNode(parent_fqn);
+ if (parentNode == null)
+ {
+ log.warn("node " + parent_fqn + " not found");
+ return;
+ }
+ InvocationContext ctx = getInvocationContext();
+ boolean isRollback = checkIsRollingBack(ctx.getTransaction());
+ Fqn fqn = new Fqn(parent_fqn, child_name);
+ if (!isRollback) notifier.notifyNodeCreated(fqn, true, ctx);
+ parentNode.addChild(child_name, childNode);
+
+ childNode.markAsDeleted(false, true);
+
+ if (gtx != null && undoOps)
+ {
+ // 1. put undo-op in TX' undo-operations list (needed to rollback TX)
+ tx_table.addUndoOperation(gtx, MethodCallFactory.create(MethodDeclarations.removeNodeMethodLocal, gtx, fqn, false));
+ }
+
+ if (!isRollback) notifier.notifyNodeCreated(fqn, false, ctx);
+ }
+
+
+ /**
+ * Replicates changes across to other nodes in the cluster. Invoked by the
+ * ReplicationInterceptor. Calls need to be forwarded to the
+ * ReplicationInterceptor in this interceptor chain. This method will later
+ * be moved entirely into the ReplicationInterceptor.
+ */
+ public Object _replicate(MethodCall method_call) throws Throwable
+ {
+ try
+ {
+ Object retVal = invokeMethod(method_call, false);
+ // we only need to return values for a set of remote calls; not every call.
+ if (MethodDeclarations.returnValueForRemoteCall(method_call.getMethodId()))
+ {
+ return retVal;
+ }
+ else
+ {
+ return null;
+ }
+ }
+ catch (Throwable ex)
+ {
+ log.warn("replication failure with method_call " + method_call + " exception", ex);
+ throw ex;
+ }
+ }
+
+ /**
+ * Replicates a list of method calls.
+ */
+ public void _replicate(List<MethodCall> methodCalls) throws Throwable
+ {
+ for (MethodCall methodCall : methodCalls) _replicate(methodCall);
+ }
+
+ /**
+ * A 'clustered get' call, called from a remote ClusteredCacheLoader.
+ *
+ * @return a List containing 2 elements: (true or false) and a value (Object). If buddy replication
+ * is used one further element is added - an Fqn of the backup subtree in which this node may be found.
+ */
+ public List _clusteredGet(MethodCall methodCall, Boolean searchBackupSubtrees)
+ {
+ MethodCall call = methodCall;
+ if (log.isTraceEnabled()) log.trace("Clustered Get called with params: " + call + ", " + searchBackupSubtrees);
+ Method m = call.getMethod();
+ Object[] args = call.getArgs();
+
+ Object callResults = null;
+
+ try
+ {
+ Fqn fqn = (Fqn) args[0];
+
+ if (log.isTraceEnabled()) log.trace("Clustered get: invoking call " + m + " with Fqn " + fqn);
+ callResults = m.invoke(this, args);
+ boolean found = validResult(callResults, call, fqn);
+ if (log.isTraceEnabled()) log.trace("Got result " + callResults + ", found=" + found);
+ if (found && callResults == null) callResults = createEmptyResults(call);
+ }
+ catch (Exception e)
+ {
+ log.warn("Problems processing clusteredGet call", e);
+ }
+
+ List<Object> results = new ArrayList<Object>(2);
+ if (callResults != null)
+ {
+ results.add(true);
+ results.add(callResults);
+ }
+ else
+ {
+ results.add(false);
+ results.add(null);
+ }
+ return results;
+ }
+
+ /**
+ * Used with buddy replication's data gravitation interceptor. If marshalling is necessary, ensure that the cache is
+ * configured to use {@link org.jboss.cache.config.Configuration#useRegionBasedMarshalling} and the {@link org.jboss.cache.Region}
+ * pertaining to the Fqn passed in is activated, and has an appropriate ClassLoader.
+ *
+ * @param fqn the fqn to gravitate
+ * @param searchSubtrees if true, buddy backup subtrees are searched and if false, they are not.
+ * @return a GravitateResult which contains the data for the gravitation
+ */
+ public GravitateResult gravitateData(Fqn fqn, boolean searchSubtrees)
+ throws CacheException
+ {
+ // we need to get the state for this Fqn and its sub-nodes.
+
+ // for now, perform a very simple series of getData calls.
+ InvocationContext ctx = getInvocationContext();
+
+ log.debug("*****************>>>>> " + printLockInfo());
+
+ try
+ {
+ ctx.setOriginLocal(false);
+
+ NodeSPI<K, V> actualNode = findNode(fqn);
+ Fqn backupNodeFqn = null;
+ if (actualNode == null && searchSubtrees)
+ {
+ NodeSPI backupSubtree = findNode(BuddyManager.BUDDY_BACKUP_SUBTREE_FQN);
+ if (backupSubtree != null)
+ {
+ // need to loop through backupSubtree's children
+ Set childNames = backupSubtree.getChildrenNamesDirect();
+ if (childNames != null)
+ {
+ for (Object childName : childNames)
+ {
+ // childName is the name of a buddy group since all child names in this
+ // collection are direct children of BUDDY_BACKUP_SUBTREE_FQN
+ backupNodeFqn = BuddyManager.getBackupFqn(childName.toString(), fqn);
+ actualNode = findNode(backupNodeFqn);
+ if (actualNode != null) break;
+ }
+ }
+ /*Map children = backupSubtree.getChildrenMapDirect();
+ if (children != null)
+ {
+ Iterator childNames = children.keySet().iterator();
+ while (childNames.hasNext() && actualNode == null)
+ {
+ backupNodeFqn = BuddyManager.getBackupFqn(childNames.next().toString(), fqn);
+ actualNode = findNode(backupNodeFqn);
+ }
+ }*/
+ }
+ }
+
+ if (actualNode == null)
+ {
+ return GravitateResult.noDataFound();
+ }
+
+ if (backupNodeFqn == null && searchSubtrees)
+ {
+ backupNodeFqn = BuddyManager.getBackupFqn(BuddyManager.getGroupNameFromAddress(getLocalAddress()), fqn);
+ }
+
+ List<NodeData> list = getNodeData(new LinkedList<NodeData>(), actualNode);
+
+ return GravitateResult.subtreeResult(list, backupNodeFqn);
+ }
+ finally
+ {
+ ctx.setOriginLocal(true);
+ }
+ }
+
+ private List<NodeData> getNodeData(List<NodeData> list, NodeSPI<K, V> node)
+ {
+ NodeData data = new NodeData(BuddyManager.getActualFqn(node.getFqn()), node.getDataDirect());
+ list.add(data);
+ for (NodeSPI<K, V> childNode : node.getChildrenDirect())
+ {
+ getNodeData(list, childNode);
+ }
+ return list;
+ }
+
+ // ------------- start: buddy replication specific 'lifecycle' method calls
+
+ public void _remoteAssignToBuddyGroup(BuddyGroup group, Map<Fqn, byte[]> state) throws Exception
+ {
+ if (buddyManager != null)
+ buddyManager.handleAssignToBuddyGroup(group, state);
+ else if (log.isWarnEnabled())
+ log.warn("Received assignToBuddyGroup call from group owner [" + group.getDataOwner() + "] but buddy replication is not enabled on this node!");
+ }
+
+ public void _remoteRemoveFromBuddyGroup(String groupName) throws BuddyNotInitException
+ {
+ if (buddyManager != null)
+ buddyManager.handleRemoveFromBuddyGroup(groupName);
+ else if (log.isWarnEnabled())
+ log.warn("Received removeFromBuddyGroup call for group name [" + groupName + "] but buddy replication is not enabled on this node!");
+
+ }
+
+ public void _remoteAnnounceBuddyPoolName(Address address, String buddyPoolName)
+ {
+ if (buddyManager != null)
+ buddyManager.handlePoolNameBroadcast(address, buddyPoolName);
+ else if (log.isWarnEnabled())
+ log.warn("Received annouceBuddyPoolName call from [" + address + "] but buddy replication is not enabled on this node!");
+ }
+
+ public void _dataGravitationCleanup(GlobalTransaction gtx, Fqn primary, Fqn backup) throws Exception
+ {
+ MethodCall primaryDataCleanup, backupDataCleanup;
+ if (buddyManager.isDataGravitationRemoveOnFind())
+ {
+ if (log.isTraceEnabled())
+ log.trace("DataGravitationCleanup: Removing primary (" + primary + ") and backup (" + backup + ")");
+ primaryDataCleanup = MethodCallFactory.create(MethodDeclarations.removeNodeMethodLocal, null, primary, false);
+ backupDataCleanup = MethodCallFactory.create(MethodDeclarations.removeNodeMethodLocal, null, backup, false);
+ }
+ else
+ {
+ if (log.isTraceEnabled())
+ log.trace("DataGravitationCleanup: Evicting primary (" + primary + ") and backup (" + backup + ")");
+ primaryDataCleanup = MethodCallFactory.create(MethodDeclarations.evictNodeMethodLocal, primary);
+ backupDataCleanup = MethodCallFactory.create(MethodDeclarations.evictNodeMethodLocal, backup);
+ }
+
+ invokeMethod(primaryDataCleanup, true);
+ invokeMethod(backupDataCleanup, true);
+ }
+
+ // ------------- end: buddy replication specific 'lifecycle' method calls
+
+
+ /**
+ * Returns true if the call results returned a valid result.
+ */
+ private boolean validResult(Object callResults, MethodCall mc, Fqn fqn)
+ {
+ switch (mc.getMethodId())
+ {
+ case MethodDeclarations.getDataMapMethodLocal_id:
+ case MethodDeclarations.getChildrenNamesMethodLocal_id:
+ return callResults != null || exists(fqn);
+ case MethodDeclarations.existsMethod_id:
+ return (Boolean) callResults;
+ default:
+ return false;
+ }
+ }
+
+ /**
+ * Creates an empty Collection class based on the return type of the method called.
+ */
+ private Object createEmptyResults(MethodCall mc)
+ {
+ switch (mc.getMethodId())
+ {
+ case MethodDeclarations.getDataMapMethodLocal_id:
+ case MethodDeclarations.getChildrenNamesMethodLocal_id:
+ return Collections.emptyMap();
+ default:
+ return null;
+ }
+ }
+
+ /**
+ * Releases all locks for a FQN.
+ */
+ public void _releaseAllLocks(Fqn fqn)
+ {
+ NodeSPI<K, V> n;
+
+ try
+ {
+ n = findNode(fqn);
+ if (n == null)
+ {
+ log.error("releaseAllLocks(): node " + fqn + " not found");
+ return;
+ }
+ releaseAll(n);
+ }
+ catch (Throwable t)
+ {
+ log.error("releaseAllLocks(): failed", t);
+ }
+ }
+
+ private void releaseAll(NodeSPI<K, V> n)
+ {
+ for (NodeSPI<K, V> child : n.getChildrenDirect())
+ {
+ releaseAll(child);
+ }
+ n.getLock().releaseAll();
+ }
+
+
+ /**
+ * Finds and returns the string value for the Fqn.
+ * Returns null if not found or upon error.
+ */
+ public String _print(Fqn fqn)
+ {
+ try
+ {
+ Node n = findNode(fqn);
+ if (n == null) return null;
+ return n.toString();
+ }
+ catch (Throwable t)
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Should not be called.
+ */
+ public void _lock(Fqn fqn, NodeLock.LockType lock_type, boolean recursive)
+ throws TimeoutException, LockingException
+ {
+ throw new UnsupportedOperationException("method _lock() should not be invoked on CacheImpl");
+ }
+
+ /**
+ * Throws UnsupportedOperationException.
+ */
+ public void optimisticPrepare(GlobalTransaction gtx, List modifications, Map data, Address address, boolean onePhaseCommit)
+ {
+ throw new UnsupportedOperationException("optimisticPrepare() should not be called on CacheImpl directly");
+ }
+
+ /**
+ * Throws UnsupportedOperationException.
+ */
+ public void prepare(GlobalTransaction global_tx, List modifications, Address coord, boolean onePhaseCommit)
+ {
+ throw new UnsupportedOperationException("prepare() should not be called on CacheImpl directly");
+ }
+
+ /**
+ * Throws UnsupportedOperationException.
+ */
+ public void commit(GlobalTransaction tx)
+ {
+ throw new UnsupportedOperationException("commit() should not be called on CacheImpl directly");
+ }
+
+ /**
+ * Throws UnsupportedOperationException.
+ */
+ public void rollback(GlobalTransaction tx)//, Boolean hasMods)
+ {
+ throw new UnsupportedOperationException("rollback() should not be called on CacheImpl directly");
+ }
+
+ /* ----------------- End of Callbacks ---------------------- */
+
+ /**
+ * Adds an undo operatoin to the transaction table.
+ */
+ public void addUndoOperation(GlobalTransaction gtx, MethodCall undo_op)
+ {
+ tx_table.addUndoOperation(gtx, undo_op);
+ }
+
+ /**
+ * Returns the CacheLoaderManager.
+ */
+ public CacheLoaderManager getCacheLoaderManager()
+ {
+ return cacheLoaderManager;
+ }
+
+ /**
+ * Sets the CacheLoaderManager.
+ */
+ public void setCacheLoaderManager(CacheLoaderManager cacheLoaderManager)
+ {
+ this.cacheLoaderManager = cacheLoaderManager;
+ }
+
+ public void setConfiguration(Configuration configuration)
+ {
+ this.configuration = configuration;
+ configuration.setCacheImpl(this);
+ }
+
+ /**
+ * @return an instance of {@link Notifier} which has been configured with this instance of CacheImpl.
+ */
+ public Notifier getNotifier()
+ {
+ return notifier;
+ }
+
+ public InvocationContext getInvocationContext()
+ {
+ InvocationContext ctx = invocationContextContainer.get();
+ if (ctx == null)
+ {
+ ctx = new InvocationContext();
+ invocationContextContainer.set(ctx);
+ }
+ return ctx;
+ }
+
+ public void setInvocationContext(InvocationContext ctx)
+ {
+ invocationContextContainer.set(ctx);
+ }
+
+ /**
+ * New API to efficiently relocate a node
+ *
+ * @since 2.0.0
+ */
+ public void move(Fqn<?> nodeToMove, Fqn<?> newParent)
+ {
+ // this needs to be passed up the interceptor chain
+ MethodCall m = MethodCallFactory.create(MethodDeclarations.moveMethodLocal, nodeToMove, newParent);
+ invokeMethod(m, true);
+ }
+
+ /**
+ * Called by reflection
+ *
+ * @param newParentFqn
+ * @param nodeToMoveFqn
+ */
+ public void _move(Fqn nodeToMoveFqn, Fqn newParentFqn)
+ {
+ // the actual move algorithm.
+ NodeSPI<K, V> newParent = findNode(newParentFqn);
+
+ if (newParent == null)
+ {
+ throw new NodeNotExistsException("New parent node " + newParentFqn + " does not exist when attempting to move node!!");
+ }
+
+ NodeSPI<K, V> node = findNode(nodeToMoveFqn);
+
+ if (node == null)
+ {
+ throw new NodeNotExistsException("Node " + nodeToMoveFqn + " does not exist when attempting to move node!!");
+ }
+
+ NodeSPI oldParent = node.getParent();
+ Object nodeName = nodeToMoveFqn.getLastElement();
+
+ // now that we have the parent and target nodes:
+ // first correct the pointers at the pruning point
+ oldParent.removeChildDirect(nodeName);
+ newParent.addChild(nodeName, node);
+ InvocationContext ctx = getInvocationContext();
+ // parent pointer is calculated on the fly using Fqns.
+ boolean isRollback = checkIsRollingBack(ctx.getTransaction());
+
+ // notify
+ if (!isRollback)
+ notifier.notifyNodeMoved(nodeToMoveFqn, new Fqn(newParentFqn, nodeToMoveFqn.getLastElement()), true, ctx);
+
+ // now adjust Fqns of node and all children.
+ moveFqns(node, newParent.getFqn());
+
+ if (!isRollback)
+ notifier.notifyNodeMoved(nodeToMoveFqn, new Fqn(newParentFqn, nodeToMoveFqn.getLastElement()), false, ctx);
+
+ // now register an undo op
+ if (ctx.getTransaction() != null)
+ {
+ MethodCall undo = MethodCallFactory.create(MethodDeclarations.moveMethodLocal, new Fqn(newParentFqn, nodeToMoveFqn.getLastElement()), oldParent.getFqn());
+ tx_table.addUndoOperation(ctx.getGlobalTransaction(), undo);
+ }
+ }
+
+ public void _block()
+ {
+ //intentionally empty, used only for reflection in MethodDeclarations.blockChannelLocal
+ }
+
+ public void _unblock()
+ {
+ //intentionally empty, used only for reflection in MethodDeclarations.unblockChannelLocal
+ }
+
+ private void moveFqns(NodeSPI node, Fqn newBase)
+ {
+ Fqn newFqn = new Fqn(newBase, node.getFqn().getLastElement());
+ node.setFqn(newFqn);
+ }
+
+ /**
+ * Set our log category to include our clusterName, if we have one.
+ */
+ private void configureLogCategory()
+ {
+ StringBuffer category = new StringBuffer(getClass().getName());
+ if (configuration != null)
+ {
+ String clusterName = configuration.getClusterName();
+ if (clusterName != null)
+ {
+ category.append('.');
+ category.append(clusterName);
+ }
+ }
+
+ log = LogFactory.getLog(category.toString());
+ }
+
+ /**
+ * Kills the JGroups channel; an unclean channel disconnect
+ */
+ public void killChannel()
+ {
+ if (channel != null)
+ {
+ channel.close();
+ channel.disconnect();
+ }
+ }
+
+ protected class MessageListenerAdaptor implements ExtendedMessageListener
+ {
+ /**
+ * Reference to an exception that was raised during
+ * state installation on this node.
+ */
+ protected volatile Exception setStateException;
+ private final Object stateLock = new Object();
+
+ protected MessageListenerAdaptor()
+ {
+ }
+
+ public void waitForState() throws Exception
+ {
+ synchronized (stateLock)
+ {
+ while (!isStateSet)
+ {
+ if (setStateException != null)
+ {
+ throw setStateException;
+ }
+
+ try
+ {
+ stateLock.wait();
+ }
+ catch (InterruptedException iex)
+ {
+ }
+ }
+ }
+ }
+
+ protected void stateReceivedSuccess()
+ {
+ isStateSet = true;
+ setStateException = null;
+ }
+
+ protected void stateReceivingFailed(Throwable t)
+ {
+ if (t instanceof CacheException)
+ {
+ log.debug(t);
+ }
+ else
+ {
+ log.error("failed setting state", t);
+ }
+ if (t instanceof Exception)
+ {
+ setStateException = (Exception) t;
+ }
+ else
+ {
+ setStateException = new Exception(t);
+ }
+ }
+
+ protected void stateProducingFailed(Throwable t)
+ {
+ if (t instanceof CacheException)
+ {
+ log.debug(t);
+ }
+ else
+ {
+ log.error("Caught " + t.getClass().getName()
+ + " while responding to state transfer request", t);
+ }
+ }
+
+ /**
+ * Callback, does nothing.
+ */
+ public void receive(Message msg)
+ {
+ }
+
+ public byte[] getState()
+ {
+ MarshalledValueOutputStream out = null;
+ byte[] result = null;
+ ExposedByteArrayOutputStream baos = new ExposedByteArrayOutputStream(16 * 1024);
+ try
+ {
+ out = new MarshalledValueOutputStream(baos);
+
+ getStateTransferManager().getState(out, Fqn.ROOT, configuration.getStateRetrievalTimeout(), true, true);
+ }
+ catch (Throwable t)
+ {
+ stateProducingFailed(t);
+ }
+ finally
+ {
+ result = baos.getRawBuffer();
+ Util.close(out);
+ }
+ return result;
+ }
+
+ public void setState(byte[] new_state)
+ {
+ if (new_state == null)
+ {
+ log.debug("transferred state is null (may be first member in cluster)");
+ return;
+ }
+ ByteArrayInputStream bais = new ByteArrayInputStream(new_state);
+ MarshalledValueInputStream in = null;
+ try
+ {
+ in = new MarshalledValueInputStream(bais);
+ getStateTransferManager().setState(in, Fqn.ROOT);
+ stateReceivedSuccess();
+ }
+ catch (Throwable t)
+ {
+ stateReceivingFailed(t);
+ }
+ finally
+ {
+ Util.close(in);
+ synchronized (stateLock)
+ {
+ // Notify wait that state has been set.
+ stateLock.notifyAll();
+ }
+ }
+ }
+
+ public byte[] getState(String state_id)
+ {
+ MarshalledValueOutputStream out = null;
+ String sourceRoot = state_id;
+ byte[] result = null;
+
+ boolean hasDifferentSourceAndIntegrationRoots = state_id.indexOf(StateTransferManager.PARTIAL_STATE_DELIMITER) > 0;
+ if (hasDifferentSourceAndIntegrationRoots)
+ {
+ sourceRoot = state_id.split(StateTransferManager.PARTIAL_STATE_DELIMITER)[0];
+ }
+
+ ExposedByteArrayOutputStream baos = new ExposedByteArrayOutputStream(16 * 1024);
+ try
+ {
+ out = new MarshalledValueOutputStream(baos);
+
+ getStateTransferManager().getState(out, Fqn.fromString(sourceRoot),
+ configuration.getStateRetrievalTimeout(), true, true);
+ }
+ catch (Throwable t)
+ {
+ stateProducingFailed(t);
+ }
+ finally
+ {
+ result = baos.getRawBuffer();
+ Util.close(out);
+ }
+ return result;
+ }
+
+ public void getState(OutputStream ostream)
+ {
+ MarshalledValueOutputStream out = null;
+ try
+ {
+ out = new MarshalledValueOutputStream(ostream);
+ getStateTransferManager().getState(out, Fqn.ROOT, configuration.getStateRetrievalTimeout(), true, true);
+ }
+ catch (Throwable t)
+ {
+ stateProducingFailed(t);
+ }
+ finally
+ {
+ Util.close(out);
+ }
+ }
+
+ public void getState(String state_id, OutputStream ostream)
+ {
+ String sourceRoot = state_id;
+ MarshalledValueOutputStream out = null;
+ boolean hasDifferentSourceAndIntegrationRoots = state_id.indexOf(StateTransferManager.PARTIAL_STATE_DELIMITER) > 0;
+ if (hasDifferentSourceAndIntegrationRoots)
+ {
+ sourceRoot = state_id.split(StateTransferManager.PARTIAL_STATE_DELIMITER)[0];
+ }
+ try
+ {
+ out = new MarshalledValueOutputStream(ostream);
+ getStateTransferManager().getState(out, Fqn.fromString(sourceRoot), configuration.getStateRetrievalTimeout(), true, true);
+ }
+ catch (Throwable t)
+ {
+ stateProducingFailed(t);
+ }
+ finally
+ {
+ Util.close(out);
+ }
+ }
+
+ public void setState(InputStream istream)
+ {
+ if (istream == null)
+ {
+ log.debug("stream is null (may be first member in cluster)");
+ return;
+ }
+ MarshalledValueInputStream in = null;
+ try
+ {
+ in = new MarshalledValueInputStream(istream);
+ getStateTransferManager().setState(in, Fqn.ROOT);
+ stateReceivedSuccess();
+ }
+ catch (Throwable t)
+ {
+ stateReceivingFailed(t);
+ }
+ finally
+ {
+ Util.close(in);
+ synchronized (stateLock)
+ {
+ // Notify wait that state has been set.
+ stateLock.notifyAll();
+ }
+ }
+ }
+
+ public void setState(String state_id, byte[] state)
+ {
+ if (state == null)
+ {
+ log.debug("partial transferred state is null");
+ return;
+ }
+
+ MarshalledValueInputStream in = null;
+ String targetRoot = state_id;
+ boolean hasDifferentSourceAndIntegrationRoots = state_id.indexOf(StateTransferManager.PARTIAL_STATE_DELIMITER) > 0;
+ if (hasDifferentSourceAndIntegrationRoots)
+ {
+ targetRoot = state_id.split(StateTransferManager.PARTIAL_STATE_DELIMITER)[1];
+ }
+ try
+ {
+ log.debug("Setting received partial state for subroot " + state_id);
+ Fqn subroot = Fqn.fromString(targetRoot);
+// Region region = regionManager.getRegion(subroot, false);
+// ClassLoader cl = null;
+// if (region != null)
+// {
+// // If a classloader is registered for the node's region, use it
+// cl = region.getClassLoader();
+// }
+ ByteArrayInputStream bais = new ByteArrayInputStream(state);
+ in = new MarshalledValueInputStream(bais);
+ //getStateTransferManager().setState(in, subroot, cl);
+ getStateTransferManager().setState(in, subroot);
+ stateReceivedSuccess();
+ }
+ catch (Throwable t)
+ {
+ stateReceivingFailed(t);
+ }
+ finally
+ {
+ Util.close(in);
+ synchronized (stateLock)
+ {
+ // Notify wait that state has been set.
+ stateLock.notifyAll();
+ }
+ }
+ }
+
+ public void setState(String state_id, InputStream istream)
+ {
+ String targetRoot = state_id;
+ MarshalledValueInputStream in = null;
+ boolean hasDifferentSourceAndIntegrationRoots = state_id.indexOf(StateTransferManager.PARTIAL_STATE_DELIMITER) > 0;
+ if (hasDifferentSourceAndIntegrationRoots)
+ {
+ targetRoot = state_id.split(StateTransferManager.PARTIAL_STATE_DELIMITER)[1];
+ }
+ if (istream == null)
+ {
+ log.debug("stream is null (may be first member in cluster). State is not set");
+ return;
+ }
+
+ try
+ {
+ log.debug("Setting received partial state for subroot " + state_id);
+ in = new MarshalledValueInputStream(istream);
+ Fqn subroot = Fqn.fromString(targetRoot);
+// Region region = regionManager.getRegion(subroot, false);
+// ClassLoader cl = null;
+// if (region != null)
+// {
+// // If a classloader is registered for the node's region, use it
+// cl = region.getClassLoader();
+// }
+ //getStateTransferManager().setState(in, subroot, cl);
+ getStateTransferManager().setState(in, subroot);
+ stateReceivedSuccess();
+ }
+ catch (Throwable t)
+ {
+ stateReceivingFailed(t);
+ }
+ finally
+ {
+ Util.close(in);
+ synchronized (stateLock)
+ {
+ // Notify wait that state has been set.
+ stateLock.notifyAll();
+ }
+ }
+ }
+ }
+
+ /*-------------------- End of MessageListener ----------------------*/
+
+ /*----------------------- MembershipListener ------------------------*/
+
+ protected class MembershipListenerAdaptor implements ExtendedMembershipListener
+ {
+
+ public void viewAccepted(View new_view)
+ {
+ Vector<Address> new_mbrs = new_view.getMembers();
+ if (log.isInfoEnabled()) log.info("viewAccepted(): " + new_view);
+ synchronized (members)
+ {
+ boolean needNotification = false;
+ if (new_mbrs != null)
+ {
+ // Determine what members have been removed
+ // and roll back any tx and break any locks
+ Vector<Address> removed = new Vector<Address>(members);
+ removed.removeAll(new_mbrs);
+ removeLocksForDeadMembers(root, removed);
+
+ members.removeAllElements();
+ members.addAll(new_mbrs);
+
+ needNotification = true;
+ }
+
+ // Now that we have a view, figure out if we are the coordinator
+ coordinator = (members.size() != 0 && members.get(0).equals(getLocalAddress()));
+
+ // now notify listeners - *after* updating the coordinator. - JBCACHE-662
+ if (needNotification && notifier != null)
+ {
+ InvocationContext ctx = getInvocationContext();
+ notifier.notifyViewChange(new_view, ctx);
+ }
+
+ // Wake up any threads that are waiting to know who the members
+ // are so they can figure out who the coordinator is
+ members.notifyAll();
+ }
+ }
+
+ /**
+ * Called when a member is suspected.
+ */
+ public void suspect(Address suspected_mbr)
+ {
+ }
+
+ /**
+ * Indicates that a channel has received a BLOCK event from FLUSH protocol.
+ */
+ public void block()
+ {
+ flushBlockGate.close();
+ if (log.isDebugEnabled())
+ {
+ log.debug("Block received at " + getLocalAddress());
+ }
+ MethodCall m = MethodCallFactory.create(MethodDeclarations.blockChannelLocal);
+ getInvocationContext().getOptionOverrides().setSkipCacheStatusCheck(true);
+ invokeMethod(m, true);
+ if (log.isDebugEnabled())
+ {
+ log.debug("Block processed at " + getLocalAddress());
+ }
+ }
+
+ /**
+ * Indicates that a channel has received a UNBLOCK event from FLUSH protocol.
+ */
+ public void unblock()
+ {
+ if (log.isDebugEnabled())
+ {
+ log.debug("UnBlock received at " + getLocalAddress());
+ }
+ MethodCall m = MethodCallFactory.create(MethodDeclarations.unblockChannelLocal);
+ getInvocationContext().getOptionOverrides().setSkipCacheStatusCheck(true);
+ invokeMethod(m, true);
+ if (log.isDebugEnabled())
+ {
+ log.debug("UnBlock processed at " + getLocalAddress());
+ }
+ flushBlockGate.open();
+ }
+
+ }
+
+ /*------------------- End of MembershipListener ----------------------*/
+
+ /* ------------------------------ Private methods --------------------------- */
+
+ /**
+ * Returns the transaction associated with the current thread. We get the
+ * initial context and a reference to the TransactionManager to get the
+ * transaction. This method is used by {@link #getCurrentTransaction()}
+ */
+ protected Transaction getLocalTransaction()
+ {
+ if (tm == null)
+ {
+ return null;
+ }
+ try
+ {
+ return tm.getTransaction();
+ }
+ catch (Throwable t)
+ {
+ return null;
+ }
+ }
+
+
+ /**
+ * Returns true if transaction is ACTIVE or PREPARING, false otherwise.
+ */
+ private boolean isValid(Transaction tx)
+ {
+ if (tx == null) return false;
+ int status = -1;
+ try
+ {
+ status = tx.getStatus();
+ return status == Status.STATUS_ACTIVE || status == Status.STATUS_PREPARING;
+ }
+ catch (SystemException e)
+ {
+ log.error("failed getting transaction status", e);
+ return false;
+ }
+ }
+
+
+ /**
+ * Returns the transaction associated with the current thread.
+ * If a local transaction exists, but doesn't yet have a mapping to a
+ * GlobalTransaction, a new GlobalTransaction will be created and mapped to
+ * the local transaction. Note that if a local transaction exists, but is
+ * not ACTIVE or PREPARING, null is returned.
+ *
+ * @return A GlobalTransaction, or null if no (local) transaction was associated with the current thread
+ */
+ public GlobalTransaction getCurrentTransaction()
+ {
+ return getCurrentTransaction(true);
+ }
+
+ /**
+ * Returns the transaction associated with the thread; optionally creating
+ * it if is does not exist.
+ */
+ public GlobalTransaction getCurrentTransaction(boolean createIfNotExists)
+ {
+ Transaction tx;
+
+ if ((tx = getLocalTransaction()) == null)
+ {// no transaction is associated with the current thread
+ return null;
+ }
+
+ if (!isValid(tx))
+ {// we got a non-null transaction, but it is not active anymore
+ int status = -1;
+ try
+ {
+ status = tx.getStatus();
+ }
+ catch (SystemException e)
+ {
+ }
+
+ // JBCACHE-982 -- don't complain if COMMITTED
+ if (status != Status.STATUS_COMMITTED)
+ {
+ log.warn("status is " + status + " (not ACTIVE or PREPARING); returning null)", new Throwable());
+ }
+ else
+ {
+ log.trace("status is COMMITTED; returning null");
+ }
+
+ return null;
+ }
+
+ return getCurrentTransaction(tx, createIfNotExists);
+ }
+
+ /**
+ * Returns the global transaction for this local transaction.
+ */
+ public GlobalTransaction getCurrentTransaction(Transaction tx)
+ {
+ return getCurrentTransaction(tx, true);
+ }
+
+ /**
+ * Returns the global transaction for this local transaction.
+ *
+ * @param createIfNotExists if true, if a global transaction is not found; one is created
+ */
+ public GlobalTransaction getCurrentTransaction(Transaction tx, boolean createIfNotExists)
+ {
+ // removed synchronization on tx_table because underlying implementation is thread safe
+ // and JTA spec (section 3.4.3 Thread of Control, par 2) says that only one thread may
+ // operate on the transaction at one time so no concern about 2 threads trying to call
+ // this method for the same Transaction instance at the same time
+ //
+ GlobalTransaction gtx = tx_table.get(tx);
+ if (gtx == null && createIfNotExists)
+ {
+ Address addr = getLocalAddress();
+ gtx = GlobalTransaction.create(addr);
+ tx_table.put(tx, gtx);
+ TransactionEntry ent = configuration.isNodeLockingOptimistic() ? new OptimisticTransactionEntry() : new TransactionEntry();
+ ent.setTransaction(tx);
+ tx_table.put(gtx, ent);
+ if (log.isTraceEnabled())
+ {
+ log.trace("created new GTX: " + gtx + ", local TX=" + tx);
+ }
+ }
+ return gtx;
+ }
+
+
+ /**
+ * Invokes a method against this object. Contains the logger_ic for handling
+ * the various use cases, e.g. mode (local, repl_async, repl_sync),
+ * transaction (yes or no) and locking (yes or no).
+ * <p/>
+ * Only sets originLocal on the invocation context IF this is explicitly passed in as <tt>false</tt>
+ * If passed in as <tt>true</tt> then it is not set; but whatever default exists in the invocation
+ * context is used. For example, it may be set prior to calling invokeMethod()
+ */
+ protected Object invokeMethod(MethodCall m, boolean originLocal) throws CacheException
+ {
+ // don't create a new one; get it from ThreadLocal just this once, in case a user has added any overrides.
+ InvocationContext ctx = getInvocationContext();
+
+ // BR methods should NOT block on the cache being started, since the cache depends on these completing to start.
+ if (!MethodDeclarations.isBuddyGroupOrganisationMethod(m.getMethodId()) && !cacheStatus.allowInvocations() && !ctx.getOptionOverrides().isSkipCacheStatusCheck())
+ throw new IllegalStateException("Cache not in STARTED state!");
+
+ MethodCall oldCall = null;
+ try
+ {
+ // check if we had a method call lurking around
+ oldCall = ctx.getMethodCall();
+ ctx.setMethodCall(m);
+ // only set this if originLocal is EXPLICITLY passed in as FALSE. Otherwise leave it as a default.
+ if (!originLocal) ctx.setOriginLocal(false);
+ return interceptor_chain.invoke(ctx);
+ }
+ catch (CacheException e)
+ {
+ throw e;
+ }
+ catch (RuntimeException e)
+ {
+ throw e;
+ }
+ catch (Throwable t)
+ {
+ throw new RuntimeException(t);
+ }
+ finally
+ {
+ if (!originLocal) ctx.setOriginLocal(true);
+ // reset old method call
+ ctx.setMethodCall(oldCall);
+ }
+ }
+
+ /**
+ * Returns an object suitable for use in node locking, either the current
+ * transaction or the current thread if there is no transaction.
+ */
+ protected Object getOwnerForLock()
+ {
+ Object owner = getCurrentTransaction();
+ if (owner == null)
+ {
+ owner = Thread.currentThread();
+ }
+
+ return owner;
+ }
+
+ /**
+ * Finds a node given a fully qualified name.
+ * Whenever nodes are created, and the global transaction is not null, the created
+ * nodes have to be added to the transaction's {@link TransactionEntry}
+ * field.<br>
+ * When a lock is acquired on a node, a reference to the lock has to be
+ * {@link TransactionEntry#addLock(org.jboss.cache.lock.NodeLock) added to the list of locked nodes}
+ * in the {@link TransactionEntry}.
+ * <p>This operation will also apply different locking to the cache nodes, depending on
+ * <tt>operation_type</tt>. If it is <tt>read</tt> type, all nodes will be acquired with
+ * read lock. Otherwise, the operation is <tt>write</tt> type, all parent nodes will be acquired
+ * with read lock while the destination node acquires write lock.</p>
+ *
+ * @param fqn Fully qualified name for the corresponding node.
+ * @return DataNode
+ */
+ public NodeSPI<K, V> findNode(Fqn fqn)
+ {
+ try
+ {
+ return findNode(fqn, null);
+ }
+ catch (CacheException e)
+ {
+ log.warn("Unexpected error", e);
+ return null;
+ }
+ }
+
+ private NodeSPI<K, V> findNodeCheck(GlobalTransaction tx, Fqn fqn)
+ {
+ NodeSPI<K, V> n = findNode(fqn);
+ if (n == null)
+ {
+ String errStr = "node " + fqn + " not found (gtx=" + tx + ", caller=" + Thread.currentThread() + ")";
+ if (log.isTraceEnabled())
+ {
+ log.trace(errStr);
+ }
+ throw new NodeNotExistsException(errStr);
+ }
+ return n;
+ }
+
+ /**
+ * Internal method; not to be used externally.
+ * Returns true if the node was found, false if not.
+ *
+ * @param f
+ */
+ public boolean realRemove(Fqn f, boolean skipMarkerCheck)
+ {
+ NodeSPI n = peek(f, true);
+ if (n == null)
+ {
+ return false;
+ }
+
+ if (log.isTraceEnabled()) log.trace("Performing a real remove for node " + f + ", marked for removal.");
+ if (skipMarkerCheck || n.isDeleted())
+ {
+ if (n.getFqn().isRoot())
+ {
+ // do not actually delete; just remove deletion marker
+ n.markAsDeleted(true);
+ // but now remove all children, since the call has been to remove("/")
+ n.removeChildrenDirect();
+ return true;
+ }
+ else
+ {
+ return n.getParent().removeChildDirect(n.getFqn().getLastElement());
+ }
+ }
+ else
+ {
+ if (log.isDebugEnabled()) log.debug("Node " + f + " NOT marked for removal as expected, not removing!");
+ return false;
+ }
+ }
+
+ /**
+ * Finds a node given a fully qualified name and DataVersion.
+ */
+ private NodeSPI<K, V> findNode(Fqn fqn, DataVersion version) throws CacheException
+ {
+ if (fqn == null) return null;
+
+ NodeSPI<K, V> toReturn = peek(fqn, false);
+
+ if (version != null && configuration.isNodeLockingOptimistic())
+ {
+ // we need to check the version of the data node...
+ DataVersion nodeVersion = toReturn.getVersion();
+ if (log.isTraceEnabled())
+ {
+ log.trace("looking for optimistic node [" + fqn + "] with version [" + version + "]. My version is [" + nodeVersion + "]");
+ }
+ if (nodeVersion.newerThan(version))
+ {
+ // we have a versioning problem; throw an exception!
+ throw new CacheException("Unable to validate versions.");
+ }
+ }
+ return toReturn;
+ }
+
+ public synchronized RegionManager getRegionManager()
+ {
+ if (regionManager == null)
+ {
+ regionManager = new RegionManager(this);
+ }
+ return regionManager;
+ }
+
+
+ public Marshaller getMarshaller()
+ {
+ if (marshaller_ == null)
+ {
+ synchronized (this)
+ {
+ if (marshaller_ == null)
+ {
+ if (configuration.getMarshallerClass() == null || configuration.getMarshallerClass().equals(VersionAwareMarshaller.class.getName()))
+ {
+ marshaller_ = new VersionAwareMarshaller(getRegionManager(), configuration);
+ }
+ else
+ {
+ try
+ {
+ marshaller_ = (Marshaller) org.jboss.cache.util.Util.loadClass(configuration.getMarshallerClass()).newInstance();
+ }
+ catch (Exception e)
+ {
+ log.error("Unable to load marshaller " + configuration.getMarshallerClass() + ". Falling back to default (" + VersionAwareMarshaller.class.getName() + ")");
+ marshaller_ = new VersionAwareMarshaller(getRegionManager(), configuration);
+ }
+ }
+ if (log.isTraceEnabled()) log.trace("Using marshaller " + marshaller_.getClass().getName());
+ }
+ }
+ }
+ return marshaller_;
+ }
+
+ /**
+ * Returns the default JGroup properties.
+ * Subclasses may wish to override this method.
+ */
+ protected String getDefaultProperties()
+ {
+ return "UDP(mcast_addr=224.0.0.36;mcast_port=55566;ip_ttl=32;" +
+ "mcast_send_buf_size=150000;mcast_recv_buf_size=80000):" +
+ "PING(timeout=1000;num_initial_members=2):" +
+ "MERGE2(min_interval=5000;max_interval=10000):" +
+ "FD_SOCK:" +
+ "VERIFY_SUSPECT(timeout=1500):" +
+ "pbcast.NAKACK(gc_lag=50;max_xmit_size=8192;retransmit_timeout=600,1200,2400,4800):" +
+ "UNICAST(timeout=600,1200,2400,4800):" +
+ "pbcast.STABLE(desired_avg_gossip=20000):" +
+ "FRAG(frag_size=8192;down_thread=false;up_thread=false):" +
+ "pbcast.GMS(join_timeout=5000;join_retry_timeout=2000;" +
+ "shun=false;print_local_addr=true):" +
+ "pbcast.STATE_TRANSFER";
+ }
+
+ private void initialiseCacheLoaderManager() throws CacheException
+ {
+ if (cacheLoaderManager == null)
+ {
+ cacheLoaderManager = new CacheLoaderManager();
+ }
+ cacheLoaderManager.setConfig(configuration.getCacheLoaderConfig(), this);
+ }
+
+ /**
+ * Sets the CacheLoader to use.
+ * Provided for backwards compatibility.
+ *
+ * @param loader
+ * @deprecated only provided for backward compat
+ */
+ @Deprecated
+ public void setCacheLoader(CacheLoader loader)
+ {
+ log.warn("Using deprecated config method setCacheLoader. This element will be removed in future, please use CacheLoaderConfiguration instead.");
+
+ try
+ {
+ if (cacheLoaderManager == null) initialiseCacheLoaderManager();
+ }
+ catch (Exception e)
+ {
+ log.warn("Problem setting cache loader. Perhaps your cache loader config has not been set yet?");
+ }
+ cacheLoaderManager.setCacheLoader(loader);
+ }
+
+ /**
+ * Purges the contents of all configured {@link CacheLoader}s
+ */
+ public void purgeCacheLoaders() throws Exception
+ {
+ if (cacheLoaderManager != null) cacheLoaderManager.purgeLoaders(true);
+ }
+
+ // ---------------------------------------------------------------
+ // END: Methods to provide backward compatibility with older cache loader config settings
+ // ---------------------------------------------------------------
+
+ private void initialiseChannelAndRpcDispatcher() throws CacheException
+ {
+ channel = configuration.getRuntimeConfig().getChannel();
+ if (channel == null)
+ {
+ // Try to create a multiplexer channel
+ channel = getMultiplexerChannel();
+
+ if (channel != null)
+ {
+ configuration.setUsingMultiplexer(true);
+ if (log.isDebugEnabled())
+ {
+ log.debug("Created Multiplexer Channel for cache cluster " + configuration.getClusterName() +
+ " using stack " + configuration.getMultiplexerStack());
+ }
+ }
+ else
+ {
+ if (configuration.getClusterConfig() == null)
+ {
+ log.debug("setting cluster properties to default value");
+ configuration.setClusterConfig(getDefaultProperties());
+ }
+ try
+ {
+ channel = new JChannel(configuration.getClusterConfig());
+ }
+ catch (Exception e)
+ {
+ throw new CacheException("Unable to create JGroups channel", e);
+ }
+ if (log.isTraceEnabled())
+ {
+ log.trace("cache properties: " + configuration.getClusterConfig());
+ }
+ }
+
+ configuration.getRuntimeConfig().setChannel(channel);
+ }
+
+ channel.setOpt(Channel.AUTO_RECONNECT, true);
+ channel.setOpt(Channel.AUTO_GETSTATE, true);
+ channel.setOpt(Channel.BLOCK, true);
+
+ // always use the InactiveRegionAwareRpcDispatcher - exceptions due to regions not being active should not propagate to remote
+ // nodes as errors. - Manik
+ disp = new InactiveRegionAwareRpcDispatcher(channel, ml, new MembershipListenerAdaptor(), this);
+ // disp = new RpcDispatcher(channel, ml, this, this);
+
+ disp.setRequestMarshaller(getMarshaller());
+ disp.setResponseMarshaller(getMarshaller());
+ }
+
+ private JChannel getMultiplexerChannel() throws CacheException
+ {
+ String stackName = configuration.getMultiplexerStack();
+
+ RuntimeConfig rtc = configuration.getRuntimeConfig();
+ ChannelFactory channelFactory = rtc.getMuxChannelFactory();
+ JChannel muxchannel = null;
+
+ if (channelFactory != null)
+ {
+ try
+ {
+ muxchannel = (JChannel) channelFactory.createMultiplexerChannel(stackName, configuration.getClusterName());
+ }
+ catch (Exception e)
+ {
+ throw new CacheException("Failed to create multiplexed channel using stack " + stackName, e);
+ }
+ }
+
+ return muxchannel;
+ }
+
+ // ================== methods to implement Cache and CacheSPI interfaces ============================
+
+ public List<Interceptor> getInterceptorChain()
+ {
+ List<Interceptor> modifiable = getInterceptors();
+ return modifiable == null ? null : Collections.unmodifiableList(modifiable);
+ }
+
+ public void addCacheListener(Object listener)
+ {
+ getNotifier().addCacheListener(listener);
+ }
+
+ public void addCacheListener(Fqn<?> region, Object listener)
+ {
+ throw new UnsupportedOperationException("Not implemented in this release");
+ }
+
+ public void removeCacheListener(Object listener)
+ {
+ // BES 2007/5/23 workaround to avoid NPE while we decide whether
+ // to remove notifier in destroy()
+ Notifier n = getNotifier();
+ if (n != null)
+ n.removeCacheListener(listener);
+ }
+
+ public void removeCacheListener(Fqn<?> region, Object listener)
+ {
+ throw new UnsupportedOperationException("Not implemented in this release");
+ }
+
+ public Set<Object> getCacheListeners()
+ {
+ return getNotifier().getCacheListeners();
+ }
+
+ public Set<Object> getCacheListeners(Fqn<?> region)
+ {
+ throw new UnsupportedOperationException("Not implemented in this release");
+ }
+
+ public synchronized void addInterceptor(Interceptor i, int position)
+ {
+ List<Interceptor> interceptors = getInterceptors();
+
+ i.setCache(this);
+
+ interceptors.add(position, i);
+
+ // now correct the chaining of interceptors...
+ Interceptor linkedChain = InterceptorChainFactory.getInstance().correctInterceptorChaining(interceptors);
+
+ setInterceptorChain(linkedChain);
+ }
+
+ public synchronized void removeInterceptor(int position)
+ {
+ List<Interceptor> i = getInterceptors();
+ i.remove(position);
+ setInterceptorChain(InterceptorChainFactory.getInstance().correctInterceptorChaining(i));
+ }
+
+ public RPCManager getRPCManager()
+ {
+ return configuration.getRuntimeConfig().getRPCManager();
+ }
+
+ public String getClusterName()
+ {
+ return getConfiguration().getClusterName();
+ }
+
+ public void evict(Fqn<?> fqn, boolean recursive)
+ {
+ if (recursive)
+ {
+ Node<K, V> n = get(fqn);
+ if (n != null)
+ {
+ evictChildren((NodeSPI<K, V>) n);
+ }
+ }
+ else
+ {
+ evict(fqn);
+ }
+ }
+
+ private void evictChildren(NodeSPI<K, V> n)
+ {
+ for (NodeSPI<K, V> child : n.getChildrenDirect())
+ {
+ evictChildren(child);
+ }
+ evict(n.getFqn());
+ }
+
+ public Region getRegion(Fqn<?> fqn, boolean createIfAbsent)
+ {
+ return getRegionManager().getRegion(fqn, createIfAbsent);
+ }
+
+ public boolean removeRegion(Fqn<?> fqn)
+ {
+ return getRegionManager().removeRegion(fqn);
+ }
+
+ public boolean removeNode(Fqn<?> fqn)
+ {
+ return remove(fqn);
+ }
+
+ public void putForExternalRead(Fqn<?> fqn, K key, V value)
+ {
+ // if the node exists then this should be a no-op.
+ if (!exists(fqn))
+ {
+ getInvocationContext().getOptionOverrides().setFailSilently(true);
+ GlobalTransaction tx = getCurrentTransaction();
+ MethodCall m = MethodCallFactory.create(MethodDeclarations.putForExternalReadMethodLocal, tx, fqn, key, value);
+ invokeMethod(m, true);
+ }
+ else
+ {
+ if (log.isDebugEnabled())
+ log.debug("putForExternalRead() called with Fqn " + fqn + " and this node already exists. This method is hence a no op.");
+ }
+ }
+
+ public void _putForExternalRead(GlobalTransaction gtx, Fqn fqn, K key, V value)
+ {
+ _put(gtx, fqn, key, value, true);
+ }
+
+ public boolean isStarted()
+ {
+ return getCacheStatus() == CacheStatus.STARTED;
+ }
+
+ protected void setMessageListener(MessageListenerAdaptor ml)
+ {
+ this.ml = ml;
+ }
+
+}
Copied: core/trunk/src/main/java/org/jboss/cache/CacheSPI.java (from rev 4250, core/trunk/src-old/org/jboss/cache/CacheSPI.java)
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/CacheSPI.java (rev 0)
+++ core/trunk/src/main/java/org/jboss/cache/CacheSPI.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -0,0 +1,186 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package org.jboss.cache;
+
+import net.jcip.annotations.ThreadSafe;
+import org.jboss.cache.buddyreplication.BuddyManager;
+import org.jboss.cache.buddyreplication.GravitateResult;
+import org.jboss.cache.interceptors.Interceptor;
+import org.jboss.cache.loader.CacheLoader;
+import org.jboss.cache.loader.CacheLoaderManager;
+import org.jboss.cache.lock.NodeLock;
+import org.jboss.cache.marshall.Marshaller;
+import org.jboss.cache.notifications.Notifier;
+import org.jboss.cache.statetransfer.StateTransferManager;
+import org.jboss.cache.transaction.GlobalTransaction;
+import org.jboss.cache.transaction.TransactionTable;
+
+import javax.transaction.Transaction;
+import javax.transaction.TransactionManager;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * A more detailed interface to {@link Cache}, which is used when writing plugins for or extending JBoss Cache. A reference
+ * to this interface should only be obtained when it is passed in to your code, for example when you write an
+ * {@link Interceptor} or {@link CacheLoader}.
+ * <p/>
+ * <B><I>You should NEVER attempt to directly cast a {@link Cache} instance to this interface. In future, the implementation may not allow it.</I></B>
+ * <p/>
+ * This interface contains overridden method signatures of some methods from {@link Cache}, overridden to ensure return
+ * types of {@link Node} are replaced with {@link NodeSPI}.
+ * <p/>
+ *
+ * @author <a href="mailto:manik at jboss.org">Manik Surtani (manik at jboss.org)</a>
+ * @see NodeSPI
+ * @see Cache
+ * @see org.jboss.cache.loader.CacheLoader
+ * @see org.jboss.cache.interceptors.Interceptor
+ * @since 2.0.0
+ */
+ at ThreadSafe
+public interface CacheSPI<K, V> extends Cache<K, V>
+{
+ /**
+ * Overrides {@link org.jboss.cache.Cache#getRoot()} to return a {@link org.jboss.cache.NodeSPI} instead of a {@link org.jboss.cache.Node}.
+ */
+ NodeSPI<K, V> getRoot();
+
+ /**
+ * Retrieves a reference to a running {@link javax.transaction.TransactionManager}, if one is configured.
+ *
+ * @return a TransactionManager
+ */
+ TransactionManager getTransactionManager();
+
+ /**
+ * @return an immutable {@link List} of {@link Interceptor}s configured for this cache, or
+ * <code>null</code> if {@link Cache#create() create()} has not been invoked
+ * and the interceptors thus do not exist.
+ */
+ List<Interceptor> getInterceptorChain();
+
+ /**
+ * Adds a custom interceptor to the interceptor chain, at specified position, where the first interceptor in the chain
+ * is at position 0 and the last one at getInterceptorChain().size() - 1.
+ *
+ * @param i the interceptor to add
+ * @param position the position to add the interceptor
+ */
+ void addInterceptor(Interceptor i, int position);
+
+ /**
+ * Removes the interceptor at a specified position, where the first interceptor in the chain
+ * is at position 0 and the last one at getInterceptorChain().size() - 1.
+ *
+ * @param position the position at which to remove an interceptor
+ */
+ void removeInterceptor(int position);
+
+ /**
+ * @return Retrieves a reference to the currently configured {@link org.jboss.cache.loader.CacheLoaderManager} if one or more cache loaders are configured, null otherwise.
+ */
+ CacheLoaderManager getCacheLoaderManager();
+
+ /**
+ * @return an instance of {@link BuddyManager} if buddy replication is enabled, null otherwise.
+ */
+ BuddyManager getBuddyManager();
+
+ /**
+ * @return the current {@link TransactionTable}
+ */
+ TransactionTable getTransactionTable();
+
+ /**
+ * Gets a handle of the RPC manager.
+ *
+ * @return the {@link org.jboss.cache.RPCManager} configured.
+ */
+ RPCManager getRPCManager();
+
+ /**
+ * @return the current {@link org.jboss.cache.statetransfer.StateTransferManager}
+ */
+ StateTransferManager getStateTransferManager();
+
+ /**
+ * @return the name of the cluster. Null if running in local mode.
+ */
+ String getClusterName();
+
+ /**
+ * @return the number of attributes in the cache.
+ */
+ int getNumberOfAttributes();
+
+ /**
+ * @return the number of nodes in the cache.
+ */
+ int getNumberOfNodes();
+
+ /**
+ * Retrieves the current table of locks.
+ *
+ * @return lock table.
+ */
+ Map<Thread, List<NodeLock>> getLockTable();
+
+ /**
+ * @return the {@link org.jboss.cache.RegionManager}
+ */
+ RegionManager getRegionManager();
+
+ /**
+ * Returns the global transaction for this local transaction.
+ * Optionally creates a new global transaction if it does not exist.
+ *
+ * @param tx the current transaction
+ * @param createIfNotExists if true creates a new transaction if none exists
+ * @return a GlobalTransaction
+ */
+ GlobalTransaction getCurrentTransaction(Transaction tx, boolean createIfNotExists);
+
+ /**
+ * @return the notifier attached with this instance of the cache. See {@link Notifier}, a class
+ * that is responsible for emitting notifications to registered CacheListeners.
+ */
+ Notifier getNotifier();
+
+ /**
+ * Returns a node without accessing the interceptor chain.
+ *
+ * @param fqn the Fqn to look up.
+ * @param includeDeletedNodes if you intend to see nodes marked as deleted within the current tx, set this to true
+ * @return a node if one exists or null
+ */
+ NodeSPI<K, V> peek(Fqn<?> fqn, boolean includeDeletedNodes);
+
+ /**
+ * Used with buddy replication's data gravitation interceptor. If marshalling is necessary, ensure that the cache is
+ * configured to use {@link org.jboss.cache.config.Configuration#useRegionBasedMarshalling} and the {@link org.jboss.cache.Region}
+ * pertaining to the Fqn passed in is activated, and has an appropriate ClassLoader.
+ *
+ * @param fqn the fqn to gravitate
+ * @param searchBuddyBackupSubtrees if true, buddy backup subtrees are searched and if false, they are not.
+ * @return a GravitateResult which contains the data for the gravitation
+ */
+ GravitateResult gravitateData(Fqn<?> fqn, boolean searchBuddyBackupSubtrees);
+
+ /**
+ * Retrieves an instance of a {@link Marshaller}, which is capable of
+ * converting Java objects to bytestreams and back in an efficient manner, which is
+ * also interoperable with bytestreams produced/consumed by other versions of JBoss
+ * Cache.
+ * <p/>
+ * The use of this marshaller is the <b>recommended</b> way of creating efficient,
+ * compatible, byte streams from objects.
+ *
+ * @return an instance of {@link Marshaller}
+ */
+ Marshaller getMarshaller();
+}
Copied: core/trunk/src/main/java/org/jboss/cache/CacheStatus.java (from rev 4250, core/trunk/src-old/org/jboss/cache/CacheStatus.java)
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/CacheStatus.java (rev 0)
+++ core/trunk/src/main/java/org/jboss/cache/CacheStatus.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -0,0 +1,224 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2006, 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 org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Various states that an object that has a four stage lifecycle
+ * (i.e. <code>create()</code>, <code>start()</code>, <code>stop()</code>
+ * and <code>destroy()</code>) might be in.
+ *
+ * @author <a href="brian.stansberry at jboss.com">Brian Stansberry</a>
+ * @version $Revision$
+ */
+public enum CacheStatus
+{
+ /**
+ * Object has been instantiated, but create() has not been called.
+ */
+ INSTANTIATED,
+ /**
+ * The <code>create()</code> method has been called but not yet completed.
+ */
+ CREATING,
+ /**
+ * The <code>create()</code> method has been completed but
+ * <code>start()</code> has not been called.
+ */
+ CREATED,
+ /**
+ * The <code>start()</code> method has been called but has not yet completed.
+ */
+ STARTING,
+ /**
+ * The <code>start()</code> method has completed.
+ */
+ STARTED,
+ /**
+ * The <code>stop()</code> method has been called but has not yet completed.
+ */
+ STOPPING,
+ /**
+ * The <code>stop()</code> method has completed but <code>destroy()</code>
+ * has not yet been called. Conceptually equivalent to {@link #CREATED}.
+ */
+ STOPPED,
+ /**
+ * The <code>destroy()</code> method has been called but has not yet completed.
+ */
+ DESTROYING,
+ /**
+ * The <code>destroy()</code> method has completed.
+ * Conceptually equivalent to {@link #INSTANTIATED}.
+ */
+ DESTROYED,
+ /**
+ * A failure occurred during the execution of <code>create()</code>,
+ * <code>start()</code>, <code>stop()</code> or <code>destroy()</code>.
+ * The next logical transition is to call <code>destroy()</code>.
+ */
+ FAILED;
+
+ private static final Log log = LogFactory.getLog(CacheStatus.class);
+
+ public boolean createAllowed()
+ {
+ switch (this)
+ {
+ case CREATING:
+ case CREATED:
+ case STARTING:
+ case STARTED:
+ case STOPPED:
+ log.debug("Ignoring call to create() as current state is " + this);
+ // fall through
+ case FAILED:
+ return false;
+ case STOPPING:
+ case DESTROYING:
+ log.warn("Ignoring call to create() while cache is " + this);
+ return false;
+ case INSTANTIATED:
+ case DESTROYED:
+ default:
+ return true;
+ }
+ }
+
+ public boolean needToDestroyFailedCache()
+ {
+ if (this == CacheStatus.FAILED)
+ {
+ log.debug("need to call destroy() since current state is " +
+ this);
+ return true;
+ }
+
+ return false;
+ }
+
+ public boolean startAllowed()
+ {
+ switch (this)
+ {
+ case INSTANTIATED:
+ case DESTROYED:
+ case STARTING:
+ case STARTED:
+ log.debug("Ignoring call to start() as current state is " + this);
+ // fall through
+ case FAILED:
+ return false;
+ case STOPPING:
+ case DESTROYING:
+ log.warn("Ignoring call to start() as current state is " + this);
+ return false;
+ case CREATED:
+ case STOPPED:
+ default:
+ return true;
+ }
+ }
+
+ public boolean needCreateBeforeStart()
+ {
+ switch (this)
+ {
+ case INSTANTIATED:
+ case DESTROYED:
+ log.debug("start() called while current state is " +
+ this + " -- call create() first");
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ public boolean stopAllowed()
+ {
+ switch (this)
+ {
+ case INSTANTIATED:
+ case CREATED:
+ case STOPPED:
+ case DESTROYED:
+ log.debug("Ignoring call to stop() as current state is " + this);
+ return false;
+ case CREATING:
+ case STARTING:
+ case STOPPING:
+ case DESTROYING:
+ log.warn("Ignoring call to stop() as current state is " + this);
+ return false;
+ case FAILED:
+ case STARTED:
+ default:
+ return true;
+ }
+
+ }
+
+ public boolean destroyAllowed()
+ {
+ switch (this)
+ {
+ case INSTANTIATED:
+ case DESTROYED:
+ log.debug("Ignoring call to destroy() as current state is " + this);
+ return false;
+ case CREATING:
+ case STARTING:
+ case STOPPING:
+ case DESTROYING:
+ log.warn("Ignoring call to destroy() as current state iswhile cache is " + this);
+ return false;
+ case STARTED:
+ // stop first
+ return false;
+ case CREATED:
+ case STOPPED:
+ case FAILED:
+ default:
+ return true;
+ }
+ }
+
+ public boolean needStopBeforeDestroy()
+ {
+ if (this == CacheStatus.STARTED)
+ {
+ log.warn("destroy() called while current state is " +
+ this + " -- call stop() first");
+ return true;
+ }
+
+ return false;
+ }
+
+ public boolean allowInvocations()
+ {
+ return (this == CacheStatus.STARTED);
+ }
+}
Copied: core/trunk/src/main/java/org/jboss/cache/ConsoleListener.java (from rev 4250, core/trunk/src-old/org/jboss/cache/ConsoleListener.java)
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/ConsoleListener.java (rev 0)
+++ core/trunk/src/main/java/org/jboss/cache/ConsoleListener.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -0,0 +1,230 @@
+package org.jboss.cache;
+
+import org.jboss.cache.notifications.annotation.CacheListener;
+import org.jboss.cache.notifications.annotation.CacheStarted;
+import org.jboss.cache.notifications.annotation.CacheStopped;
+import org.jboss.cache.notifications.annotation.NodeActivated;
+import org.jboss.cache.notifications.annotation.NodeCreated;
+import org.jboss.cache.notifications.annotation.NodeEvicted;
+import org.jboss.cache.notifications.annotation.NodeLoaded;
+import org.jboss.cache.notifications.annotation.NodeModified;
+import org.jboss.cache.notifications.annotation.NodeMoved;
+import org.jboss.cache.notifications.annotation.NodePassivated;
+import org.jboss.cache.notifications.annotation.NodeRemoved;
+import org.jboss.cache.notifications.annotation.NodeVisited;
+import org.jboss.cache.notifications.annotation.ViewChanged;
+import org.jboss.cache.notifications.event.Event;
+import org.jboss.cache.notifications.event.NodeEvent;
+import org.jboss.cache.notifications.event.ViewChangedEvent;
+
+/**
+ * This class provides a non-graphical view of <em>JBossCache</em> replication
+ * events for a replicated cache.
+ * <p/>
+ * It can be utilized as a standalone application or as a component in other
+ * applications.
+ * <p/>
+ * <strong>WARNING</strong>: take care when using this class in conjunction with
+ * transactionally replicated cache's as it can cause deadlock situations due to
+ * the reading of values for nodes in the cache.
+ *
+ * @author Jimmy Wilson 12-2004
+ */
+ at CacheListener
+public class ConsoleListener
+{
+ private CacheImpl _cache;
+ private boolean _startCache;
+
+ /**
+ * Constructor.
+ * <p/>
+ * When using this constructor, this class with attempt to start and stop
+ * the specified cache.
+ *
+ * @param cache the cache to monitor for replication events.
+ */
+ public ConsoleListener(CacheImpl cache)
+ throws Exception
+ {
+ this(cache, true, true);
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param cache the cache to monitor for replication events.
+ * @param startCache indicates whether or not the cache should be started by
+ * this class.
+ * @param stopCache indicates whether or not the cache should be stopped by
+ * this class.
+ */
+ public ConsoleListener(CacheImpl cache,
+ boolean startCache, boolean stopCache)
+ throws Exception
+ {
+ _cache = cache;
+ _startCache = startCache;
+
+ if (stopCache)
+ {
+ new ListenerShutdownHook().register();
+ }
+ }
+
+ /**
+ * Instructs this class to listen for cache replication events.
+ * <p/>
+ * This method waits indefinately. Use the notify method of this class
+ * (using traditional Java thread notification semantics) to cause this
+ * method to return.
+ */
+ public void listen()
+ throws Exception
+ {
+ listen(true);
+ }
+
+ /**
+ * Instructs this class to listen for cache replication events.
+ *
+ * @param wait whether or not this method should wait indefinately.
+ * <p/>
+ * If this parameter is set to <code>true</code>, using the
+ * notify method of this class (using traditional Java thread
+ * notification semantics) will cause this method to return.
+ */
+ public void listen(boolean wait)
+ throws Exception
+ {
+ _cache.getNotifier().addCacheListener(this);
+
+ if (_startCache)
+ {
+ _cache.start();
+ }
+
+ synchronized (this)
+ {
+ while (wait)
+ {
+ wait();
+ }
+ }
+ }
+
+
+ @CacheStarted
+ @CacheStopped
+ public void printDetails(Event e)
+ {
+ printEvent("Cache started.");
+ }
+
+
+ @NodeCreated
+ @NodeLoaded
+ @NodeModified
+ @NodeRemoved
+ @NodeVisited
+ @NodeMoved
+ @NodeEvicted
+ @NodeActivated
+ @NodePassivated
+ public void printDetailsWithFqn(NodeEvent e)
+ {
+ if (e.isPre())
+ {
+ printEvent("Event " + e.getType() + " on node [" + e.getFqn() + "] about to be invoked");
+ }
+ else
+ {
+ printEvent("Event " + e.getType() + " on node [" + e.getFqn() + "] invoked");
+ }
+ }
+
+ @ViewChanged
+ public void printNewView(ViewChangedEvent e)
+ {
+ printEvent("View change: " + e.getNewView());
+ }
+
+ /**
+ * Prints an event message.
+ *
+ * @param eventSuffix the suffix of the event message.
+ */
+ private void printEvent(String eventSuffix)
+ {
+ System.out.print("EVENT");
+ System.out.print(' ');
+
+ System.out.println(eventSuffix);
+ }
+
+ /**
+ * This class provides a shutdown hook for shutting down the cache.
+ */
+ private class ListenerShutdownHook extends Thread
+ {
+ /**
+ * Registers this hook for invocation during shutdown.
+ */
+ public void register()
+ {
+ Runtime.getRuntime().addShutdownHook(this);
+ }
+
+ /*
+ * Thread overrides.
+ */
+
+ public void run()
+ {
+ _cache.stop();
+ }
+ }
+
+ /**
+ * The main method.
+ *
+ * @param args command line arguments dictated by convention.
+ * <p/>
+ * The first command line argument is the name of the
+ * <code>JBossCache</code> configuration file to be utilized
+ * for configuration of the cache. Only the name of the
+ * configuration file is necessary as it is read off of the
+ * classpath.
+ * <p/>
+ * If a configuration file is not specified on the command line,
+ * <code>jboss-cache.xml</code> will be the assumed file name.
+ * <p/>
+ * All command line arguments after the first are ignored.
+ */
+ public static void main(String[] args)
+ {
+ final String DEFAULT_CONFIG_FILE_NAME = "jboss-cache.xml";
+
+ try
+ {
+ String configFileName = DEFAULT_CONFIG_FILE_NAME;
+
+ if (args.length >= 1)
+ {
+ configFileName = args[0];
+ }
+ else
+ {
+ System.out.print("No xml config file argument is supplied. Will use jboss-cache.xml from classpath");
+ }
+
+ CacheImpl cache = (CacheImpl) DefaultCacheFactory.getInstance().createCache(configFileName);
+ ConsoleListener listener = new ConsoleListener(cache);
+ listener.listen();
+ }
+ catch (Throwable throwable)
+ {
+ throwable.printStackTrace();
+ }
+ }
+}
Copied: core/trunk/src/main/java/org/jboss/cache/DefaultCacheFactory.java (from rev 4250, core/trunk/src-old/org/jboss/cache/DefaultCacheFactory.java)
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/DefaultCacheFactory.java (rev 0)
+++ core/trunk/src/main/java/org/jboss/cache/DefaultCacheFactory.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -0,0 +1,95 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package org.jboss.cache;
+
+import org.jboss.cache.config.Configuration;
+import org.jboss.cache.config.ConfigurationException;
+import org.jboss.cache.factories.XmlConfigurationParser;
+
+/**
+ * Default (singleton) implementation of the {@link org.jboss.cache.CacheFactory} interface.
+ * Use {@link #getInstance()} to obtain an instance.
+ *
+ * @author <a href="mailto:manik at jboss.org">Manik Surtani (manik at jboss.org)</a>
+ */
+public class DefaultCacheFactory<K, V> implements CacheFactory<K, V>
+{
+ private static CacheFactory singleton = new DefaultCacheFactory();
+
+ /**
+ * @return a singleton instance of this class.
+ */
+ public static <K, V> CacheFactory<K, V> getInstance()
+ {
+ return singleton;
+ }
+
+ public Cache<K, V> createCache() throws ConfigurationException
+ {
+ return createCache(true);
+ }
+
+ public Cache<K, V> createCache(boolean start) throws ConfigurationException
+ {
+ return createCache(new Configuration(), start);
+ }
+
+ public Cache<K, V> createCache(String configFileName) throws ConfigurationException
+ {
+ return createCache(configFileName, true);
+ }
+
+ public Cache<K, V> createCache(String configFileName, boolean start) throws ConfigurationException
+ {
+ XmlConfigurationParser parser = new XmlConfigurationParser();
+ Configuration c = parser.parseFile(configFileName);
+ return createCache(c, start);
+ }
+
+ /**
+ * This implementation clones the configuration passed in before using it.
+ *
+ * @param configuration to use
+ * @return a cache
+ * @throws ConfigurationException if there are problems with the cfg
+ */
+ public Cache<K, V> createCache(Configuration configuration) throws ConfigurationException
+ {
+ return createCache(configuration, true);
+ }
+
+ /**
+ * This implementation clones the configuration passed in before using it.
+ *
+ * @param configuration to use
+ * @param start whether to start the cache
+ * @return a cache
+ * @throws ConfigurationException if there are problems with the cfg
+ */
+ public Cache<K, V> createCache(Configuration configuration, boolean start) throws ConfigurationException
+ {
+ try
+ {
+ CacheImpl<K, V> cache = new CacheImpl<K, V>();
+ cache.setConfiguration(configuration);
+ if (start) cache.start();
+ return cache;
+ }
+ catch (ConfigurationException ce)
+ {
+ throw ce;
+ }
+ catch (RuntimeException re)
+ {
+ throw re;
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(e);
+ }
+ }
+}
Copied: core/trunk/src/main/java/org/jboss/cache/Fqn.java (from rev 4250, core/trunk/src-old/org/jboss/cache/Fqn.java)
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/Fqn.java (rev 0)
+++ core/trunk/src/main/java/org/jboss/cache/Fqn.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -0,0 +1,518 @@
+/*
+ * JBoss, the OpenSource J2EE webOS
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package org.jboss.cache;
+
+
+import net.jcip.annotations.Immutable;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.StringTokenizer;
+
+/**
+ * A Fully Qualified Name (Fqn) is a list of names (typically Strings but can be any Object),
+ * which represent a path to a particular {@link Node} or sometimes a {@link Region} in a {@link Cache}.
+ * <p/>
+ * This name can be absolute (i.e., relative from the root node - {@link #ROOT}), or relative to any node in the cache. Reading the
+ * documentation on each API call that makes use of {@link org.jboss.cache.Fqn}s will tell you whether the API expects a
+ * relative or absolute Fqn.
+ * <p/>
+ * For instance, using this class to fetch a particular node might look like
+ * this. (Here data on "Joe" is kept under the "Smith" surname node, under
+ * the "people" tree.)
+ * <pre>
+ * Fqn<String> abc = Fqn.fromString("/people/Smith/Joe/");
+ * Node joesmith = Cache.getRoot().getChild(abc);
+ * </pre>
+ * Alternatively, the same Fqn could be constructed using an array:
+ * <pre>
+ * Fqn<String> abc = new Fqn<String>(new String[] { "people", "Smith", "Joe" });
+ * </pre>
+ * This is a bit more efficient to construct.
+ * <p/>
+ * <p/>
+ * Note that<br>
+ * <p/>
+ * <code>Fqn<String> f = new Fqn<String>("/a/b/c");</code>
+ * <p/>
+ * is <b>not</b> the same as
+ * <p/>
+ * <code>Fqn<String> f = Fqn.fromString("/a/b/c");</code>
+ * <p/>
+ * The former will result in a single Fqn, called "/a/b/c" which hangs directly under Fqn.ROOT.
+ * <p/>
+ * The latter will result in 3 Fqns, called "a", "b" and "c", where "c" is a child of "b", "b" is a child of "a", and "a" hangs off Fqn.ROOT.
+ * <p/>
+ * Another way to look at it is that the "/" separarator is only parsed when it forms
+ * part of a String passed in to Fqn.fromString() and not otherwise.
+ *
+ * @version $Revision$
+ */
+ at Immutable
+public class Fqn<E> implements Cloneable, Externalizable, Comparable<Fqn>
+{
+
+ /**
+ * Separator between FQN elements.
+ */
+ public static final String SEPARATOR = "/";
+ private static final long serialVersionUID = -5351930616956603651L;
+ private List<E> elements;
+ private transient int hash_code = 0;
+
+ /**
+ * Immutable root FQN.
+ */
+ public static final Fqn ROOT = new Fqn();
+ private static Log log = LogFactory.getLog(Fqn.class);
+ // a cached string representation of this Fqn, used by toString to it isn't calculated again every time.
+ private String cachedStringRep;
+
+ /**
+ * Constructs a root Fqn
+ */
+ public Fqn()
+ {
+ elements = Collections.emptyList();
+ }
+
+ /**
+ * Constructs a FQN from a list of names.
+ *
+ * @param names List of names
+ */
+ public Fqn(List<E> names)
+ {
+ // the list is unsafe - may be referenced externally
+ this(names, false);
+ }
+
+ /**
+ * If safe is false, Collections.unmodifiableList() is used to wrap the list passed in. This is an optimisation so
+ * Fqn.fromString(), probably the most frequently used factory method, doesn't end up needing to use the unmodifiableList()
+ * since it creates the list internally.
+ *
+ * @param names List of names
+ * @param safe whether this list is referenced externally (safe = false) or not (safe = true).
+ */
+ protected Fqn(List<E> names, boolean safe)
+ {
+ if (names != null)
+ {
+ // if not safe make a defensive copy
+ elements = safe ? names : new ArrayList<E>(names);
+ }
+ else
+ {
+ elements = Collections.emptyList();
+ }
+ }
+
+
+ /**
+ * Constructs a Fqn from an array of names.
+ *
+ * @param names Names that comprose this Fqn
+ */
+ public Fqn(E... names)
+ {
+ // safe - the list is created here.
+ this(Arrays.asList(names), true);
+ }
+
+ /**
+ * Constructs a Fqn from a base and relative Fqn.
+ *
+ * @param base parent Fqn
+ * @param relative Sub-Fqn relative to the parent
+ */
+ public Fqn(Fqn<E> base, Fqn<E> relative)
+ {
+ this(base, relative.elements);
+ }
+
+ /**
+ * Constructs a Fqn from a base and a list of relative names.
+ *
+ * @param base parent Fqn
+ * @param relative List of elements that identify the child Fqn, relative to the parent
+ */
+ public Fqn(Fqn<E> base, List<E> relative)
+ {
+ List<E> elements = new ArrayList<E>(base.elements.size() + relative.size());
+ elements.addAll(base.elements);
+ elements.addAll(relative);
+ this.elements = elements;
+ }
+
+ /**
+ * Constructs a Fqn from a base and two relative names.
+ *
+ * @param base parent Fqn
+ * @param childNames elements that denote the path to the Fqn, under the parent
+ */
+ public Fqn(Fqn<E> base, E... childNames)
+ {
+ List<E> elements = new ArrayList<E>(base.elements.size() + childNames.length);
+ elements.addAll(base.elements);
+ elements.addAll(Arrays.asList(childNames));
+ this.elements = elements;
+ }
+
+ /**
+ * Returns a new Fqn from a string, where the elements are deliminated by
+ * one or more separator ({@link #SEPARATOR}) characters.<br><br>
+ * Example use:<br>
+ * <pre>
+ * Fqn.fromString("/a/b/c/");
+ * </pre><br>
+ * is equivalent to:<br>
+ * <pre>
+ * new Fqn("a", "b", "c");
+ * </pre><br>
+ * but not<br>
+ * <pre>
+ * new Fqn("/a/b/c");
+ * </pre>
+ *
+ * @param stringRepresentation String representation of the Fqn
+ * @return an Fqn<String> constructed from the string representation passed in
+ * @see #Fqn(Object[])
+ */
+ public static Fqn<String> fromString(String stringRepresentation)
+ {
+ if (stringRepresentation == null)
+ {
+ return Fqn.ROOT;
+ }
+ List<String> list = new ArrayList<String>();
+ StringTokenizer tok = new StringTokenizer(stringRepresentation, SEPARATOR);
+ while (tok.hasMoreTokens()) list.add(tok.nextToken());
+ return new Fqn<String>(list, true);
+ }
+
+ /**
+ * Obtains an ancestor of the current Fqn. Literally performs <code>elements.subList(0, generation)</code>
+ * such that if
+ * <code>
+ * generation == Fqn.size()
+ * </code>
+ * then the return value is the Fqn itself (current generation), and if
+ * <code>
+ * generation == Fqn.size() - 1
+ * </code>
+ * then the return value is the same as
+ * <code>
+ * Fqn.getParent()
+ * </code>
+ * i.e., just one generation behind the current generation.
+ * <code>
+ * generation == 0
+ * </code>
+ * would return Fqn.ROOT.
+ *
+ * @param generation the generation of the ancestor to retrieve
+ * @return an ancestor of the current Fqn
+ */
+ public Fqn<E> getAncestor(int generation)
+ {
+ if (generation == 0) return Fqn.ROOT;
+ return getSubFqn(0, generation);
+ }
+
+ /**
+ * Obtains a sub-Fqn from the given Fqn. Literally performs <code>elements.subList(startIndex, endIndex)</code>
+ */
+ public Fqn<E> getSubFqn(int startIndex, int endIndex)
+ {
+ return new Fqn<E>(elements.subList(startIndex, endIndex));
+ }
+
+ /**
+ * @return the number of elements in the Fqn. The root node contains zero.
+ */
+ public int size()
+ {
+ return elements.size();
+ }
+
+ /**
+ * @param n index of the element to return
+ * @return Returns the nth element in the Fqn.
+ */
+ public E get(int n)
+ {
+ return elements.get(n);
+ }
+
+ /**
+ * @return the last element in the Fqn.
+ * @see #getLastElementAsString
+ */
+ public E getLastElement()
+ {
+ if (isRoot()) return null;
+ return elements.get(elements.size() - 1);
+ }
+
+ /**
+ * @param element element to find
+ * @return true if the Fqn contains this element, false otherwise.
+ */
+ public boolean hasElement(E element)
+ {
+ return elements.lastIndexOf(element) != -1;
+ }
+
+ /**
+ * Clones the Fqn.
+ */
+ public Fqn<E> clone() throws CloneNotSupportedException
+ {
+ try
+ {
+ return (Fqn<E>) super.clone();
+ }
+ catch (CloneNotSupportedException e)
+ {
+ log.error("Unable to clone Fqn " + this, e);
+ return null;
+ }
+ }
+
+ /**
+ * Returns true if obj is a Fqn with the same elements.
+ */
+ public boolean equals(Object obj)
+ {
+ if (this == obj)
+ {
+ return true;
+ }
+ if (!(obj instanceof Fqn))
+ {
+ return false;
+ }
+ Fqn other = (Fqn) obj;
+ return elements.equals(other.elements);
+ }
+
+ /**
+ * Returns a hash code with Fqn elements.
+ */
+ public int hashCode()
+ {
+ if (hash_code == 0)
+ {
+ hash_code = _hashCode();
+ }
+ return hash_code;
+ }
+
+ /**
+ * Returns this Fqn as a string, prefixing the first element with a {@link Fqn#SEPARATOR} and
+ * joining each subsequent element with a {@link Fqn#SEPARATOR}.
+ * If this is the root Fqn, returns {@link Fqn#SEPARATOR}.
+ * Example:
+ * <pre>
+ * new Fqn(new Object[] { "a", "b", "c" }).toString(); // "/a/b/c"
+ * Fqn.ROOT.toString(); // "/"
+ * </pre>
+ */
+ public String toString()
+ {
+ if (cachedStringRep == null)
+ {
+ if (isRoot())
+ {
+ cachedStringRep = SEPARATOR;
+ }
+ else
+ {
+ StringBuffer sb = new StringBuffer();
+ for (E element : elements)
+ {
+ sb.append(SEPARATOR).append(element);
+ }
+ cachedStringRep = sb.toString();
+ }
+ }
+ return cachedStringRep;
+ }
+
+ public void writeExternal(ObjectOutput out) throws IOException
+ {
+ out.writeShort(elements.size());
+ for (E element : elements)
+ {
+ out.writeObject(element);
+ }
+ }
+
+ public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException
+ {
+ short length = in.readShort();
+ this.elements = new ArrayList<E>(length);
+ for (int i = 0; i < length; i++)
+ {
+ elements.add((E) in.readObject());
+ }
+ }
+
+
+ /**
+ * Returns true if this Fqn is child of parentFqn.
+ * Example usage:
+ * <pre>
+ * Fqn<String> f1 = Fqn.fromString("/a/b");
+ * Fqn<String> f2 = Fqn.fromString("/a/b/c");
+ * assertTrue(f1.isChildOf(f2));
+ * assertFalse(f1.isChildOf(f1));
+ * assertFalse(f2.isChildOf(f1));
+ * </pre>
+ *
+ * @param parentFqn candidate parent to test against
+ * @return true if the target is a child of parentFqn
+ */
+ public boolean isChildOf(Fqn<E> parentFqn)
+ {
+ return parentFqn.elements.size() != elements.size() && isChildOrEquals(parentFqn);
+ }
+
+ /**
+ * Returns true if this Fqn is equals or the child of parentFqn.
+ * Example usage:
+ * <pre>
+ * Fqn<String> f1 = Fqn.fromString("/a/b");
+ * Fqn<String> f2 = Fqn.fromString("/a/b/c");
+ * assertTrue(f1.isChildOrEquals(f2));
+ * assertTrue(f1.isChildOrEquals(f1));
+ * assertFalse(f2.isChildOrEquals(f1));
+ * </pre>
+ *
+ * @param parentFqn candidate parent to test against
+ * @return true if this Fqn is equals or the child of parentFqn.
+ */
+ public boolean isChildOrEquals(Fqn<E> parentFqn)
+ {
+ List<E> parentList = parentFqn.elements;
+ if (parentList.size() > elements.size())
+ {
+ return false;
+ }
+ for (int i = parentList.size() - 1; i >= 0; i--)
+ {
+ if (!parentList.get(i).equals(elements.get(i)))
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Calculates a hash code by summing the hash code of all elements.
+ *
+ * @return a cached hashcode
+ */
+ private int _hashCode()
+ {
+ int hashCode = 0;
+ int count = 1;
+ Object o;
+ for (E element : elements)
+ {
+ o = element;
+ hashCode += (o == null) ? 0 : o.hashCode() * count++;
+ }
+ if (hashCode == 0)// fix degenerate case
+ {
+ hashCode = 0xFEED;
+ }
+ return hashCode;
+ }
+
+ /**
+ * Returns the parent of this Fqn.
+ * The parent of the root node is {@link #ROOT}.
+ * Examples:
+ * <pre>
+ * Fqn<String> f1 = Fqn.fromString("/a");
+ * Fqn<String> f2 = Fqn.fromString("/a/b");
+ * assertEquals(f1, f2.getParent());
+ * assertEquals(Fqn.ROOT, f1.getParent().getParent());
+ * assertEquals(Fqn.ROOT, Fqn.ROOT.getParent());
+ * </pre>
+ *
+ * @return the parent Fqn
+ */
+ public Fqn<E> getParent()
+ {
+ switch (elements.size())
+ {
+ case 0:
+ case 1:
+ return ROOT;
+ default:
+ return new Fqn<E>(elements.subList(0, elements.size() - 1));
+ }
+ }
+
+ /**
+ * Returns true if this is a root Fqn.
+ *
+ * @return true if the Fqn is Fqn.ROOT.
+ */
+ public boolean isRoot()
+ {
+ return elements.isEmpty();
+ }
+
+ /**
+ * If this is the root, returns {@link Fqn#SEPARATOR}.
+ *
+ * @return a String representation of the last element that makes up this Fqn.
+ */
+ public String getLastElementAsString()
+ {
+ if (isRoot())
+ {
+ return SEPARATOR;
+ }
+ else
+ {
+ return String.valueOf(getLastElement());
+ }
+ }
+
+ /**
+ * Peeks into the elements that build up this Fqn. The list returned is
+ * read-only, to maintain the immutable nature of Fqn.
+ *
+ * @return an unmodifiable list
+ */
+ public List<E> peekElements()
+ {
+ return elements;
+ }
+
+ /**
+ * Compares this Fqn to another using {@link FqnComparator}.
+ */
+ public int compareTo(Fqn Fqn)
+ {
+ return FqnComparator.INSTANCE.compare(this, Fqn);
+ }
+}
\ No newline at end of file
Copied: core/trunk/src/main/java/org/jboss/cache/FqnComparator.java (from rev 4250, core/trunk/src-old/org/jboss/cache/FqnComparator.java)
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/FqnComparator.java (rev 0)
+++ core/trunk/src/main/java/org/jboss/cache/FqnComparator.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -0,0 +1,106 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package org.jboss.cache;
+
+import net.jcip.annotations.Immutable;
+
+import java.util.Comparator;
+
+/**
+ * Compares the order of two FQN.
+ * Sorts by name, then by depth, e.g.
+ * <pre>
+ * aaa/bbb
+ * xxx
+ * xxx/ccc
+ * </pre>
+ *
+ * @author Manik Surtani (<a href="mailto:manik at jboss.org">manik at jboss.org</a>)
+ * @author Steve Woodcock (<a href="mailto:stevew at jofti.com">stevew at jofti.com</a>)
+ */
+ at Immutable
+public class FqnComparator implements Comparator<Fqn>
+{
+ public static final FqnComparator INSTANCE = new FqnComparator();
+
+ /**
+ * Sorts by name, then depth.
+ */
+ public FqnComparator()
+ {
+ }
+
+ /**
+ * Returns -1 if the first comes before; 0 if they are the same; 1 if the
+ * second Fqn comes before. <code>null</code> always comes first.
+ */
+ public int compare(Fqn fqn1, Fqn fqn2)
+ {
+ int s1 = fqn1.size();
+ int s2 = fqn2.size();
+
+ if (s1 == 0)
+ {
+ return (s2 == 0) ? 0 : -1;
+ }
+
+ if (s2 == 0)
+ {
+ return 1;
+ }
+
+ int size = Math.min(s1, s2);
+
+ for (int i = 0; i < size; i++)
+ {
+ Object e1 = fqn1.get(i);
+ Object e2 = fqn2.get(i);
+ if (e1 == e2)
+ {
+ continue;
+ }
+ if (e1 == null)
+ {
+ return 0;
+ }
+ if (e2 == null)
+ {
+ return 1;
+ }
+ if (!e1.equals(e2))
+ {
+ int c = compareElements(e1, e2);
+ if (c != 0)
+ {
+ return c;
+ }
+ }
+ }
+
+ return s1 - s2;
+ }
+
+ /**
+ * Compares two Fqn elements.
+ * If e1 and e2 are the same class and e1 implements Comparable,
+ * returns e1.compareTo(e2).
+ * Otherwise, returns e1.toString().compareTo(e2.toString()).
+ */
+ private int compareElements(Object e1, Object e2)
+ {
+ if (e1.getClass() == e2.getClass() && e1 instanceof Comparable)
+ {
+ return ((Comparable) e1).compareTo(e2);
+ }
+ else
+ {
+ return e1.toString().compareTo(e2.toString());
+ }
+ }
+
+
+}
Copied: core/trunk/src/main/java/org/jboss/cache/InvocationContext.java (from rev 4250, core/trunk/src-old/org/jboss/cache/InvocationContext.java)
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/InvocationContext.java (rev 0)
+++ core/trunk/src/main/java/org/jboss/cache/InvocationContext.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -0,0 +1,257 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package org.jboss.cache;
+
+import org.jboss.cache.config.Option;
+import org.jboss.cache.marshall.MethodCall;
+import org.jboss.cache.transaction.GlobalTransaction;
+
+import javax.transaction.Transaction;
+
+/**
+ * This context holds information specific to a method invocation.
+ *
+ * @author <a href="mailto:manik at jboss.org">Manik Surtani (manik at jboss.org)</a>
+ */
+public class InvocationContext implements Cloneable
+{
+ private Transaction transaction;
+ private GlobalTransaction globalTransaction;
+ private Option optionOverrides;
+ // defaults to true.
+ private boolean originLocal = true;
+ private boolean txHasMods;
+ private boolean localRollbackOnly;
+ private MethodCall methodCall;
+
+ InvocationContext()
+ {
+ }
+
+ public void setLocalRollbackOnly(boolean localRollbackOnly)
+ {
+ this.localRollbackOnly = localRollbackOnly;
+ }
+
+
+ /**
+ * Retrieves the transaction associated with this invocation
+ *
+ * @return The transaction associated with this invocation
+ */
+ public Transaction getTransaction()
+ {
+ return transaction;
+ }
+
+ /**
+ * Sets the transaction associated with this invocation
+ *
+ * @param transaction
+ */
+ public void setTransaction(Transaction transaction)
+ {
+ this.transaction = transaction;
+ }
+
+ /**
+ * Retrieves the global transaction associated with this invocation
+ *
+ * @return the global transaction associated with this invocation
+ */
+ public GlobalTransaction getGlobalTransaction()
+ {
+ return globalTransaction;
+ }
+
+ /**
+ * Sets the global transaction associated with this invocation
+ *
+ * @param globalTransaction
+ */
+ public void setGlobalTransaction(GlobalTransaction globalTransaction)
+ {
+ this.globalTransaction = globalTransaction;
+ }
+
+ /**
+ * Retrieves the option overrides associated with this invocation
+ *
+ * @return the option overrides associated with this invocation
+ */
+ public Option getOptionOverrides()
+ {
+ if (optionOverrides == null)
+ {
+ optionOverrides = new Option();
+ }
+ return optionOverrides;
+ }
+
+ /**
+ * Sets the option overrides associated with this invocation
+ *
+ * @param optionOverrides
+ */
+ public void setOptionOverrides(Option optionOverrides)
+ {
+ this.optionOverrides = optionOverrides;
+ }
+
+ /**
+ * Tests if this invocation originated locally or from a remote cache.
+ *
+ * @return true if the invocation originated locally.
+ */
+ public boolean isOriginLocal()
+ {
+ return originLocal;
+ }
+
+ /**
+ * If set to true, the invocation is assumed to have originated locally. If set to false,
+ * assumed to have originated from a remote cache.
+ *
+ * @param originLocal
+ */
+ public void setOriginLocal(boolean originLocal)
+ {
+ this.originLocal = originLocal;
+ }
+
+ public String toString()
+ {
+ return "InvocationContext{" +
+ "methodCall=" + methodCall +
+ "transaction=" + transaction +
+ ", globalTransaction=" + globalTransaction +
+ ", optionOverrides=" + optionOverrides +
+ ", originLocal=" + originLocal +
+ ", txHasMods=" + txHasMods +
+ '}';
+ }
+
+ public boolean isTxHasMods()
+ {
+ return txHasMods;
+ }
+
+ public void setTxHasMods(boolean b)
+ {
+ txHasMods = b;
+ }
+
+ public boolean isLocalRollbackOnly()
+ {
+ return localRollbackOnly;
+ }
+
+ /**
+ * Resets this to the defaults used when constructing an invocation context object
+ */
+ public void reset()
+ {
+ transaction = null;
+ globalTransaction = null;
+ optionOverrides = null;
+ originLocal = true;
+ txHasMods = false;
+ }
+
+ public InvocationContext clone() throws CloneNotSupportedException
+ {
+ InvocationContext clone = (InvocationContext) super.clone();
+ clone.setOptionOverrides(getOptionOverrides().clone());
+ return clone;
+ }
+
+ /**
+ * Sets the state of the InvocationContext based on the template context passed in
+ *
+ * @param template
+ */
+ public void setState(InvocationContext template)
+ {
+ if (template == null)
+ {
+ throw new NullPointerException("Template InvocationContext passed in to InvocationContext.setState() passed in is null");
+ }
+
+ this.setGlobalTransaction(template.getGlobalTransaction());
+ this.setLocalRollbackOnly(template.isLocalRollbackOnly());
+ this.setOptionOverrides(template.getOptionOverrides());
+ this.setOriginLocal(template.isOriginLocal());
+ this.setTransaction(template.getTransaction());
+ this.setTxHasMods(template.isTxHasMods());
+ }
+
+ public boolean equals(Object o)
+ {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+
+ final InvocationContext that = (InvocationContext) o;
+
+ if (localRollbackOnly != that.localRollbackOnly) return false;
+ if (originLocal != that.originLocal) return false;
+ if (txHasMods != that.txHasMods) return false;
+ if (globalTransaction != null ? !globalTransaction.equals(that.globalTransaction) : that.globalTransaction != null)
+ {
+ return false;
+ }
+ if (optionOverrides != null ? !optionOverrides.equals(that.optionOverrides) : that.optionOverrides != null)
+ {
+ return false;
+ }
+ if (transaction != null ? !transaction.equals(that.transaction) : that.transaction != null) return false;
+
+ return true;
+ }
+
+ public int hashCode()
+ {
+ int result;
+ result = (transaction != null ? transaction.hashCode() : 0);
+ result = 29 * result + (globalTransaction != null ? globalTransaction.hashCode() : 0);
+ result = 29 * result + (optionOverrides != null ? optionOverrides.hashCode() : 0);
+ result = 29 * result + (originLocal ? 1 : 0);
+ result = 29 * result + (txHasMods ? 1 : 0);
+ result = 29 * result + (localRollbackOnly ? 1 : 0);
+ return result;
+ }
+
+ /**
+ * @return the method call associated with this invocation
+ */
+ public MethodCall getMethodCall()
+ {
+ return methodCall;
+ }
+
+ /**
+ * Sets the method call associated with this invocation.
+ *
+ * @param methodCall methodcall to set
+ */
+ public void setMethodCall(MethodCall methodCall)
+ {
+ this.methodCall = methodCall;
+ }
+
+ /**
+ * Factory method that creates a context with a given method call.
+ *
+ * @param methodCall methodcall to use
+ * @return invocation context
+ */
+ public static InvocationContext fromMethodCall(MethodCall methodCall)
+ {
+ InvocationContext ctx = new InvocationContext();
+ ctx.methodCall = methodCall;
+ return ctx;
+ }
+}
Copied: core/trunk/src/main/java/org/jboss/cache/Modification.java (from rev 4250, core/trunk/src-old/org/jboss/cache/Modification.java)
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/Modification.java (rev 0)
+++ core/trunk/src/main/java/org/jboss/cache/Modification.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -0,0 +1,290 @@
+/*
+ * JBoss, the OpenSource J2EE webOS
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package org.jboss.cache;
+
+
+import java.io.Externalizable;
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.util.Map;
+
+
+/**
+ * Represents a modification in the cache. Contains the nature of the modification
+ * (e.g. PUT, REMOVE), the fqn of the node, the new value and the previous value.
+ * A list of modifications will be sent to all nodes in a cluster when a transaction
+ * has been committed (PREPARE phase). A Modification is also used to roll back changes,
+ * e.g. since we know the previous value, we can reconstruct the previous state by
+ * applying the changes in a modification listin reverse order.
+ *
+ * @author <a href="mailto:bela at jboss.org">Bela Ban</a> Apr 12, 2003
+ * @version $Revision$
+ */
+public class Modification implements Externalizable
+{
+
+ private static final long serialVersionUID = 7463314130283897197L;
+
+ public enum ModificationType
+ {
+ PUT_KEY_VALUE,
+ PUT_DATA,
+ PUT_DATA_ERASE,
+ REMOVE_NODE,
+ REMOVE_KEY_VALUE,
+ REMOVE_DATA,
+ MOVE,
+ UNKNOWN
+ }
+
+ private ModificationType type = ModificationType.UNKNOWN;
+ private Fqn fqn = null;
+ private Fqn fqn2 = null;
+ private Object key = null;
+ private Object value = null;
+ private Object old_value = null;
+ private Map data = null;
+
+ /**
+ * Constructs a new modification.
+ */
+ public Modification()
+ {
+ }
+
+ /**
+ * Constructs a new modification with details.
+ */
+ public Modification(ModificationType type, Fqn fqn, Object key, Object value)
+ {
+ this.type = type;
+ this.fqn = fqn;
+ this.key = key;
+ this.value = value;
+ }
+
+ /**
+ * Constructs a new modification with key.
+ */
+ public Modification(ModificationType type, Fqn fqn, Object key)
+ {
+ this.type = type;
+ this.fqn = fqn;
+ this.key = key;
+ }
+
+ /**
+ * Constructs a new modification with data map.
+ */
+ public Modification(ModificationType type, Fqn fqn, Map data)
+ {
+ this.type = type;
+ this.fqn = fqn;
+ this.data = data;
+ }
+
+ /**
+ * Constructs a new modification with fqn only.
+ */
+ public Modification(ModificationType type, Fqn fqn)
+ {
+ this.type = type;
+ this.fqn = fqn;
+ }
+
+ /**
+ * Constructs a new modification with fqn only.
+ */
+ public Modification(ModificationType type, Fqn fqn1, Fqn fqn2)
+ {
+ this.type = type;
+ this.fqn = fqn1;
+ this.fqn2 = fqn2;
+ }
+
+
+ /**
+ * Returns the type of modification.
+ */
+ public ModificationType getType()
+ {
+ return type;
+ }
+
+ /**
+ * Sets the type of modification.
+ */
+ public void setType(ModificationType type)
+ {
+ this.type = type;
+ }
+
+ /**
+ * Returns the modification fqn.
+ */
+ public Fqn getFqn()
+ {
+ return fqn;
+ }
+
+ /**
+ * Sets the modification fqn.
+ */
+ public void setFqn(Fqn fqn)
+ {
+ this.fqn = fqn;
+ }
+
+ public void setFqn2(Fqn fqn2)
+ {
+ this.fqn2 = fqn2;
+ }
+
+ public Fqn getFqn2()
+ {
+ return fqn2;
+ }
+
+ /**
+ * Returns the modification key.
+ */
+ public Object getKey()
+ {
+ return key;
+ }
+
+ /**
+ * Sets the modification key.
+ */
+ public void setKey(Object key)
+ {
+ this.key = key;
+ }
+
+ /**
+ * Returns the modification value.
+ */
+ public Object getValue()
+ {
+ return value;
+ }
+
+ /**
+ * Sets the modification value.
+ */
+ public void setValue(Object value)
+ {
+ this.value = value;
+ }
+
+ /**
+ * Returns the <i>post</i> modification old value.
+ */
+ public Object getOldValue()
+ {
+ return old_value;
+ }
+
+ /**
+ * Sets the <i>post</i> modification old value.
+ */
+ public void setOldValue(Object old_value)
+ {
+ this.old_value = old_value;
+ }
+
+ /**
+ * Returns the modification Map set.
+ */
+ public Map getData()
+ {
+ return data;
+ }
+
+ /**
+ * Sets the modification Map set.
+ */
+ public void setData(Map data)
+ {
+ this.data = data;
+ }
+
+ /**
+ * Writes data to an external stream.
+ */
+ public void writeExternal(ObjectOutput out) throws IOException
+ {
+ out.writeObject(type);
+
+ out.writeBoolean(fqn != null);
+ if (fqn != null)
+ {
+ fqn.writeExternal(out);
+ }
+
+ out.writeObject(key);
+ out.writeObject(value);
+ out.writeObject(old_value);
+
+ out.writeBoolean(data != null);
+ if (data != null)
+ {
+ out.writeObject(data);
+ }
+ }
+
+ /**
+ * Reads data from an external stream.
+ */
+ public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException
+ {
+ type = (ModificationType) in.readObject();
+
+ if (in.readBoolean())
+ {
+ fqn = new Fqn();
+ fqn.readExternal(in);
+ }
+
+ key = in.readObject();
+ value = in.readObject();
+ old_value = in.readObject();
+
+ if (in.readBoolean())
+ {
+ data = (Map) in.readObject();
+ }
+ }
+
+ /**
+ * Returns debug information about this modification.
+ */
+ public String toString()
+ {
+ StringBuffer sb = new StringBuffer();
+ sb.append(type.toString()).append(": ").append(fqn);
+ if (key != null)
+ {
+ sb.append("\nkey=").append(key);
+ }
+ if (value != null)
+ {
+ sb.append("\nvalue=").append(value);
+ }
+ if (old_value != null)
+ {
+ sb.append("\nold_value=").append(old_value);
+ }
+ if (data != null)
+ {
+ sb.append("\ndata=").append(data);
+ }
+ return sb.toString();
+ }
+
+}
Copied: core/trunk/src/main/java/org/jboss/cache/Node.java (from rev 4250, core/trunk/src-old/org/jboss/cache/Node.java)
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/Node.java (rev 0)
+++ core/trunk/src/main/java/org/jboss/cache/Node.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -0,0 +1,280 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.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.
+ * <p/>
+ * 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.
+ * <p/>
+ * 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}.)
+ * <p/>
+ * 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.
+ * <p/>
+ *
+ * @author <a href="mailto:manik at jboss.org">Manik Surtani (manik at jboss.org)</a>
+ * @see Cache
+ * @since 2.0.0
+ */
+ at ThreadSafe
+public interface Node<K, V>
+{
+ /**
+ * Returns the parent node.
+ * If this is the root node, this method returns <code>null</code>.
+ *
+ * @return the parent node, or null if this is the root node
+ */
+ Node<K, V> 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<Node<K, V>> 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<Object> 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<K, V> 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<K> 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.
+ * <p/>
+ * If the child exists returns the child node anyway. Guaranteed to return a non-null node.
+ * <p/>
+ * The {@link Fqn} passed in is relative to the current node. The new child node will have an absolute fqn
+ * calculated as follows: <pre>new Fqn(getFqn(), f)</pre>. 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<K, V> addChild(Fqn<?> f);
+
+ /**
+ * Removes a child node specified by the given relative {@link Fqn}.
+ * <p/>
+ * 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<K, V> getChild(Fqn<?> f);
+
+ /**
+ * @param name name of the child
+ * @return a direct child of the current node.
+ */
+ Node<K, V> 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.
+ * <p/>
+ * Equivalent to calling
+ * <pre>
+ * if (!node.getKeys().contains(key))
+ * return node.put(key, value);
+ * else
+ * return node.get(key);
+ * </pre>
+ * <p/>
+ * 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
+ * <pre>
+ * if ((node.getKeys().contains(key))
+ * {
+ * return node.put(key, value);
+ * }
+ * else
+ * return null;
+ * </pre>
+ * <p/>
+ * 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 <tt>null</tt>
+ * 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
+ * <pre>
+ * if (node.get(key).equals(oldValue))
+ * {
+ * node.putAll(key, newValue);
+ * return true;
+ * }
+ * else
+ * return false;
+ * </pre>
+ * <p/>
+ * 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:
+ * <pre>
+ * Node node;
+ * for (Map.Entry me : map.entrySet())
+ * node.put(me.getKey(), me.getValue());
+ * </pre>
+ *
+ * @param map map to copy from
+ */
+ void putAll(Map<K, 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<K, V> map);
+
+
+ /**
+ * Returns the value to which this node maps the specified key.
+ * Returns <code>null</code> 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 <code>null</code> 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 <code>null</code> 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 <code>null</code>
+ * 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 evicted, for example,
+ * in which case it should be looked up again from the cache.
+ *
+ * @return true if the node is valid.
+ */
+ boolean isValid();
+
+}
Copied: core/trunk/src/main/java/org/jboss/cache/NodeFactory.java (from rev 4250, core/trunk/src-old/org/jboss/cache/NodeFactory.java)
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/NodeFactory.java (rev 0)
+++ core/trunk/src/main/java/org/jboss/cache/NodeFactory.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -0,0 +1,97 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package org.jboss.cache;
+
+import org.jboss.cache.optimistic.TransactionWorkspace;
+import org.jboss.cache.optimistic.WorkspaceNode;
+import org.jboss.cache.optimistic.WorkspaceNodeImpl;
+
+import java.util.Map;
+
+/**
+ * Generates new nodes based on the {@link CacheSPI} configuration.
+ *
+ * @author <a href="mailto:manik at jboss.org">Manik Surtani (manik at jboss.org)</a>
+ */
+public class NodeFactory<K, V>
+{
+ public enum NodeType
+ {
+ UNVERSIONED_NODE, VERSIONED_NODE, WORKSPACE_NODE
+ }
+
+ private CacheSPI<K, V> cache;
+ private boolean optimistic;
+
+ /**
+ * Constructs an instance of the factory
+ */
+ public NodeFactory(CacheSPI<K, V> cache)
+ {
+ this.cache = cache;
+ init();
+ }
+
+ /**
+ * Initialises the node factory with the configuration from the cache.
+ */
+ public void init()
+ {
+ optimistic = cache.getConfiguration().isNodeLockingOptimistic();
+ }
+
+
+ /**
+ * Creates a new {@link Node} instance.
+ *
+ * @param childName the new node's name
+ * @param fqn the new node's Fqn
+ * @param parent the new node's parent
+ * @param data the new node's attribute map
+ * @param mapSafe <code>true</code> if param <code>data</code> can safely
+ * be directly assigned to the new node's data field;
+ * <code>false</code> if param <code>data</code>'s contents
+ * should be copied into the new node's data field.
+ * @return the new node
+ */
+ public NodeSPI<K, V> createDataNode(Object childName, Fqn fqn, NodeSPI<K, V> parent, Map<K, V> data, boolean mapSafe)
+ {
+ NodeSPI<K, V> n = optimistic ? new VersionedNode<K, V>(fqn, parent, data, cache) : new UnversionedNode<K, V>(childName, fqn, data, mapSafe, cache);
+ // always assume that new nodes do not have data loaded
+ n.setDataLoaded(false);
+ return n;
+ }
+
+ public Node<K, V> createNode(Object childName, Node<K, V> parent, Map<K, V> data)
+ {
+ return createNodeOfType(parent, childName, parent, data);
+ }
+
+ public Node<K, V> createNodeOfType(Node<K, V> template, Object childName, Node<K, V> parent, Map<K, V> data)
+ {
+ if (template instanceof WorkspaceNode)
+ {
+ NodeSPI<K, V> dataNodeParent = ((WorkspaceNode<K, V>) parent).getNode();
+ TransactionWorkspace workspace = ((WorkspaceNode) template).getTransactionWorkspace();
+ return createWorkspaceNode(dataNodeParent, workspace);
+ }
+
+ // not a workspace node.
+ return createDataNode(childName, new Fqn(parent.getFqn(), childName), (NodeSPI<K, V>) parent, data, false);
+ }
+
+ public WorkspaceNode<K, V> createWorkspaceNode(NodeSPI<K, V> dataNode, TransactionWorkspace workspace)
+ {
+ return new WorkspaceNodeImpl<K, V>(dataNode, workspace);
+ }
+
+ public NodeSPI<K, V> createRootDataNode()
+ {
+ return createDataNode(null, Fqn.ROOT, null, null, false);
+ }
+
+}
Copied: core/trunk/src/main/java/org/jboss/cache/NodeNotExistsException.java (from rev 4250, core/trunk/src-old/org/jboss/cache/NodeNotExistsException.java)
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/NodeNotExistsException.java (rev 0)
+++ core/trunk/src/main/java/org/jboss/cache/NodeNotExistsException.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -0,0 +1,42 @@
+// $Id$
+
+/*
+ * JBoss, the OpenSource J2EE webOS
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+
+package org.jboss.cache;
+
+
+
+
+/**
+ * Thrown when an operation is attempted on a non-existing node in the cache
+ *
+ * @author <a href="mailto:bela at jboss.com">Bela Ban</a>.
+ * @version $Id$
+ */
+
+public class NodeNotExistsException extends CacheException {
+
+ private static final long serialVersionUID = 779376138690777440L;
+
+ public NodeNotExistsException() {
+ super();
+ }
+
+
+ public NodeNotExistsException(String msg) {
+ super(msg);
+ }
+
+
+ public NodeNotExistsException(String msg, Throwable cause) {
+ super(msg, cause);
+ }
+
+
+
+}
Copied: core/trunk/src/main/java/org/jboss/cache/NodeSPI.java (from rev 4250, core/trunk/src-old/org/jboss/cache/NodeSPI.java)
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/NodeSPI.java (rev 0)
+++ core/trunk/src/main/java/org/jboss/cache/NodeSPI.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -0,0 +1,440 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package org.jboss.cache;
+
+import net.jcip.annotations.NotThreadSafe;
+import org.jboss.cache.lock.NodeLock;
+import org.jboss.cache.optimistic.DataVersion;
+import org.jboss.cache.transaction.GlobalTransaction;
+
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * A more detailed interface to {@link Node}, which is used when writing plugins for or extending JBoss Cache. References are usually
+ * obtained by calling methods on {@link org.jboss.cache.CacheSPI}.
+ * <p/>
+ * <B><I>You should NEVER attempt to directly cast a {@link Node} instance to this interface. In future, the implementation may not allow it.</I></B>
+ * <p/>
+ * This interface contains overridden method signatures of some methods from {@link Node}, overridden to ensure return
+ * types of {@link Node} are replaced with {@link NodeSPI}.
+ * <p/>
+ * <b><i>An important note</i></b> on the xxxDirect() methods below. These methods are counterparts to similarly named
+ * methods in {@link Node} - e.g., {@link NodeSPI#getDirect(Object)} is a direct access counterpart to {@link Node#get(Object)},
+ * the difference being that:
+ * <p/>
+ * <ul>
+ * <li>{@link Node#get(Object)} - Passes the call up the interceptor stack, applies all aspects including node locking, cache loading, passivation, etc etc.</li>
+ * <li>{@link NodeSPI#getDirect(Object)} - directly works on the underlying data in the node.</li>
+ * </ul>
+ * <p/>
+ * The big difference with the direct access methods are that it is the onus of the caller to ensure proper locks are obtained
+ * prior to the call. A proper call should have gone through a locking-capable interceptor first and based on the cache
+ * configuration's locking policy, an appropriate lock should be obtained prior to the call. These direct access methods will
+ * throw {@link org.jboss.cache.lock.LockingException}s if appropriate locks haven't been obtained by the caller.
+ * <p/>
+ * It is important to node that the direct <b>read</b> methods, such as getDataDirect(), return unmodifiable collections.
+ * In addition to being unmodifiable, they are also defensively copied from the underlying data map to ensure view consistency.
+ * <p/>
+ *
+ * @author <a href="mailto:manik at jboss.org">Manik Surtani (manik at jboss.org)</a>
+ * @see Node
+ * @see org.jboss.cache.CacheSPI
+ * @since 2.0.0
+ */
+ at NotThreadSafe
+public interface NodeSPI<K, V> extends Node<K, V>
+{
+ /**
+ * Returns true if the children of this node were loaded from a cache loader.
+ *
+ * @return true if the children of this node were loaded from a cache loader.
+ */
+ boolean isChildrenLoaded();
+
+ /**
+ * Sets if the children of this node were loaded from a cache loader.
+ *
+ * @param loaded true if loaded, false otherwise
+ */
+ void setChildrenLoaded(boolean loaded);
+
+ /**
+ * Returns true if the data was loaded from the cache loader.
+ *
+ * @return true if the data was loaded from the cache loader.
+ */
+ public boolean isDataLoaded();
+
+ /**
+ * Sets if the data was loaded from the cache loader.
+ *
+ * @param dataLoaded true if loaded, false otherwise
+ */
+ public void setDataLoaded(boolean dataLoaded);
+
+ /**
+ * Returns a map to access the raw children.
+ * This method may return a null if the node does not have any children. It is important to note that this method
+ * returns a direct reference to the underlying child map and is intended for internal use only. Incorrect use
+ * may result in very inconsistent state of the cache.
+ *
+ * @return Map, keyed by child name, values Nodes.
+ */
+ Map<Object, Node<K, V>> getChildrenMapDirect();
+
+ /**
+ * Sets the node's children explictly.
+ * This method will remove all children currently associated with this node and add all the children passed in.
+ *
+ * @param children cannot be null
+ */
+ void setChildrenMapDirect(Map<Object, Node<K, V>> children);
+
+ /**
+ * Returns an existing child or creates a new one using a global transaction.
+ *
+ * @param name name of child to create
+ * @param tx transaction under which to create child
+ * @return newly created node
+ */
+ NodeSPI<K, V> getOrCreateChild(Object name, GlobalTransaction tx);
+
+ /**
+ * Returns a lock for this node.
+ *
+ * @return node lock
+ */
+ NodeLock getLock();
+
+ /**
+ * Sets the FQN of this node and resets the names of all children as well.
+ *
+ * @param f fqn to set
+ */
+ void setFqn(Fqn<?> f);
+
+ /**
+ * Returns true if the instance has been deleted in the current transaction.
+ *
+ * @return true if the instance has been deleted in the current transaction.
+ */
+ boolean isDeleted();
+
+ /**
+ * Marks the node as being deleted (or not) in the current transaction. This is not recursive, child nodes are not affected.
+ *
+ * @param marker true if the node has been deleted, false if not.
+ */
+ void markAsDeleted(boolean marker);
+
+ /**
+ * Same as {@link #markAsDeleted(boolean)} except that the option to recurse into children is provided.
+ *
+ * @param marker true if the node has been deleted, false if not.
+ * @param recursive if true, child nodes (and their children) are marked as well.
+ */
+ void markAsDeleted(boolean marker, boolean recursive);
+
+ /**
+ * Adds or replaces a child by name.
+ *
+ * @param nodeName child node name (not an FQN)
+ * @param nodeToAdd child node
+ */
+ void addChild(Object nodeName, Node<K, V> nodeToAdd);
+
+ /**
+ * Prints details of this node to the StringBuffer passed in.
+ *
+ * @param sb StringBuffer to print to
+ * @param indent depth of this node in the tree. Used to indent details by prepending spaces.
+ */
+ void printDetails(StringBuffer sb, int indent);
+
+ /**
+ * Prints basic information of this node to the StringBuffer passed in.
+ *
+ * @param sb StringBuffer to print to
+ * @param indent depth of this node in the tree. Used to indent details by prepending spaces.
+ */
+
+ void print(StringBuffer sb, int indent);
+
+ // versioning
+ /**
+ * Sets the data version of this node if versioning is supported.
+ *
+ * @param version data version to apply
+ * @throws UnsupportedOperationException if versioning is not supported
+ */
+ void setVersion(DataVersion version);
+
+ /**
+ * Returns the data version of this node if versioning is supported.
+ *
+ * @return data version
+ * @throws UnsupportedOperationException if versioning is not supported
+ */
+ DataVersion getVersion();
+
+
+ // ------- these XXXDirect() methods work directly on the node and bypass the interceptor chain.
+ /**
+ * Functionally the same as {@link #getChildren()} except that it operates directly on the node and bypasses the
+ * interceptor chain.
+ * <p/>
+ * The caller needs to ensure a proper lock has been obtained prior to calling this method, otherwise a
+ * {@link org.jboss.cache.lock.LockingException} will be thrown.
+ * <p/>
+ *
+ * @return set of child nodes.
+ * @see #getChildren()
+ */
+ Set<NodeSPI<K, V>> getChildrenDirect();
+
+ /**
+ * Directly removes all children for this node.
+ * The only direct method that does not have a non-direct counterpart.
+ */
+ void removeChildrenDirect();
+
+ /**
+ * Retrieves children (directly), optionally including any marked as deleted nodes.
+ * <p/>
+ * The caller needs to ensure a proper lock has been obtained prior to calling this method.
+ *
+ * @param includeMarkedAsDeleted if true, the returned set will include nodes marked as deleted
+ * @return a set of nodes
+ * @throws org.jboss.cache.lock.LockingException
+ * if locking was not obtained
+ */
+ Set<NodeSPI<K, V>> getChildrenDirect(boolean includeMarkedAsDeleted);
+
+ /**
+ * Retrives a child directly by name.
+ * Functionally the same as {@link #getChild(Object)} except that it bypasses the
+ * interceptor chain.
+ * <p/>
+ * The caller needs to ensure a proper lock has been obtained prior to calling this method.
+ *
+ * @param childName name of child
+ * @return child node
+ * @throws org.jboss.cache.lock.LockingException
+ * if locking was not obtained
+ * @see #getChild(Object)
+ */
+ NodeSPI<K, V> getChildDirect(Object childName);
+
+ /**
+ * Adds a child directly to a Node.
+ * Functionally the same as {@link #addChild(Fqn)} except that it bypasses the
+ * interceptor chain.
+ * <p/>
+ * The caller needs to ensure a proper lock has been obtained prior to calling this method.
+ *
+ * @param childName name of child
+ * @return child node
+ * @throws org.jboss.cache.lock.LockingException
+ * if locking was not obtained
+ * @see #addChild(Fqn)
+ */
+ NodeSPI<K, V> addChildDirect(Fqn childName);
+
+ /**
+ * Directly adds the node passed in to the children map of the current node. Will throw a CacheException if
+ * <tt>child.getFqn().getParent().equals(getFqn())</tt> returns false.
+ *
+ * @param child child to add
+ */
+ void addChildDirect(NodeSPI<K, V> child);
+
+ /**
+ * Retrives a child directly by fully qualified name.
+ * Functionally the same as {@link #getChild(Fqn)} except that it bypasses the
+ * interceptor chain.
+ * <p/>
+ * The caller needs to ensure a proper lock has been obtained prior to calling this method.
+ *
+ * @param childName name of child
+ * @return child node
+ * @throws org.jboss.cache.lock.LockingException
+ * if locking was not obtained
+ * @see #getChild(Fqn)
+ */
+ NodeSPI<K, V> getChildDirect(Fqn childName);
+
+ /**
+ * Removes a child directly from a node.
+ * Functionally the same as {@link #removeChild(Fqn)} except that it bypasses the
+ * interceptor chain.
+ * <p/>
+ * The caller needs to ensure a proper lock has been obtained prior to calling this method, otherwise a
+ *
+ * @param fqn of child.
+ * @return true if the node was found, false otherwise
+ * @throws org.jboss.cache.lock.LockingException
+ * if locking was not obtained
+ * @see #removeChild(Fqn)
+ */
+ boolean removeChildDirect(Fqn fqn);
+
+ /**
+ * Removes a child directly from a node.
+ * Functionally the same as {@link #removeChild(Object)} except that bypasses the
+ * interceptor chain.
+ * <p/>
+ * The caller needs to ensure a proper lock has been obtained prior to calling this method.
+ *
+ * @param childName of child.
+ * @return true if the node was found, false otherwise
+ * @throws org.jboss.cache.lock.LockingException
+ * if locking was not obtained
+ * @see #removeChild(Object)
+ */
+ boolean removeChildDirect(Object childName);
+
+
+ /**
+ * Removes a data key directly from a node.
+ * Functionally the same as {@link #remove(Object)} except that it bypasses the
+ * interceptor chain.
+ * <p/>
+ * The caller needs to ensure a proper lock has been obtained prior to calling this method.
+ *
+ * @param key to remove
+ * @return the old data contained under the key
+ * @throws org.jboss.cache.lock.LockingException
+ * if locking was not obtained
+ * @see #remove(Object)
+ */
+ V removeDirect(K key);
+
+ /**
+ * Functionally the same as {@link #put(Object,Object)} except that it operates directly on the node and bypasses the
+ * interceptor chain.
+ * <p/>
+ * The caller needs to ensure a proper lock has been obtained prior to calling this method, otherwise a
+ * {@link org.jboss.cache.lock.LockingException} will be thrown.
+ * <p/>
+ *
+ * @param key of data
+ * @param value of data
+ * @return the previous value under the key passed in, or <tt>null</tt>
+ * @see #put(Object,Object)
+ */
+ V putDirect(K key, V value);
+
+ /**
+ * Functionally the same as {@link #putAll(Map)} except that it operates directly on the node and bypasses the
+ * interceptor chain.
+ * <p/>
+ * The caller needs to ensure a proper lock has been obtained prior to calling this method, otherwise a
+ * {@link org.jboss.cache.lock.LockingException} will be thrown.
+ * <p/>
+ *
+ * @param data to put
+ * @see #putAll(Map)
+ */
+ void putAllDirect(Map<K, V> data);
+
+ /**
+ * Functionally the same as {@link #getData()} except that it operates directly on the node and bypasses the
+ * interceptor chain.
+ * <p/>
+ * Note that this returns a reference to access the node's data.
+ * This data should only be modified by the cache itself.
+ * This method should never return null.
+ * <p/>
+ * Also note that this method returns an unmodifiable reference to the underlying data map.
+ * <p/>
+ * The caller needs to ensure a proper lock has been obtained prior to calling this method, otherwise a
+ * {@link org.jboss.cache.lock.LockingException} will be thrown.
+ * <p/>
+ *
+ * @return map containing data
+ * @see #getData()
+ */
+ Map<K, V> getDataDirect();
+
+ /**
+ * Functionally the same as {@link #get(Object)} except that it operates directly on the node and bypasses the
+ * interceptor chain.
+ * <p/>
+ * The caller needs to ensure a proper lock has been obtained prior to calling this method, otherwise a
+ * {@link org.jboss.cache.lock.LockingException} will be thrown.
+ * <p/>
+ *
+ * @param key data to get
+ * @return value under key
+ * @see #get(Object)
+ */
+ V getDirect(K key);
+
+
+ /**
+ * Functionally the same as {@link #clearData()} except that it operates directly on the node and bypasses the
+ * interceptor chain.
+ * <p/>
+ * The caller needs to ensure a proper lock has been obtained prior to calling this method, otherwise a
+ * {@link org.jboss.cache.lock.LockingException} will be thrown.
+ * <p/>
+ *
+ * @see #clearData()
+ */
+ void clearDataDirect();
+
+
+ /**
+ * Functionally the same as {@link #getKeys()} except that it operates directly on the node and bypasses the
+ * interceptor chain.
+ * <p/>
+ * The caller needs to ensure a proper lock has been obtained prior to calling this method, otherwise a
+ * {@link org.jboss.cache.lock.LockingException} will be thrown.
+ * <p/>
+ *
+ * @return set of keys
+ * @see #getKeys()
+ */
+ Set<K> getKeysDirect();
+
+ /**
+ * Functionally the same as {@link #getChildrenNames()} except that it operates directly on the node and bypasses the
+ * interceptor chain.
+ * <p/>
+ * The caller needs to ensure a proper lock has been obtained prior to calling this method, otherwise a
+ * {@link org.jboss.cache.lock.LockingException} will be thrown.
+ * <p/>
+ *
+ * @return set of children names
+ * @see #getChildrenNames()
+ */
+ Set<Object> getChildrenNamesDirect();
+
+ /**
+ * Retrieves a reference to the cache in which this Node resides.
+ *
+ * @return a cache
+ */
+ CacheSPI<K, V> getCache();
+
+ // ----------- these methods override their corresponding methods in Node, so that the return types are NodeSPI rather than Node.
+
+ /**
+ * Returns the parent node as a {@link NodeSPI}, instead
+ * of {@link Node} from {@link Node#getParent()}, and is otherwise identical.
+ *
+ * @return parent node
+ * @see Node#getParent()
+ */
+ NodeSPI<K, V> getParent();
+
+ /**
+ * @return true if the node has one or more child nodes; false otherwise.
+ */
+ boolean hasChildrenDirect();
+}
Copied: core/trunk/src/main/java/org/jboss/cache/RPCManager.java (from rev 4250, core/trunk/src-old/org/jboss/cache/RPCManager.java)
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/RPCManager.java (rev 0)
+++ core/trunk/src/main/java/org/jboss/cache/RPCManager.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -0,0 +1,27 @@
+package org.jboss.cache;
+
+import org.jboss.cache.marshall.MethodCall;
+import org.jgroups.Address;
+
+import java.lang.reflect.Method;
+import java.util.List;
+
+public interface RPCManager
+{
+ public List callRemoteMethods(List<Address> recipients, MethodCall methodCall, int mode, boolean excludeSelf, long timeout) throws Exception;
+
+ public boolean isCoordinator();
+
+ public Address getCoordinator();
+
+ public List callRemoteMethods(List<Address> recipients, MethodCall methodCall, boolean synchronous, boolean excludeSelf, int timeout) throws Exception;
+
+ public List callRemoteMethods(List<Address> recipients, Method method, Object[] arguments, boolean synchronous, boolean excludeSelf, long timeout) throws Exception;
+
+ public void setCache(CacheSPI c);
+
+ /**
+ * @return Returns the replication queue (if one is used), null otherwise.
+ */
+ public ReplicationQueue getReplicationQueue();
+}
Copied: core/trunk/src/main/java/org/jboss/cache/RPCManagerImpl.java (from rev 4250, core/trunk/src-old/org/jboss/cache/RPCManagerImpl.java)
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/RPCManagerImpl.java (rev 0)
+++ core/trunk/src/main/java/org/jboss/cache/RPCManagerImpl.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -0,0 +1,75 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package org.jboss.cache;
+
+import org.jboss.cache.marshall.MethodCall;
+import org.jgroups.Address;
+
+import java.lang.reflect.Method;
+import java.util.List;
+
+/**
+ * Manager that handles all RPC calls between JBoss Cache instances
+ *
+ * @author <a href="mailto:manik at jboss.org">Manik Surtani (manik at jboss.org)</a>
+ */
+public class RPCManagerImpl implements RPCManager
+{
+ private CacheImpl c;
+
+ /**
+ * Empty ctor for mock object creation/unit testing
+ */
+ public RPCManagerImpl()
+ {
+ }
+
+ public RPCManagerImpl(CacheSPI c)
+ {
+ this.c = (CacheImpl) c;
+ }
+
+ // for now, we delegate RPC calls to deprecated methods in CacheImpl.
+
+ public List callRemoteMethods(List<Address> recipients, MethodCall methodCall, int mode, boolean excludeSelf, long timeout) throws Exception
+ {
+ return c.callRemoteMethods(recipients, methodCall, mode, excludeSelf, timeout);
+ }
+
+ public boolean isCoordinator()
+ {
+ return c.isCoordinator();
+ }
+
+ public Address getCoordinator()
+ {
+ return c.getCoordinator();
+ }
+
+ public List callRemoteMethods(List<Address> recipients, MethodCall methodCall, boolean synchronous, boolean excludeSelf, int timeout) throws Exception
+ {
+ return c.callRemoteMethods(recipients, methodCall, synchronous, excludeSelf, timeout);
+ }
+
+ public List callRemoteMethods(List<Address> recipients, Method method, Object[] arguments, boolean synchronous, boolean excludeSelf, long timeout) throws Exception
+ {
+ return c.callRemoteMethods(recipients, method, arguments, synchronous, excludeSelf, timeout);
+ }
+
+ public void setCache(CacheSPI c)
+ {
+ this.c = (CacheImpl) c;
+ }
+
+ /**
+ * @return Returns the replication queue (if one is used), null otherwise.
+ */
+ public ReplicationQueue getReplicationQueue()
+ {
+ return c.getReplicationQueue();
+ }
+}
Copied: core/trunk/src/main/java/org/jboss/cache/Region.java (from rev 4250, core/trunk/src-old/org/jboss/cache/Region.java)
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/Region.java (rev 0)
+++ core/trunk/src/main/java/org/jboss/cache/Region.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -0,0 +1,189 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package org.jboss.cache;
+
+import org.jboss.cache.config.EvictionPolicyConfig;
+import org.jboss.cache.config.EvictionRegionConfig;
+import org.jboss.cache.eviction.EvictedEventNode;
+import org.jboss.cache.eviction.EvictionPolicy;
+import org.jboss.cache.eviction.LRUPolicy;
+
+/**
+ * Defines characteristics such as class loading and eviction of {@link org.jboss.cache.Node}s belonging to a Region in a {@link Cache}.
+ * A Region is described by an {@link #getFqn() Fqn} relative to the root of the cache.
+ * All nodes and child nodes of this Fqn belong to this region.
+ * <p/>
+ * If a region is to be recognised as an eviction region (region of type {@link Type#EVICTION} then
+ * it <b>must</b> have an {@link org.jboss.cache.config.EvictionPolicyConfig} set using {@link #setEvictionPolicy(org.jboss.cache.config.EvictionPolicyConfig)}.
+ * <p/>
+ * Similarly, to be recognised as a marshalling region (region of type {@link Type#MARSHALLING} then it <b>must</b> have a
+ * {@link ClassLoader} registered using {@link #registerContextClassLoader(ClassLoader)}.
+ * <p/>
+ * Note that a single region can be both an eviction and marshalling region at the same time.
+ * <p/>
+ *
+ * @author <a href="mailto:manik at jboss.org">Manik Surtani (manik at jboss.org)</a>
+ * @see org.jboss.cache.RegionManager
+ * @since 2.0.0
+ */
+public interface Region extends Comparable<Region>
+{
+
+ /**
+ * Types of regions.
+ */
+ public enum Type
+ {
+ EVICTION, MARSHALLING, ANY
+ }
+
+ /**
+ * Registers a specific {@link ClassLoader} for this region,
+ * overridding the default cache class loader.
+ *
+ * @param classLoader specific class loader
+ */
+ void registerContextClassLoader(ClassLoader classLoader);
+
+ /**
+ * Unregisters a registered {@link ClassLoader}s for this region.
+ */
+ void unregisterContextClassLoader();
+
+ /**
+ * Activates this region for replication.
+ * By default, the entire cache is activated for replication at start-up.
+ *
+ * @throws RegionNotEmptyException if the {@link Fqn} that represents this region already exists and contains data or children.
+ */
+ void activate() throws RegionNotEmptyException;
+
+ /**
+ * Activates this region for replication, but if the {@link Fqn} that represents this region already exists and
+ * either contains data or children, no state transfers take place. The region is simply marked as active in this
+ * case.
+ */
+ public void activateIfEmpty();
+
+ /**
+ * Deactivates this region from being replicated.
+ */
+ void deactivate();
+
+ /**
+ * Sets this region as active - this only marks a flag
+ * and does not actually activates or
+ * deactivates this region. Use {@link #activate()}
+ * and {@link #deactivate()} for the full process.
+ *
+ * @param b
+ */
+ void setActive(boolean b);
+
+ /**
+ * Returns true if this region has been activated.
+ *
+ * @return true if this region has been activated.
+ */
+ boolean isActive();
+
+ /**
+ * Returns the configured {@link ClassLoader} for this region.
+ *
+ * @return a ClassLoader
+ */
+ ClassLoader getClassLoader();
+
+ /**
+ * Configures an eviction policy for this region.
+ *
+ * @param evictionPolicyConfig configuration to set
+ */
+ void setEvictionPolicy(EvictionPolicyConfig evictionPolicyConfig);
+
+ /**
+ * Returns an eviction policy configuration.
+ *
+ * @return an eviction policy configuration
+ */
+ EvictionPolicyConfig getEvictionPolicyConfig();
+
+ /**
+ * Returns an eviction policy.
+ *
+ * @return an eviction policy
+ */
+ EvictionPolicy getEvictionPolicy();
+
+ /**
+ * Returns an eviction region configuration for this region.
+ *
+ * @return an eviction region configuration
+ */
+ EvictionRegionConfig getEvictionRegionConfig();
+
+ /**
+ * Clears the node event queue used for processing eviction.
+ *
+ * @see #nodeEventQueueSize()
+ */
+ void resetEvictionQueues();
+
+ /**
+ * Returns the size of the node event queue, used by the eviction thread.
+ *
+ * @return number of events
+ */
+ int nodeEventQueueSize();
+
+ /**
+ * Returns the most recent {@link org.jboss.cache.eviction.EvictedEventNode} added to the event queue by
+ * {@link #putNodeEvent(EvictedEventNode)}.
+ *
+ * @return the last {@link org.jboss.cache.eviction.EvictedEventNode}, or null if no more events exist
+ */
+ EvictedEventNode takeLastEventNode();
+
+ /**
+ * Adds an {@link org.jboss.cache.eviction.EvictedEventNode} to the internal queue for processing
+ * by the eviction thread.
+ *
+ * @param event event to add
+ */
+ void putNodeEvent(EvictedEventNode event);
+
+ /**
+ * Marks a {@link org.jboss.cache.Node} as currently in use, by adding an event to the eviction queue.
+ * If there is an {@link EvictionPolicy} associated with this region, and
+ * it respects this event (e.g., {@link LRUPolicy} does), then the {@link org.jboss.cache.Node} will not
+ * be evicted until {@link #unmarkNodeCurrentlyInUse(Fqn)} is invoked.
+ * <p/>
+ * This mechanism can be used to prevent eviction of data that the application
+ * is currently using, in the absence of any locks on the {@link org.jboss.cache.Node} where the
+ * data is stored.
+ *
+ * @param fqn Fqn of the node.
+ * @see #unmarkNodeCurrentlyInUse(Fqn)
+ */
+ void markNodeCurrentlyInUse(Fqn fqn, long timeout);
+
+ /**
+ * Adds an event to the eviction queue indicating that a node is no longer in use.
+ *
+ * @param fqn Fqn of the node.
+ * @see #markNodeCurrentlyInUse(Fqn,long)
+ */
+ void unmarkNodeCurrentlyInUse(Fqn fqn);
+
+ /**
+ * Returns the {@link org.jboss.cache.Fqn} of this region.
+ *
+ * @return the Fqn
+ */
+ Fqn getFqn();
+
+}
Copied: core/trunk/src/main/java/org/jboss/cache/RegionImpl.java (from rev 4250, core/trunk/src-old/org/jboss/cache/RegionImpl.java)
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/RegionImpl.java (rev 0)
+++ core/trunk/src/main/java/org/jboss/cache/RegionImpl.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -0,0 +1,243 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package org.jboss.cache;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.jboss.cache.config.EvictionPolicyConfig;
+import org.jboss.cache.config.EvictionRegionConfig;
+import org.jboss.cache.eviction.EvictedEventNode;
+import org.jboss.cache.eviction.EvictionPolicy;
+import org.jboss.cache.eviction.NodeEventType;
+import org.jboss.cache.util.Util;
+
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Default implementation of a {@link Region}
+ *
+ * @author <a href="mailto:manik at jboss.org">Manik Surtani (manik at jboss.org)</a>
+ */
+public class RegionImpl implements Region
+{
+ private static final Log log = LogFactory.getLog(RegionImpl.class);
+
+ private RegionManager regionManager;
+ private Fqn fqn;
+ private boolean active;
+ private ClassLoader classLoader;
+ private BlockingQueue<EvictedEventNode> nodeEventQueue = null;
+ private int capacityWarnThreshold = 0;
+ private EvictionRegionConfig configuration = new EvictionRegionConfig();
+ private EvictionPolicy policy;
+
+ /**
+ * Constructs a marshalling region from an fqn and region manager.
+ */
+ public RegionImpl(Fqn fqn, RegionManager regionManager)
+ {
+ this.fqn = fqn;
+ this.regionManager = regionManager;
+ this.active = !regionManager.isDefaultInactive();
+ }
+
+ /**
+ * Constructs an eviction region from a policy and configuration, defined by an fqn and region manager.
+ */
+ public RegionImpl(EvictionPolicy policy, EvictionRegionConfig config, Fqn fqn, RegionManager regionManager)
+ {
+ this(fqn, regionManager);
+ this.configuration = config;
+ this.policy = policy;
+ createQueue();
+ }
+
+ public void registerContextClassLoader(ClassLoader classLoader)
+ {
+ this.classLoader = classLoader;
+ }
+
+ public void unregisterContextClassLoader()
+ {
+ this.classLoader = null;
+ }
+
+ public void activate()
+ {
+ regionManager.activate(fqn);
+ active = true;
+ }
+
+ public void activateIfEmpty()
+ {
+ regionManager.activateIfEmpty(fqn);
+ active = true;
+ }
+
+ public void deactivate()
+ {
+ regionManager.deactivate(fqn);
+ active = false;
+ }
+
+ public boolean isActive()
+ {
+ return active;
+ }
+
+ public ClassLoader getClassLoader()
+ {
+ return classLoader;
+ }
+
+ public Fqn getFqn()
+ {
+ return fqn;
+ }
+
+ public void setActive(boolean b)
+ {
+ active = b;
+ }
+
+ // -------- eviction stuff -----
+
+ public void markNodeCurrentlyInUse(Fqn fqn, long timeout)
+ {
+ EvictedEventNode markUse = new EvictedEventNode(fqn, NodeEventType.MARK_IN_USE_EVENT);
+ markUse.setInUseTimeout(timeout);
+ putNodeEvent(markUse);
+ }
+
+ public void unmarkNodeCurrentlyInUse(Fqn fqn)
+ {
+ EvictedEventNode markNoUse = new EvictedEventNode(fqn, NodeEventType.UNMARK_USE_EVENT);
+ putNodeEvent(markNoUse);
+ }
+
+ public String toString()
+ {
+ return "RegionImpl{" +
+ "fqn=" + fqn +
+ "; classloader="+ classLoader +
+ "; active=" + active +
+ "; eviction=" + (getEvictionPolicy() != null) +
+ "; timerThreadRegistered=" + (getEvictionPolicy() != null && regionManager.getEvictionTimerTask().isRegionRegisteredForProcessing(this)) +
+ '}';
+ }
+
+ public int compareTo(Region other)
+ {
+ return getFqn().compareTo(other.getFqn());
+ }
+
+ public void putNodeEvent(EvictedEventNode event)
+ {
+ try
+ {
+ if (nodeEventQueue == null) createQueue();// in case the queue does not exist yet.
+ if (nodeEventQueue.size() > capacityWarnThreshold)
+ {
+ log.warn("putNodeEvent(): eviction node event queue size is at 98% threshold value of capacity: " + configuration.getEventQueueSize() +
+ " Region: " + fqn +
+ " You will need to reduce the wakeUpIntervalSeconds parameter.");
+ }
+
+ nodeEventQueue.put(event);
+ }
+ catch (InterruptedException e)
+ {
+ log.debug("give up put", e);
+ }
+ }
+
+ public EvictedEventNode takeLastEventNode()
+ {
+ try
+ {
+ return nodeEventQueue.poll(0, TimeUnit.SECONDS);
+ }
+ catch (InterruptedException e)
+ {
+ log.debug("trace", e);
+ }
+ return null;
+ }
+
+ public int nodeEventQueueSize()
+ {
+ return nodeEventQueue.size();
+ }
+
+ public void resetEvictionQueues()
+ {
+ nodeEventQueue.clear();
+ }
+
+ private synchronized void createQueue()
+ {
+ if (nodeEventQueue == null)
+ {
+ if (configuration == null)
+ {
+ throw new IllegalArgumentException("null eviction configuration");
+ }
+ int size = configuration.getEventQueueSize();
+ capacityWarnThreshold = (98 * size) / 100 - 100;
+ if (capacityWarnThreshold <= 0)
+ {
+ throw new RuntimeException("Capacity warn threshold used in eviction is smaller than 1.");
+ }
+ nodeEventQueue = new LinkedBlockingQueue<EvictedEventNode>(size);
+ }
+ }
+
+ public EvictionRegionConfig getEvictionRegionConfig()
+ {
+ return this.configuration;
+ }
+
+ public EvictionPolicyConfig getEvictionPolicyConfig()
+ {
+ return configuration == null ? null : configuration.getEvictionPolicyConfig();
+ }
+
+ public EvictionPolicy getEvictionPolicy()
+ {
+ return policy;
+ }
+
+ public void setEvictionPolicy(EvictionPolicyConfig evictionPolicyConfig)
+ {
+ configuration.setEvictionPolicyConfig(evictionPolicyConfig);
+ policy = createPolicy(evictionPolicyConfig.getEvictionPolicyClass());
+ regionManager.getEvictionTimerTask().addRegionToProcess(this);
+ if (nodeEventQueue == null) createQueue();
+ }
+
+ private EvictionPolicy createPolicy(String className)
+ {
+ if (className == null)
+ {
+ throw new IllegalArgumentException("null className");
+ }
+ try
+ {
+ if (log.isTraceEnabled()) log.trace("Instantiating " + className);
+ EvictionPolicy ep = (EvictionPolicy) Util.loadClass(className).newInstance();
+ ep.setCache(regionManager.getCache());
+ return ep;
+ }
+ catch (Exception e)
+ {
+ log.fatal("Unable to instantiate eviction policy class " + className, e);
+ return null;
+ }
+ }
+}
Copied: core/trunk/src/main/java/org/jboss/cache/RegionManager.java (from rev 4250, core/trunk/src-old/org/jboss/cache/RegionManager.java)
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/RegionManager.java (rev 0)
+++ core/trunk/src/main/java/org/jboss/cache/RegionManager.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -0,0 +1,819 @@
+package org.jboss.cache;
+
+import net.jcip.annotations.ThreadSafe;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.jboss.cache.buddyreplication.BuddyManager;
+import org.jboss.cache.config.ConfigurationException;
+import org.jboss.cache.config.EvictionConfig;
+import org.jboss.cache.config.EvictionRegionConfig;
+import org.jboss.cache.eviction.EvictionTimerTask;
+import org.jboss.cache.eviction.RegionNameConflictException;
+import org.jboss.cache.lock.NodeLock;
+import org.jgroups.Address;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * Manages multiple {@link Region}s for a Cache instance.
+ *
+ * @author <a href="mailto:manik at jboss.org">Manik Surtani</a>
+ * @since 2.0.0
+ */
+ at ThreadSafe
+public class RegionManager
+{
+ /**
+ * The default region used in XML configuration files when defining eviction policies. Any
+ * eviction settings bound under this 'default' Fqn is appplied to {@link org.jboss.cache.Fqn#ROOT} internally so
+ * any region that is not explicitly defined comes under the settings defined for this default.
+ */
+ public static final Fqn DEFAULT_REGION = new Fqn("_default_");
+
+ /**
+ * A registry of regions that have been defined.
+ */
+ private Map<Fqn, Region> regionsRegistry = new ConcurrentHashMap<Fqn, Region>();
+ private boolean defaultInactive;
+ private Log log = LogFactory.getLog(RegionManager.class);
+ private CacheImpl cache;
+ private boolean usingEvictions;
+ private EvictionConfig evictionConfig;
+ private EvictionTimerTask evictionTimerTask = new EvictionTimerTask();
+
+ protected final Set<Fqn> activationChangeNodes = Collections.synchronizedSet(new HashSet<Fqn>());
+
+ /**
+ * Constructs a new instance not attached to a cache.
+ */
+ public RegionManager()
+ {
+ }
+
+ /**
+ * Constructs a new instance attached to a cache.
+ */
+ public RegionManager(CacheImpl cache)
+ {
+ this.cache = cache;
+ }
+
+ /**
+ * Returns true if evictions are being processed.
+ */
+ public boolean isUsingEvictions()
+ {
+ return usingEvictions;
+ }
+
+ /**
+ * Returns true if replication is by default inactive for new {@link Region}s.
+ */
+ public boolean isDefaultInactive()
+ {
+ return defaultInactive;
+ }
+
+ /**
+ * Sets if replication for new {@link Region}s is by default inactive.
+ */
+ public void setDefaultInactive(boolean defaultInactive)
+ {
+ this.defaultInactive = defaultInactive;
+ }
+
+ /**
+ * Helper utility that checks for a {@link ClassLoader} registered for the
+ * given {@link Fqn}, and if found sets it as the TCCL. If the given Fqn is
+ * under the _BUDDY_BACKUP_ region, the equivalent region in the main
+ * cache is used to find the {@link ClassLoader}.
+ *
+ * @param fqn Fqn pointing to a region for which a special classloader
+ * may have been registered.
+ */
+ public void setContextClassLoaderAsCurrent(Fqn fqn)
+ {
+ if (fqn.isChildOf(BuddyManager.BUDDY_BACKUP_SUBTREE_FQN))
+ {
+ if (fqn.size() <= 2)
+ {
+ fqn = Fqn.ROOT;
+ }
+ else
+ {
+ fqn = fqn.getSubFqn(2, fqn.size());
+ }
+ }
+ Region region = getRegion(fqn, false);
+ ClassLoader regionCL = (region == null) ? null : region.getClassLoader();
+ if (regionCL != null)
+ {
+ Thread.currentThread().setContextClassLoader(regionCL);
+ }
+
+ }
+
+ /**
+ * Returns a region by {@link Fqn}, creating it optionally if absent. If the region does not exist and <tt>createIfAbsent</tt>
+ * is <tt>false</tt>, a parent region which may apply to the {@link Fqn} is sought.
+ */
+ public Region getRegion(Fqn fqn, boolean createIfAbsent)
+ {
+ return getRegion(fqn, Region.Type.ANY, createIfAbsent);
+ }
+
+ /**
+ * An overloaded form of {@link #getRegion(Fqn,boolean)} that takes an additional {@link org.jboss.cache.Region.Type}
+ * parameter to force regions of a specific type.
+ *
+ * @see org.jboss.cache.Region.Type
+ */
+ public Region getRegion(Fqn fqn, Region.Type type, boolean createIfAbsent)
+ {
+ Fqn fqnToUse = fqn;
+ if (DEFAULT_REGION.equals(fqnToUse)) fqnToUse = Fqn.ROOT;
+ // first see if a region for this specific Fqn exists
+ if (regionsRegistry.containsKey(fqnToUse))
+ {
+ Region r = regionsRegistry.get(fqnToUse);
+
+ // this is a very poor way of telling whether a region is a marshalling one or an eviction one. :-(
+ // mandates that class loaders be registered for marshalling regions.
+ if (type == Region.Type.ANY
+ || (type == Region.Type.MARSHALLING && r.getClassLoader() != null)
+ || (type == Region.Type.EVICTION && r.getEvictionPolicyConfig() != null))
+ {
+ return r;
+ }
+ }
+
+ // if not, attempt to create one ...
+ if (createIfAbsent)
+ {
+ Region r = new RegionImpl(fqnToUse, this);
+ regionsRegistry.put(fqnToUse, r);
+ if (type == Region.Type.MARSHALLING)
+ {
+ // insert current class loader into region so at least it is recognised as a marshalling region
+ r.registerContextClassLoader(getClass().getClassLoader());
+ }
+ return r;
+ }
+ else
+ {
+ // first test if the default region has been defined. If not, and if eviction regions
+ // are in use, throw an exception since it is required.
+ if (isUsingEvictions() && !regionsRegistry.containsKey(Fqn.ROOT))
+ {
+ throw new RuntimeException("No default eviction region defined!");
+ }
+ }
+
+ // else try and find a parent which has a defined region, may return null if nothing is defined.
+ Region nextBestThing = null;
+ Fqn nextFqn = fqnToUse;
+
+ while (nextBestThing == null)
+ {
+ nextFqn = nextFqn.getParent();
+ if (regionsRegistry.containsKey(nextFqn))
+ {
+ Region r = regionsRegistry.get(nextFqn);
+
+ // this is a very poor way of telling whether a region is a marshalling one or an eviction one. :-(
+ // mandates that class loaders be registered for marshalling regions.
+ if (type == Region.Type.ANY
+ || (type == Region.Type.MARSHALLING && r.getClassLoader() != null)
+ || (type == Region.Type.EVICTION && r.getEvictionPolicyConfig() != null))
+ {
+ nextBestThing = r;
+ }
+ }
+ if (nextFqn.isRoot()) break;
+ }
+
+ return nextBestThing;
+ }
+
+ /**
+ * Returns a region using Fqn.fromString(fqn), calling {@link #getRegion(Fqn,boolean)}
+ *
+ * @param fqn
+ * @param createIfAbsent
+ * @see #getRegion(Fqn,boolean)
+ */
+ public Region getRegion(String fqn, boolean createIfAbsent)
+ {
+ return getRegion(Fqn.fromString(fqn), createIfAbsent);
+ }
+
+ /**
+ * Removes a {@link org.jboss.cache.Region} identified by the given fqn.
+ *
+ * @param fqn fqn of the region to remove
+ * @return true if such a region existed and was removed.
+ */
+ public boolean removeRegion(Fqn fqn)
+ {
+ Region r = regionsRegistry.remove(fqn);
+ if (r == null) return false;
+
+ if (isUsingEvictions() && r.getEvictionPolicy() != null)
+ {
+ evictionTimerTask.removeRegionToProcess(r);
+ }
+ return true;
+ }
+
+ /**
+ * @return the eviction timer task object associated with this Region Manager.
+ */
+ protected EvictionTimerTask getEvictionTimerTask()
+ {
+ return evictionTimerTask;
+ }
+
+ /**
+ * Activates unmarshalling of replication messages for the region
+ * rooted in the given Fqn.
+ * <p/>
+ * <strong>NOTE:</strong> This method will cause the creation of a node
+ * in the local cache at <code>subtreeFqn</code> whether or not that
+ * node exists anywhere else in the cluster. If the node does not exist
+ * elsewhere, the local node will be empty. The creation of this node will
+ * not be replicated.
+ * <p/>
+ *
+ * @param fqn representing the region to be activated.
+ * @throws RegionNotEmptyException if the node <code>fqn</code>
+ * exists and already has either data or children
+ */
+ public void activate(Fqn fqn) throws RegionNotEmptyException
+ {
+ activate(fqn, false);
+ }
+
+ /**
+ * Attempts to activate a given region rooted at a given Fqn, similar to {@link #activate(Fqn)} except
+ * that if the fqn is currently already in use (probably already been activated) this method is a no-op.
+ *
+ * @param fqn which represents the region to activate
+ */
+ public void activateIfEmpty(Fqn fqn)
+ {
+ activate(fqn, true);
+ }
+
+ private void activate(Fqn fqn, boolean suppressRegionNotEmptyException)
+ {
+ try
+ {
+ if (log.isTraceEnabled()) log.trace("Activating region " + fqn);
+ Region r = getRegion(fqn, false);
+ if (r != null)
+ {
+ if (!defaultInactive && r.getClassLoader() == null)
+ {
+ // This region's state will no match that of a non-existent one
+ // So, there is no reason to keep this region any more
+
+ // (Brian) We shouldn't do this anymore; now outside code
+ // can have a ref to the region!!
+ removeRegion(fqn);
+ }
+ else
+ {
+ //r.activate();
+ r.setActive(true);
+ // FIXME - persistent state transfer counts too!
+ if (cache.getConfiguration().isFetchInMemoryState())
+ {
+ activateRegion(r.getFqn(), suppressRegionNotEmptyException);
+ }
+ }
+ }
+ else if (defaultInactive)
+ {
+ // "Active" region is not the default, so create a region
+ r = getRegion(fqn, true);
+ r.setActive(true);
+ // FIXME - persistent state transfer counts too!
+ if (cache.getConfiguration().isFetchInMemoryState())
+ {
+ activateRegion(r.getFqn(), suppressRegionNotEmptyException);
+ }
+ }
+ }
+ catch (RuntimeException re)
+ {
+ throw re;
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Causes the cache to transfer state for the subtree rooted at
+ * <code>subtreeFqn</code> and to begin accepting replication messages
+ * for that subtree.
+ * <p/>
+ * <strong>NOTE:</strong> This method will cause the creation of a node
+ * in the local cache at <code>subtreeFqn</code> whether or not that
+ * node exists anywhere else in the cluster. If the node does not exist
+ * elsewhere, the local node will be empty. The creation of this node will
+ * not be replicated.
+ *
+ * @param fqn Fqn string indicating the uppermost node in the
+ * portion of the cache that should be activated.
+ * @throws RegionNotEmptyException if the node <code>subtreeFqn</code>
+ * exists and has either data or children
+ */
+ private void activateRegion(Fqn fqn, boolean suppressRegionNotEmptyException)
+ {
+ // Check whether the node already exists and has data
+ Node subtreeRoot = cache.findNode(fqn);
+
+ /*
+ * Commented out on Nov 16,2006 Manik&Vladimir
+ *
+ * if (!(cache.isNodeEmpty(subtreeRoot)))
+ {
+ throw new RegionNotEmptyException("Node " + subtreeRoot.getFqn() + " already exists and is not empty");
+ }*/
+
+ if (isActivatingDeactivating(fqn))
+ {
+ throw new CacheException("Region " + subtreeRoot.getFqn() + " is already being activated/deactivated");
+ }
+
+ if (log.isDebugEnabled())
+ {
+ log.debug("activating " + fqn);
+ }
+
+ try
+ {
+
+ // Add this fqn to the set of those we are activating
+ // so calls to _getState for the fqn can return quickly
+ activationChangeNodes.add(fqn);
+
+ Region region = getRegion(fqn, true);
+
+ BuddyManager buddyManager = cache.getBuddyManager();
+ // Request partial state from the cluster and integrate it
+ if (buddyManager == null)
+ {
+ // Get the state from any node that has it and put it
+ // in the main cache
+ if (subtreeRoot == null)
+ {
+ // We'll update this node with the state we receive
+ subtreeRoot = cache.createSubtreeRootNode(fqn);
+ }
+
+ List<Address> members = cache.getMembers();
+ cache.fetchPartialState(members, subtreeRoot.getFqn());
+ }
+ else
+ {
+ // Get the state from each DataOwner and integrate in their
+ // respective buddy backup cache
+ List<Address> buddies = buddyManager.getBuddyAddresses();
+ for (Address buddy : buddies)
+ {
+ List<Address> sources = new ArrayList<Address>(1);
+ sources.add(buddy);
+ Fqn base = new Fqn(BuddyManager.BUDDY_BACKUP_SUBTREE_FQN, BuddyManager.getGroupNameFromAddress(buddy));
+ Fqn buddyRoot = new Fqn(base, fqn);
+ subtreeRoot = cache.findNode(buddyRoot);
+ if (subtreeRoot == null)
+ {
+ // We'll update this node with the state we receive
+ subtreeRoot = cache.createSubtreeRootNode(buddyRoot);
+ }
+ cache.fetchPartialState(sources, fqn, subtreeRoot.getFqn());
+ }
+ }
+ }
+ catch (Throwable t)
+ {
+ log.error("failed to activate " + fqn, t);
+
+ // "Re-deactivate" the region
+ try
+ {
+ inactivateRegion(fqn);
+ }
+ catch (Exception e)
+ {
+ log.error("failed inactivating " + fqn, e);
+ // just swallow this one and throw the first one
+ }
+
+ // Throw the exception on, wrapping if necessary
+ if (t instanceof RegionNotEmptyException)
+ {
+ if (!suppressRegionNotEmptyException) throw (RegionNotEmptyException) t;
+ }
+ else if (t instanceof CacheException)
+ {
+ throw (CacheException) t;
+ }
+ else
+ {
+ throw new CacheException(t.getClass().getName() + " " +
+ t.getLocalizedMessage(), t);
+ }
+ }
+ finally
+ {
+ activationChangeNodes.remove(fqn);
+ }
+ }
+
+ /**
+ * Convenienve method. If the region defined by fqn does not exist, {@link #isDefaultInactive()} is returned, otherwise
+ * !{@link Region#isActive()} is returned.
+ *
+ * @param fqn fqn to test
+ * @return true if inactive
+ */
+ public boolean isInactive(Fqn fqn)
+ {
+ Region region = getRegion(fqn, false);
+ return region == null ? defaultInactive : !region.isActive();
+ }
+
+
+ /**
+ * Causes the cache to stop accepting replication events for the subtree
+ * rooted at <code>subtreeFqn</code> and evict all nodes in that subtree.
+ * <p/>
+ * This is legacy code and should not be called directly. This is a private method for now and will be refactored out.
+ * You should be using {@link #activate(Fqn)} and {@link #deactivate(Fqn)}
+ * <p/>
+ *
+ * @param fqn Fqn string indicating the uppermost node in the
+ * portion of the cache that should be activated.
+ * @throws RegionNameConflictException if <code>subtreeFqn</code> indicates
+ * a node that is part of another
+ * subtree that is being specially
+ * managed (either by activate/inactiveRegion()
+ * or by registerClassLoader())
+ * @throws CacheException if there is a problem evicting nodes
+ * @throws IllegalStateException if {@link org.jboss.cache.config.Configuration#isUseRegionBasedMarshalling()} is <code>false</code>
+ */
+ private void inactivateRegion(Fqn fqn) throws CacheException
+ {
+ if (isActivatingDeactivating(fqn))
+ {
+ throw new CacheException("Region " + fqn + " is already being activated/deactivated");
+ }
+
+ NodeSPI parent = null;
+ NodeSPI subtreeRoot = null;
+ boolean parentLocked = false;
+ boolean subtreeLocked = false;
+ NodeLock parentLock = null;
+ NodeLock subtreeLock = null;
+
+ try
+ {
+ // Record that this fqn is in status change, so can't provide state
+ activationChangeNodes.add(fqn);
+
+ if (!isInactive(fqn))
+ {
+ deactivate(fqn);
+ }
+
+ // Create a list with the Fqn in the main cache and any buddy backup trees
+ BuddyManager buddyManager = cache.getBuddyManager();
+ ArrayList<Fqn> list = new ArrayList<Fqn>();
+ list.add(fqn);
+
+ if (buddyManager != null)
+ {
+ Set buddies = cache.getChildrenNames(BuddyManager.BUDDY_BACKUP_SUBTREE_FQN);
+ if (buddies != null)
+ {
+ for (Iterator it = buddies.iterator(); it.hasNext();)
+ {
+ Fqn base = new Fqn(BuddyManager.BUDDY_BACKUP_SUBTREE_FQN, it.next());
+ list.add(new Fqn(base, fqn));
+ }
+ }
+ }
+
+ long stateFetchTimeout = cache.getConfiguration().getLockAcquisitionTimeout() + 5000;
+ // Remove the subtree from the main cache and any buddy backup trees
+ for (Iterator<Fqn> it = list.iterator(); it.hasNext();)
+ {
+ Fqn subtree = it.next();
+ subtreeRoot = cache.findNode(subtree);
+ if (subtreeRoot != null)
+ {
+ // Acquire locks
+ Object owner = cache.getOwnerForLock();
+ subtreeLock = subtreeRoot.getLock();
+ subtreeLock.acquireAll(owner, stateFetchTimeout, NodeLock.LockType.WRITE);
+ subtreeLocked = true;
+
+ // Lock the parent, as we're about to write to it
+ parent = subtreeRoot.getParent();
+ if (parent != null)
+ {
+ parentLock = parent.getLock();
+ parentLock.acquire(owner, stateFetchTimeout, NodeLock.LockType.WRITE);
+ parentLocked = true;
+ }
+
+ // Remove the subtree
+ cache._evictSubtree(subtree);
+
+ // Release locks
+ if (parent != null)
+ {
+ log.debug("forcing release of locks in parent");
+ parentLock.releaseAll();
+ }
+
+ parentLocked = false;
+
+ log.debug("forcing release of all locks in subtree");
+ subtreeLock.releaseAll();
+ subtreeLocked = false;
+ }
+ }
+ }
+ catch (InterruptedException ie)
+ {
+ throw new CacheException("Interrupted while acquiring lock", ie);
+ }
+ finally
+ {
+ // If we didn't succeed, undo the marshalling change
+ // NO. Since we inactivated, we may have missed changes
+ //if (!success && !inactive)
+ // marshaller_.activate(subtreeFqn);
+
+ // If necessary, release locks
+ if (parentLocked)
+ {
+ log.debug("forcing release of locks in parent");
+ try
+ {
+ parentLock.releaseAll();
+ }
+ catch (Throwable t)
+ {
+ log.error("failed releasing locks", t);
+ }
+ }
+ if (subtreeLocked)
+ {
+ log.debug("forcing release of all locks in subtree");
+ try
+ {
+ subtreeLock.releaseAll();
+ }
+ catch (Throwable t)
+ {
+ log.error("failed releasing locks", t);
+ }
+ }
+
+ activationChangeNodes.remove(fqn);
+ }
+ }
+
+ /**
+ * <p/>
+ * This is legacy code and should not be called directly. This is a private method for now and will be refactored out.
+ * You should be using {@link #activate(Fqn)} and {@link #deactivate(Fqn)}
+ * <p/>
+ *
+ * @param fqn fqn of the region
+ * @return true if the region defined by the fqn is in the process of activating/deactivating
+ */
+ private boolean isActivatingDeactivating(Fqn fqn)
+ {
+ return activationChangeNodes.contains(fqn);
+ }
+
+ /**
+ * Returns true if the region exists
+ *
+ * @param fqn FQN of the region
+ * @param type type of region to search for
+ * @return true if the region exists
+ */
+ public boolean hasRegion(Fqn fqn, Region.Type type)
+ {
+ Region r = regionsRegistry.get(fqn);
+ if (r == null) return false;
+ switch (type)
+ {
+ case ANY:
+ return true;
+ case EVICTION:
+ return r.getEvictionPolicy() != null && evictionTimerTask.isRegionRegisteredForProcessing(r);
+ case MARSHALLING:
+ return r.isActive() && r.getClassLoader() != null;
+ }
+ // should never reach here?
+ return false;
+ }
+
+ /**
+ * Disables unmarshalling of replication messages for the region
+ * rooted in the given Fqn.
+ *
+ * @param fqn
+ */
+ public void deactivate(Fqn fqn)
+ {
+ try
+ {
+ Region region = getRegion(fqn, false);
+
+ if (region != null)
+ {
+ if (defaultInactive && region.getClassLoader() == null)
+ {
+ // This region's state will no match that of a non-existent one
+ // So, there is no reason to keep this region any more
+
+ // FIXME (Brian) We shouldn't do this anymore; now outside code
+ // can have a ref to the region!!
+ removeRegion(fqn);
+ }
+ else
+ {
+ //region.deactivate();
+ region.setActive(false);
+ // FIXME - we should always clean up; otherwise stale data
+ // is in memory!
+ if (cache.getConfiguration().isFetchInMemoryState())
+ {
+ inactivateRegion(fqn);
+ }
+ }
+ }
+ else if (!defaultInactive)
+ {
+ region = getRegion(fqn, true);
+ region.setActive(false);
+ // FIXME - we should always clean up; otherwise stale data
+ // is in memory!
+ if (cache.getConfiguration().isFetchInMemoryState())
+ {
+ inactivateRegion(fqn);
+ }
+ }
+ }
+ catch (RuntimeException re)
+ {
+ throw re;
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Resets the region manager's regions registry
+ */
+ public void reset()
+ {
+ regionsRegistry.clear();
+ }
+
+ /**
+ * Returns an ordered list of all regions.
+ * Note that the ordered list returned is sorted according to the natural order defined in the {@link Comparable} interface, which {@link org.jboss.cache.Region} extends.
+ *
+ * @param type Type of region to return
+ * @return an ordered list of all regions, based on the type requested.
+ */
+ public List<Region> getAllRegions(Region.Type type)
+ {
+ List<Region> regions;
+
+ if (type != Region.Type.ANY)
+ {
+ regions = new ArrayList<Region>();
+ // we need to loop thru the regions and only select specific regions to rtn.
+ for (Region r : regionsRegistry.values())
+ {
+ if ((type == Region.Type.EVICTION && r.getEvictionPolicy() != null && evictionTimerTask.isRegionRegisteredForProcessing(r)) ||
+ (type == Region.Type.MARSHALLING && r.isActive() && r.getClassLoader() != null))
+ regions.add(r);
+ }
+ }
+ else
+ {
+ // put all regions
+ regions = new ArrayList<Region>(regionsRegistry.values());
+ }
+
+ Collections.sort(regions);
+
+ return regions;
+ }
+
+ /**
+ * Sets if evictions are processed.
+ */
+ public void setUsingEvictions(boolean usingEvictions)
+ {
+ this.usingEvictions = usingEvictions;
+ }
+
+ /**
+ * Sets the eviction configuration.
+ */
+ public void setEvictionConfig(EvictionConfig evictionConfig)
+ {
+ this.evictionConfig = evictionConfig;
+ boolean setDefault = false;
+ // create regions for the regions defined in the evictionConfig.
+ for (EvictionRegionConfig erc : evictionConfig.getEvictionRegionConfigs())
+ {
+ Fqn fqn = erc.getRegionFqn();
+ if (log.isTraceEnabled()) log.trace("Creating eviction region " + fqn);
+
+ if (fqn.equals(DEFAULT_REGION))
+ {
+ if (setDefault)
+ {
+ throw new ConfigurationException("A default region for evictions has already been set for this cache");
+ }
+ if (log.isTraceEnabled()) log.trace("Applying settings for " + DEFAULT_REGION + " to Fqn.ROOT");
+ fqn = Fqn.ROOT;
+ setDefault = true;
+ }
+ Region r = getRegion(fqn, true);
+ r.setEvictionPolicy(erc.getEvictionPolicyConfig());
+ }
+ }
+
+ /**
+ * Starts the eviction processing thread.
+ */
+ public void startEvictionThread()
+ {
+ evictionTimerTask.init(evictionConfig.getWakeupIntervalSeconds());
+ }
+
+ /**
+ * Stops the eviction processing thread
+ */
+ public void stopEvictionThread()
+ {
+ evictionTimerTask.stop();
+ }
+
+
+ /**
+ * Returns a string containing debug information on every region.
+ */
+ public String dumpRegions()
+ {
+ StringBuilder sb = new StringBuilder();
+ for (Region r : regionsRegistry.values())
+ {
+ sb.append("\tRegion " + r);
+ sb.append("\n");
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Returns a string containing debug information on every region.
+ */
+ public String toString()
+ {
+ return "RegionManager " + dumpRegions();
+ }
+
+ /**
+ * Returns the cache for this region manager
+ */
+ public CacheImpl getCache()
+ {
+ return this.cache;
+ }
+
+}
Copied: core/trunk/src/main/java/org/jboss/cache/RegionNotEmptyException.java (from rev 4250, core/trunk/src-old/org/jboss/cache/RegionNotEmptyException.java)
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/RegionNotEmptyException.java (rev 0)
+++ core/trunk/src/main/java/org/jboss/cache/RegionNotEmptyException.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -0,0 +1,39 @@
+/*
+ * JBoss, the OpenSource J2EE webOS
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+
+package org.jboss.cache;
+
+/**
+ * Thrown when an attempt is made to {@link RegionManager#activate(Fqn)} activate a subtree}
+ * root in Fqn that already has an existing node in the cache.
+ *
+ * @author <a href="mailto://brian.stansberry@jboss.com">Brian Stansberry</a>
+ */
+public class RegionNotEmptyException extends CacheException
+{
+
+ /**
+ * The serialVersionUID
+ */
+ private static final long serialVersionUID = 1L;
+
+ public RegionNotEmptyException()
+ {
+ super();
+ }
+
+ public RegionNotEmptyException(String msg)
+ {
+ super(msg);
+ }
+
+ public RegionNotEmptyException(String msg, Throwable cause)
+ {
+ super(msg, cause);
+ }
+
+}
Copied: core/trunk/src/main/java/org/jboss/cache/ReplicationException.java (from rev 4250, core/trunk/src-old/org/jboss/cache/ReplicationException.java)
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/ReplicationException.java (rev 0)
+++ core/trunk/src/main/java/org/jboss/cache/ReplicationException.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -0,0 +1,44 @@
+// $Id$
+
+/*
+ * JBoss, the OpenSource J2EE webOS
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+
+package org.jboss.cache;
+
+/**
+ * Thrown when a replication problem occurred
+ */
+public class ReplicationException extends CacheException
+{
+
+ private static final long serialVersionUID = 33172388691879866L;
+
+ public ReplicationException()
+ {
+ super();
+ }
+
+ public ReplicationException(Throwable cause)
+ {
+ super(cause);
+ }
+
+ public ReplicationException(String msg)
+ {
+ super(msg);
+ }
+
+ public ReplicationException(String msg, Throwable cause)
+ {
+ super(msg, cause);
+ }
+
+ public String toString()
+ {
+ return super.toString();
+ }
+}
Copied: core/trunk/src/main/java/org/jboss/cache/ReplicationQueue.java (from rev 4250, core/trunk/src-old/org/jboss/cache/ReplicationQueue.java)
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/ReplicationQueue.java (rev 0)
+++ core/trunk/src/main/java/org/jboss/cache/ReplicationQueue.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -0,0 +1,197 @@
+/*
+ * JBoss, the OpenSource J2EE webOS
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package org.jboss.cache;
+
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.jboss.cache.marshall.MethodCall;
+import org.jboss.cache.marshall.MethodDeclarations;
+
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Timer;
+import java.util.TimerTask;
+
+
+/**
+ * Periodically (or when certain size is exceeded) takes elements and replicates them.
+ *
+ * @author <a href="mailto:bela at jboss.org">Bela Ban</a> May 24, 2003
+ * @version $Revision$
+ */
+public class ReplicationQueue
+{
+
+ private static Log log = LogFactory.getLog(ReplicationQueue.class);
+
+ private CacheImpl cache = null;
+
+ /**
+ * We flush every 5 seconds. Inactive if -1 or 0
+ */
+ private long interval = 5000;
+
+ /**
+ * Max elements before we flush
+ */
+ private long max_elements = 500;
+
+ /**
+ * Holds the replication jobs: LinkedList<MethodCall>
+ */
+ private final List<MethodCall> elements = new LinkedList<MethodCall>();
+
+ /**
+ * For periodical replication
+ */
+ private Timer timer = null;
+
+ /**
+ * The timer task, only calls flush() when executed by Timer
+ */
+ private MyTask task = null;
+
+ public ReplicationQueue()
+ {
+ }
+
+ /**
+ * Constructs a new ReplicationQueue.
+ */
+ public ReplicationQueue(CacheImpl cache, long interval, long max_elements)
+ {
+ this.cache = cache;
+ this.interval = interval;
+ this.max_elements = max_elements;
+ }
+
+ /**
+ * Returns the flush interval in milliseconds.
+ */
+ public long getInterval()
+ {
+ return interval;
+ }
+
+ /**
+ * Sets the flush interval in milliseconds.
+ */
+ public void setInterval(long interval)
+ {
+ this.interval = interval;
+ stop();
+ start();
+ }
+
+ /**
+ * Returns the maximum number of elements to hold.
+ * If the maximum number is reached, flushes in the calling thread.
+ */
+ public long getMax_elements()
+ {
+ return max_elements;
+ }
+
+ /**
+ * Sets the maximum number of elements to hold.
+ */
+ public void setMax_elements(long max_elements)
+ {
+ this.max_elements = max_elements;
+ }
+
+ /**
+ * Starts the asynchronous flush queue.
+ */
+ public synchronized void start()
+ {
+ if (interval > 0)
+ {
+ if (task == null)
+ task = new MyTask();
+ if (timer == null)
+ {
+ timer = new Timer(true);
+ timer.schedule(task,
+ 500, // delay before initial flush
+ interval); // interval between flushes
+ }
+ }
+ }
+
+ /**
+ * Stops the asynchronous flush queue.
+ */
+ public synchronized void stop()
+ {
+ if (task != null)
+ {
+ task.cancel();
+ task = null;
+ }
+ if (timer != null)
+ {
+ timer.cancel();
+ timer = null;
+ }
+ }
+
+
+ /**
+ * Adds a new method call.
+ */
+ public void add(MethodCall job)
+ {
+ if (job == null)
+ throw new NullPointerException("job is null");
+ synchronized (elements)
+ {
+ elements.add(job);
+ if (elements.size() >= max_elements)
+ flush();
+ }
+ }
+
+ /**
+ * Flushes existing method calls.
+ */
+ public void flush()
+ {
+ List<MethodCall> l;
+ synchronized (elements)
+ {
+ if (log.isTraceEnabled())
+ log.trace("flush(): flushing repl queue (num elements=" + elements.size() + ")");
+ l = new ArrayList<MethodCall>(elements);
+ elements.clear();
+ }
+
+ if (l.size() > 0)
+ {
+ try
+ {
+ // send to all live nodes in the cluster
+ cache.getRPCManager().callRemoteMethods(null, MethodDeclarations.replicateAllMethod, new Object[]{l}, false, true, 5000);
+ }
+ catch (Throwable t)
+ {
+ log.error("failed replicating " + l.size() + " elements in replication queue", t);
+ }
+ }
+ }
+
+ class MyTask extends TimerTask
+ {
+ public void run()
+ {
+ flush();
+ }
+ }
+
+}
Copied: core/trunk/src/main/java/org/jboss/cache/SuspectException.java (from rev 4250, core/trunk/src-old/org/jboss/cache/SuspectException.java)
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/SuspectException.java (rev 0)
+++ core/trunk/src/main/java/org/jboss/cache/SuspectException.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -0,0 +1,28 @@
+package org.jboss.cache;
+
+/**
+ * Thrown when a member is suspected during remote method invocation
+ * @author Bela Ban
+ * @version $Id$
+ */
+public class SuspectException extends CacheException
+{
+
+ private static final long serialVersionUID = -2965599037371850141L;
+
+ public SuspectException() {
+ super();
+ }
+
+ public SuspectException(String msg) {
+ super(msg);
+ }
+
+ public SuspectException(String msg, Throwable cause) {
+ super(msg, cause);
+ }
+
+ public String toString() {
+ return super.toString();
+ }
+}
Copied: core/trunk/src/main/java/org/jboss/cache/TreeCacheViewMBean.java (from rev 4250, core/trunk/src-old/org/jboss/cache/TreeCacheViewMBean.java)
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/TreeCacheViewMBean.java (rev 0)
+++ core/trunk/src/main/java/org/jboss/cache/TreeCacheViewMBean.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -0,0 +1,34 @@
+/*
+ * JBoss, the OpenSource J2EE webOS
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package org.jboss.cache;
+
+import org.jboss.cache.jmx.CacheJmxWrapperMBean;
+
+
+/**
+ * MBean interface.
+ *
+ * @author <a href="mailto:bela at jboss.org">Bela Ban</a> March 27 2003
+ */
+public interface TreeCacheViewMBean
+{
+ void create() throws Exception;
+
+ void start() throws Exception;
+
+ void stop() ;
+
+ void destroy() ;
+
+ Cache getCache();
+
+ void setCache(Cache cache);
+
+ CacheJmxWrapperMBean getCacheService();
+
+ void setCacheService(CacheJmxWrapperMBean cache_service);
+}
Copied: core/trunk/src/main/java/org/jboss/cache/UnversionedNode.java (from rev 4250, core/trunk/src-old/org/jboss/cache/UnversionedNode.java)
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/UnversionedNode.java (rev 0)
+++ core/trunk/src/main/java/org/jboss/cache/UnversionedNode.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -0,0 +1,745 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package org.jboss.cache;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.jboss.cache.lock.IdentityLock;
+import org.jboss.cache.marshall.MethodCall;
+import org.jboss.cache.marshall.MethodCallFactory;
+import org.jboss.cache.marshall.MethodDeclarations;
+import org.jboss.cache.optimistic.DataVersion;
+import org.jboss.cache.transaction.GlobalTransaction;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * Basic data node class. Throws {@link UnsupportedOperationException} for version-specific methods like {@link #getVersion()} and
+ * {@link #setVersion(org.jboss.cache.optimistic.DataVersion)}, defined in {@link org.jboss.cache.NodeSPI}.
+ *
+ * @author Manik Surtani (<a href="mailto:manik at jboss.org">manik at jboss.org</a>)
+ * @since 2.0.0
+ */
+public class UnversionedNode<K, V> extends AbstractNode<K, V> implements NodeSPI<K, V>
+{
+
+ /**
+ * Default output indent for printing.
+ */
+ private static final int INDENT = 4;
+
+ /**
+ * Debug log.
+ */
+ private static Log log = LogFactory.getLog(UnversionedNode.class);
+
+ /**
+ * True if all children have been loaded. This is set when CacheImpl.getChildrenNames() is called.
+ */
+ private boolean childrenLoaded = false;
+
+ /**
+ * True if data has been loaded from the cache loader.
+ */
+ private boolean dataLoaded = true;
+
+ /**
+ * Lock manager that manages locks to be acquired when accessing the node inside a transaction. Lazy set just in case
+ * locking is not needed.
+ */
+ private transient IdentityLock lock_ = null;
+
+ /**
+ * A reference of the CacheImpl instance.
+ */
+ private transient CacheImpl<K, V> cache;
+
+ /**
+ * Map of general data keys to values.
+ */
+ private final Map<K, V> data = new HashMap<K, V>();
+
+ /**
+ * Constructs a new node with an FQN of Root.
+ */
+ public UnversionedNode()
+ {
+ this.fqn = Fqn.ROOT;
+ }
+
+ /**
+ * Constructs a new node with a name, etc.
+ *
+ * @param mapSafe <code>true</code> if param <code>data</code> can safely be directly assigned to this object's
+ * {@link #data} field; <code>false</code> if param <code>data</code>'s contents should be copied into
+ * this object's {@link #data} field.
+ */
+ protected UnversionedNode(Object child_name, Fqn fqn, Map<K, V> data, boolean mapSafe, CacheSPI<K, V> cache)
+ {
+ init(child_name, fqn, cache);
+ if (data != null)
+ {
+ this.data.putAll(data);// ? is this safe
+ }
+ }
+
+ /**
+ * Initializes with a name and FQN and cache.
+ */
+ private void init(Object child_name, Fqn fqn, CacheSPI<K, V> cache)
+ {
+ if (cache == null)
+ {
+ throw new IllegalArgumentException("no cache init for " + fqn);
+ }
+ this.cache = (CacheImpl) cache;
+ this.fqn = fqn;
+ if (!fqn.isRoot() && !child_name.equals(fqn.getLastElement()))
+ {
+ throw new IllegalArgumentException("Child " + child_name + " must be last part of " + fqn);
+ }
+ }
+
+ /**
+ * Returns a parent by checking the TreeMap by name.
+ */
+ public NodeSPI<K, V> getParent()
+ {
+ if (fqn.isRoot())
+ {
+ return null;
+ }
+ return cache.peek(fqn.getParent(), true);
+ }
+
+ private synchronized void initLock()
+ {
+ if (lock_ == null)
+ {
+ lock_ = new IdentityLock(cache.getConfiguration().getIsolationLevel(), this);
+ }
+ }
+
+ private synchronized Map<Object, Node<K, V>> children()
+ {
+ if (children == null)
+ {
+ if (getFqn().isRoot())
+ {
+ children = new ConcurrentHashMap<Object, Node<K, V>>(64, .5f, 16);
+ }
+ else
+ {
+ // Less segments to save memory
+ children = new ConcurrentHashMap<Object, Node<K, V>>(4, .75f, 4);
+ }
+ }
+ return children;
+ }
+
+ public CacheSPI<K, V> getCache()
+ {
+ return cache;
+ }
+
+ public boolean isChildrenLoaded()
+ {
+ return childrenLoaded;
+ }
+
+ public void setChildrenLoaded(boolean flag)
+ {
+ childrenLoaded = flag;
+ }
+
+ public V get(K key)
+ {
+ return cache.get(getFqn(), key);
+ }
+
+ public V getDirect(K key)
+ {
+ return data == null ? null : data.get(key);
+ }
+
+
+ private boolean isReadLocked()
+ {
+ return lock_ != null && lock_.isReadLocked();
+ }
+
+ private boolean isWriteLocked()
+ {
+ return lock_ != null && lock_.isWriteLocked();
+ }
+
+ public IdentityLock getLock()
+ {
+ initLock();
+ return lock_;
+ }
+
+ public Map<K, V> getData()
+ {
+ if (cache == null) return Collections.emptyMap();
+ return cache.getData(getFqn());
+
+/*
+ Map<K, V> dMap = new HashMap<K, V>();
+ for (K k : cache.getKeys(getFqn()))
+ {
+ dMap.put(k, cache.get(fqn, k));
+ }
+ return Collections.unmodifiableMap(dMap);
+*/
+ }
+
+ public Map<K, V> getDataDirect()
+ {
+ if (data == null) return Collections.emptyMap();
+ return Collections.unmodifiableMap(data);
+ }
+
+ public V put(K key, V value)
+ {
+ return cache.put(getFqn(), key, value);
+ }
+
+ public V putDirect(K key, V value)
+ {
+ return data.put(key, value);
+ }
+
+ public NodeSPI getOrCreateChild(Object child_name, GlobalTransaction gtx)
+ {
+ return getOrCreateChild(child_name, gtx, true);
+ }
+
+ private NodeSPI getOrCreateChild(Object child_name, GlobalTransaction gtx, boolean createIfNotExists)
+ {
+
+ NodeSPI child;
+ if (child_name == null)
+ {
+ throw new IllegalArgumentException("null child name");
+ }
+
+ child = (NodeSPI) children().get(child_name);
+ InvocationContext ctx = cache.getInvocationContext();
+ if (createIfNotExists && child == null)
+ {
+ // construct the new child outside the synchronized block to avoid
+ // spending any more time than necessary in the synchronized section
+ Fqn child_fqn = new Fqn(this.fqn, child_name);
+ NodeSPI newChild = (NodeSPI) cache.getConfiguration().getRuntimeConfig().getNodeFactory().createNode(child_name, this, null);
+ if (newChild == null)
+ {
+ throw new IllegalStateException();
+ }
+ synchronized (this)
+ {
+ // check again to see if the child exists
+ // after acquiring exclusive lock
+ child = (NodeSPI) children().get(child_name);
+ if (child == null)
+ {
+ cache.getNotifier().notifyNodeCreated(child_fqn, true, ctx);
+ child = newChild;
+ children.put(child_name, child);
+ if (gtx != null)
+ {
+ MethodCall undo_op = MethodCallFactory.create(MethodDeclarations.removeNodeMethodLocal, gtx,
+ child_fqn, false);
+ cache.addUndoOperation(gtx, undo_op);
+ // add the node name to the list maintained for the current tx
+ // (needed for abort/rollback of transaction)
+ // cache.addNode(gtx, child.getFqn());
+ }
+ }
+ }
+
+ // notify if we actually created a new child
+ if (newChild == child)
+ {
+ if (log.isTraceEnabled())
+ {
+ log.trace("created child: fqn=" + child_fqn);
+ }
+ cache.getNotifier().notifyNodeCreated(child_fqn, false, ctx);
+ }
+ }
+ return child;
+
+ }
+
+ public V remove(K key)
+ {
+ return cache.remove(getFqn(), key);
+ }
+
+ public V removeDirect(K key)
+ {
+ if (data == null) return null;
+ return data.remove(key);
+ }
+
+ public void printDetails(StringBuffer sb, int indent)
+ {
+ printDetailsInMap(sb, indent);
+ }
+
+ /**
+ * Returns a debug string.
+ */
+ @Override
+ public String toString()
+ {
+ StringBuffer sb = new StringBuffer();
+ sb.append(getClass().getSimpleName());
+ if (deleted)
+ {
+ sb.append(" (deleted) [ ").append(fqn);
+ }
+ else
+ {
+ sb.append("[ ").append(fqn);
+ }
+ if (data != null)
+ {
+ synchronized (data)
+ {
+ sb.append(" data=").append(data.keySet());
+ }
+ }
+ if (children != null && !children.isEmpty())
+ {
+ sb.append(" child=").append(getChildrenNamesDirect());
+ }
+ if (lock_ != null)
+ {
+ if (isReadLocked())
+ {
+ sb.append(" RL");
+ }
+ if (isWriteLocked())
+ {
+ sb.append(" WL");
+ }
+ }
+ sb.append("]");
+ return sb.toString();
+ }
+
+ public Node<K, V> addChild(Fqn f)
+ {
+ Fqn nf = new Fqn(getFqn(), f);
+ cache.put(nf, null);
+ return getChild(f);
+ }
+
+ public void addChildDirect(NodeSPI<K, V> child)
+ {
+ if (child.getFqn().getParent().equals(getFqn()))
+ {
+ synchronized (this)
+ {
+ children().put(child.getFqn().getLastElement(), child);
+ }
+ }
+ else
+ throw new CacheException("Attempting to add a child [" + child.getFqn() + "] to [" + getFqn() + "]. Can only add direct children.");
+ }
+
+ public NodeSPI<K, V> addChildDirect(Fqn f)
+ {
+ if (f.size() == 1)
+ {
+ GlobalTransaction gtx = cache.getInvocationContext().getGlobalTransaction();
+ return getOrCreateChild(f.getLastElement(), gtx);
+ }
+ else
+ {
+ throw new UnsupportedOperationException("Cannot directly create children which aren't directly under the current node.");
+ }
+
+ }
+
+ public void clearData()
+ {
+ cache.removeData(getFqn());
+ }
+
+ public void clearDataDirect()
+ {
+ if (data != null) data.clear();
+ }
+
+ public Node<K, V> getChild(Fqn fqn)
+ {
+ return cache.get(new Fqn(getFqn(), fqn));
+ }
+
+ public NodeSPI<K, V> getChildDirect(Fqn fqn)
+ {
+ if (fqn.size() == 1)
+ {
+ return getChildDirect(fqn.getLastElement());
+ }
+ else
+ {
+ NodeSPI currentNode = this;
+ for (int i = 0; i < fqn.size(); i++)
+ {
+ Object nextChildName = fqn.get(i);
+ currentNode = currentNode.getChildDirect(nextChildName);
+ if (currentNode == null) return null;
+ }
+ return currentNode;
+ }
+ }
+
+ public Set<Object> getChildrenNames()
+ {
+ return cache.getChildrenNames(getFqn());
+ }
+
+ public Set<Object> getChildrenNamesDirect()
+ {
+ return children == null ? Collections.emptySet() : new HashSet(children.keySet());
+ //return childrenNames();
+ }
+
+ public Set<K> getKeys()
+ {
+ Set<K> keys = cache.getKeys(getFqn());
+ return (Set<K>) (keys == null ? Collections.emptySet() : Collections.unmodifiableSet(keys));
+ }
+
+ public Set<K> getKeysDirect()
+ {
+ if (data == null)
+ {
+ return Collections.emptySet();
+ }
+ return Collections.unmodifiableSet(new HashSet<K>(data.keySet()));
+ }
+
+ public boolean hasChild(Fqn f)
+ {
+ return getChild(f) != null;
+ }
+
+ public boolean hasChild(Object o)
+ {
+ return getChild(o) != null;
+ }
+
+ public V putIfAbsent(K k, V v)
+ {
+ // make sure this is atomic. Not hugely performant at the moment (should use the locking interceptors) but for now ...
+ synchronized (this)
+ {
+ if (!getKeys().contains(k))
+ return put(k, v);
+ else
+ return get(k);
+ }
+ }
+
+ public V replace(K key, V value)
+ {
+ // make sure this is atomic. Not hugely performant at the moment (should use the locking interceptors) but for now ...
+ synchronized (this)
+ {
+ if (getKeys().contains(key))
+ {
+ return put(key, value);
+ }
+ else
+ return null;
+ }
+ }
+
+ public boolean replace(K key, V oldValue, V newValue)
+ {
+ // make sure this is atomic. Not hugely performant at the moment (should use the locking interceptors) but for now ...
+ synchronized (this)
+ {
+ if (oldValue.equals(get(key)))
+ {
+ put(key, newValue);
+ return true;
+ }
+ else
+ return false;
+ }
+ }
+
+ public boolean removeChild(Fqn fqn)
+ {
+ return cache.removeNode(new Fqn(getFqn(), fqn));
+ }
+
+ public int dataSize()
+ {
+ return cache.getKeys(getFqn()).size();
+ }
+
+ public boolean removeChild(Object childName)
+ {
+ return removeChild(new Fqn(getFqn(), childName));
+ }
+
+ public boolean removeChildDirect(Object childName)
+ {
+ return children != null && children.remove(childName) != null;
+ }
+
+ public boolean removeChildDirect(Fqn f)
+ {
+ if (f.size() == 1)
+ {
+ return removeChildDirect(f.getLastElement());
+ }
+ else
+ {
+ NodeSPI child = getChildDirect(f);
+ return child != null && child.getParent().removeChildDirect(f.getLastElement());
+ }
+ }
+
+ public Map<Object, Node<K, V>> getChildrenMapDirect()
+ {
+ return children;
+ }
+
+ public void setChildrenMapDirect(Map<Object, Node<K, V>> children)
+ {
+ this.children().clear();
+ this.children.putAll(children);
+ }
+
+ public void putAll(Map data)
+ {
+ cache.put(fqn, data);
+ }
+
+ public void replaceAll(Map data)
+ {
+ cache.put(fqn, data, true);
+ }
+
+ public void putAllDirect(Map<K, V> data)
+ {
+ if (data == null) return;
+ this.data.putAll(data);
+ }
+
+ public void removeChildrenDirect()
+ {
+ if (children != null)
+ {
+ children.clear();
+ }
+ children = null;
+ }
+
+ public void print(StringBuffer sb, int indent)
+ {
+ printIndent(sb, indent);
+ sb.append(Fqn.SEPARATOR).append(getName()).append(" ").append(getDataDirect().size());
+ if (children != null)
+ {
+ for (Node node : children.values())
+ {
+ sb.append("\n");
+ ((NodeSPI) node).print(sb, indent + INDENT);
+ }
+ }
+ }
+
+ // versioning
+
+ public void setVersion(DataVersion version)
+ {
+ throw new UnsupportedOperationException("Versioning not supported");
+ }
+
+ public DataVersion getVersion()
+ {
+ throw new UnsupportedOperationException("Versioning not supported");
+ }
+
+ private void printIndent(StringBuffer sb, int indent)
+ {
+ if (sb != null)
+ {
+ for (int i = 0; i < indent; i++)
+ {
+ sb.append(" ");
+ }
+ }
+ }
+
+ public void addChild(Object child_name, Node<K, V> n)
+ {
+ if (child_name != null)
+ {
+ children().put(child_name, n);
+ }
+ }
+
+ /**
+ * Returns the name of this node.
+ */
+ private Object getName()
+ {
+ return fqn.getLastElement();
+ }
+
+ /**
+ * Returns the name of this node.
+ */
+ public Fqn getFqn()
+ {
+ return fqn;
+ }
+
+ public void setFqn(Fqn fqn)
+ {
+ if (log.isTraceEnabled())
+ {
+ log.trace(getFqn() + " set FQN " + fqn);
+ }
+ this.fqn = fqn;
+
+ if (children == null)
+ {
+ return;
+ }
+
+ // process children
+ for (Map.Entry<Object, ? extends Node> me : children.entrySet())
+ {
+ NodeSPI n = (NodeSPI) me.getValue();
+ Fqn cfqn = new Fqn(fqn, me.getKey());
+ n.setFqn(cfqn);
+ }
+ }
+
+ public Node<K, V> getChild(Object childName)
+ {
+ return cache.get(new Fqn(getFqn(), childName));
+ }
+
+ public NodeSPI<K, V> getChildDirect(Object childName)
+ {
+ if (childName == null) return null;
+ return (NodeSPI<K, V>) (children == null ? null : children.get(childName));
+ }
+
+ public Set<Node<K, V>> getChildren()
+ {
+ if (cache == null) return Collections.emptySet();
+ Set<Node<K, V>> children = new HashSet<Node<K, V>>();
+ for (Object c : cache.getChildrenNames(getFqn()))
+ {
+ Node n = cache.get(new Fqn(getFqn(), c));
+ if (n != null) children.add(n);
+ }
+ return Collections.unmodifiableSet(children);
+ }
+
+ public Set<NodeSPI<K, V>> getChildrenDirect()
+ {
+ // strip out deleted child nodes...
+ if (children == null || children.size() == 0) return Collections.emptySet();
+
+ Set<NodeSPI<K, V>> exclDeleted = new HashSet<NodeSPI<K, V>>();
+ for (Node n : children.values())
+ {
+ NodeSPI spi = (NodeSPI) n;
+ if (!spi.isDeleted()) exclDeleted.add(spi);
+ }
+ return Collections.unmodifiableSet(exclDeleted);
+ }
+
+ public boolean hasChildrenDirect()
+ {
+ return children != null && children.size() != 0;
+ }
+
+ public Set<NodeSPI<K, V>> getChildrenDirect(boolean includeMarkedForRemoval)
+ {
+ if (includeMarkedForRemoval)
+ {
+ if (children != null && !children.isEmpty())
+ {
+ return Collections.unmodifiableSet(new HashSet(children.values()));
+ }
+ else
+ {
+ return Collections.emptySet();
+ }
+ }
+ else
+ {
+ return getChildrenDirect();
+ }
+ }
+
+ /**
+ * Adds details of the node into a map as strings.
+ */
+ private void printDetailsInMap(StringBuffer sb, int indent)
+ {
+ printIndent(sb, indent);
+ indent += 2;// increse it
+ if (!(getFqn()).isRoot())
+ {
+ sb.append(Fqn.SEPARATOR);
+ }
+ sb.append(getName());
+ sb.append(" ");
+ sb.append(data);
+ if (children != null)
+ {
+ for (Node n : children.values())
+ {
+ sb.append("\n");
+ ((NodeSPI) n).printDetails(sb, indent);
+ }
+ }
+ }
+
+ /**
+ * Returns true if the data was loaded from the cache loader.
+ */
+ public boolean isDataLoaded()
+ {
+ return dataLoaded;
+ }
+
+ /**
+ * Sets if the data was loaded from the cache loader.
+ */
+ public void setDataLoaded(boolean dataLoaded)
+ {
+ this.dataLoaded = dataLoaded;
+ }
+
+ public boolean isValid()
+ {
+ // TODO; implement this property, to detect if it has been evicted, removed by another thread, etc. Method added for now as a dummy so it exists in the API
+ return true;
+ }
+}
Copied: core/trunk/src/main/java/org/jboss/cache/Version.java (from rev 4250, core/trunk/src-old/org/jboss/cache/Version.java)
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/Version.java (rev 0)
+++ core/trunk/src/main/java/org/jboss/cache/Version.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -0,0 +1,172 @@
+package org.jboss.cache;
+
+import java.util.StringTokenizer;
+
+/**
+ * Contains version information about this release of JBoss Cache.
+ *
+ * @author Bela Ban
+ * @version $Id$
+ */
+public class Version
+{
+ public static final String version = "2.0.0.GA";
+ public static final String codename = "Habanero";
+ public static byte[] version_id = {'0', '2', '0', '0'};
+ public static final String cvs = "$Id$";
+
+ private static final int MAJOR_SHIFT = 11;
+ private static final int MINOR_SHIFT = 6;
+ private static final int MAJOR_MASK = 0x00f800;
+ private static final int MINOR_MASK = 0x0007c0;
+ private static final int PATCH_MASK = 0x00003f;
+
+ private static final short SHORT_1_2_3 = encodeVersion(1, 2, 3);
+ private static final short SHORT_1_2_4_SP2 = encodeVersion(1, 2, 4);
+
+ /**
+ * Prints version information.
+ */
+ public static void main(String[] args)
+ {
+ System.out.println("\nVersion: \t" + version);
+ System.out.println("Codename: \t" + codename);
+ System.out.println("CVS: \t" + cvs);
+ System.out.println("History: \t(see http://jira.jboss.com/jira/browse/JBCACHE for details)\n");
+ }
+
+ /**
+ * Returns version information as a string.
+ */
+ public static String printVersion()
+ {
+ return "JBossCache '" + codename + "' " + version + "[ " + cvs + "]";
+ }
+
+ public static String printVersionId(byte[] v, int len)
+ {
+ StringBuffer sb = new StringBuffer();
+ if (v != null)
+ {
+ if (len <= 0)
+ len = v.length;
+ for (int i = 0; i < len; i++)
+ sb.append((char) v[i]);
+ }
+ return sb.toString();
+ }
+
+ public static String printVersionId(byte[] v)
+ {
+ StringBuffer sb = new StringBuffer();
+ if (v != null)
+ {
+ for (byte aV : v) sb.append((char) aV);
+ }
+ return sb.toString();
+ }
+
+
+ public static boolean compareTo(byte[] v)
+ {
+ if (v == null)
+ return false;
+ if (v.length < version_id.length)
+ return false;
+ for (int i = 0; i < version_id.length; i++)
+ {
+ if (version_id[i] != v[i])
+ return false;
+ }
+ return true;
+ }
+
+ public static int getLength()
+ {
+ return version_id.length;
+ }
+
+ public static short getVersionShort()
+ {
+ return getVersionShort(version);
+ }
+
+ public static short getVersionShort(String versionString)
+ {
+ if (versionString == null)
+ throw new IllegalArgumentException("versionString is null");
+
+ // Special cases for version prior to 1.2.4.SP2
+ if ("1.2.4".equals(versionString))
+ return 124;
+ else if ("1.2.4.SP1".equals(versionString))
+ return 1241;
+
+ StringTokenizer tokenizer = new StringTokenizer(versionString, ".");
+
+ int major = 0;
+ int minor = 0;
+ int patch = 0;
+
+ if (tokenizer.hasMoreTokens())
+ major = Integer.parseInt(tokenizer.nextToken());
+ if (tokenizer.hasMoreTokens())
+ minor = Integer.parseInt(tokenizer.nextToken());
+ if (tokenizer.hasMoreTokens())
+ patch = Integer.parseInt(tokenizer.nextToken());
+
+ return encodeVersion(major, minor, patch);
+ }
+
+ public static String getVersionString(short versionShort)
+ {
+ if (versionShort == SHORT_1_2_4_SP2)
+ return "1.2.4.SP2";
+
+ switch (versionShort)
+ {
+ case 124:
+ return "1.2.4";
+ case 1241:
+ return "1.2.4.SP1";
+ default:
+ return decodeVersion(versionShort);
+ }
+ }
+
+ public static short encodeVersion(int major, int minor, int patch)
+ {
+ short version = (short) ((major << MAJOR_SHIFT)
+ + (minor << MINOR_SHIFT)
+ + patch);
+ return version;
+ }
+
+ public static String decodeVersion(short version)
+ {
+ int major = (version & MAJOR_MASK) >> MAJOR_SHIFT;
+ int minor = (version & MINOR_MASK) >> MINOR_SHIFT;
+ int patch = (version & PATCH_MASK);
+ String versionString = major + "." + minor + "." + patch;
+ return versionString;
+ }
+
+ public static boolean isBefore124(short version)
+ {
+ return (version > 1241 && version <= SHORT_1_2_3);
+ }
+
+ /**
+ * Retroweaver version info.
+ */
+ public static class Retro
+ {
+ public static void main(String[] args)
+ {
+ System.out.println("\nVersion: \t" + version + " (Retroweaved for JDK 1.4.x compatibility)");
+ System.out.println("Codename: \t" + codename);
+ System.out.println("CVS: \t" + cvs);
+ System.out.println("History: \t(see http://jira.jboss.com/jira/browse/JBCACHE for details)\n");
+ }
+ }
+}
Copied: core/trunk/src/main/java/org/jboss/cache/VersionedNode.java (from rev 4250, core/trunk/src-old/org/jboss/cache/VersionedNode.java)
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/VersionedNode.java (rev 0)
+++ core/trunk/src/main/java/org/jboss/cache/VersionedNode.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -0,0 +1,73 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package org.jboss.cache;
+
+import org.jboss.cache.optimistic.DataVersion;
+import org.jboss.cache.optimistic.DefaultDataVersion;
+
+import java.util.Map;
+
+/**
+ * VersionedNode extends the {@link org.jboss.cache.UnversionedNode} by adding a {@link org.jboss.cache.optimistic.DataVersion} property.
+ * <p/>
+ * Unlike {@link org.jboss.cache.UnversionedNode}, this node supports {@link #getVersion} and {@link #setVersion(org.jboss.cache.optimistic.DataVersion)}
+ * defined in {@link org.jboss.cache.NodeSPI}
+ * <p/>
+ * Typically used when the cache mode configured is {@link org.jboss.cache.config.Configuration.NodeLockingScheme#OPTIMISTIC}
+ *
+ * @author <a href="mailto:manik at jboss.org">Manik Surtani (manik at jboss.org)</a>
+ * @since 2.0.0
+ */
+public class VersionedNode<K, V> extends UnversionedNode<K, V>
+{
+ private DataVersion version;
+ /**
+ * Although this object has a reference to the CacheImpl, the optimistic
+ * node is actually disconnected from the CacheImpl itself.
+ * The parent could be looked up from the TransactionWorkspace.
+ */
+ private NodeSPI<K, V> parent;
+
+ protected VersionedNode(Fqn fqn, NodeSPI<K, V> parent, Map<K, V> data, CacheSPI<K, V> cache)
+ {
+ super(fqn.getLastElement(), fqn, data, false, cache);
+ if (parent == null && !fqn.isRoot()) throw new NullPointerException("parent");
+ this.parent = parent;
+ this.version = DefaultDataVersion.ZERO;
+ }
+
+ /**
+ * Returns the version id of this node.
+ *
+ * @return the version
+ */
+ @Override
+ public DataVersion getVersion()
+ {
+ return version;
+ }
+
+ /**
+ * Returns the parent.
+ */
+ @Override
+ public NodeSPI<K, V> getParent()
+ {
+ return parent;
+ }
+
+ /**
+ * Sets the version id of this node.
+ *
+ * @param version
+ */
+ @Override
+ public void setVersion(DataVersion version)
+ {
+ this.version = version;
+ }
+}
Copied: core/trunk/src/main/java/org/jboss/cache/buddyreplication (from rev 4250, core/trunk/src-old/org/jboss/cache/buddyreplication)
Copied: core/trunk/src/main/java/org/jboss/cache/config (from rev 4250, core/trunk/src-old/org/jboss/cache/config)
Copied: core/trunk/src/main/java/org/jboss/cache/demo (from rev 4250, core/trunk/src-old/org/jboss/cache/demo)
Copied: core/trunk/src/main/java/org/jboss/cache/eviction (from rev 4250, core/trunk/src-old/org/jboss/cache/eviction)
Copied: core/trunk/src/main/java/org/jboss/cache/factories (from rev 4250, core/trunk/src-old/org/jboss/cache/factories)
Copied: core/trunk/src/main/java/org/jboss/cache/interceptors (from rev 4250, core/trunk/src-old/org/jboss/cache/interceptors)
Copied: core/trunk/src/main/java/org/jboss/cache/jmx (from rev 4250, core/trunk/src-old/org/jboss/cache/jmx)
Copied: core/trunk/src/main/java/org/jboss/cache/loader (from rev 4250, core/trunk/src-old/org/jboss/cache/loader)
Copied: core/trunk/src/main/java/org/jboss/cache/lock (from rev 4250, core/trunk/src-old/org/jboss/cache/lock)
Copied: core/trunk/src/main/java/org/jboss/cache/marshall (from rev 4250, core/trunk/src-old/org/jboss/cache/marshall)
Copied: core/trunk/src/main/java/org/jboss/cache/notifications (from rev 4250, core/trunk/src-old/org/jboss/cache/notifications)
Copied: core/trunk/src/main/java/org/jboss/cache/optimistic (from rev 4250, core/trunk/src-old/org/jboss/cache/optimistic)
Copied: core/trunk/src/main/java/org/jboss/cache/statetransfer (from rev 4250, core/trunk/src-old/org/jboss/cache/statetransfer)
Copied: core/trunk/src/main/java/org/jboss/cache/transaction (from rev 4250, core/trunk/src-old/org/jboss/cache/transaction)
Copied: core/trunk/src/main/java/org/jboss/cache/util (from rev 4250, core/trunk/src-old/org/jboss/cache/util)
Copied: core/trunk/src/main/java/org/jboss/cache/xml (from rev 4250, core/trunk/src-old/org/jboss/cache/xml)
Deleted: core/trunk/src-old/org/jboss/cache/AbstractNode.java
===================================================================
--- core/trunk/src-old/org/jboss/cache/AbstractNode.java 2007-08-14 19:09:32 UTC (rev 4251)
+++ core/trunk/src-old/org/jboss/cache/AbstractNode.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -1,58 +0,0 @@
-/**
- *
- */
-package org.jboss.cache;
-
-import java.util.Map;
-
-/**
- * Base class for {@link UnversionedNode}.
- *
- * @author manik
- */
-public abstract class AbstractNode<K, V> implements Node<K, V>
-{
- protected boolean deleted;
- protected Map<Object, Node<K, V>> children;
- protected Fqn fqn;
-
- public boolean isDeleted()
- {
- return deleted;
- }
-
- public void markAsDeleted(boolean marker)
- {
- markAsDeleted(marker, false);
- }
-
- public void markAsDeleted(boolean marker, boolean recursive)
- {
- deleted = marker;
- if (recursive && children != null)
- {
- synchronized (this)
- {
- for (Node child : children.values())
- {
- ((AbstractNode) child).markAsDeleted(marker, true);
- }
- }
- }
- }
-
- public boolean equals(Object another)
- {
- if (another instanceof AbstractNode)
- {
- AbstractNode anotherNode = (AbstractNode) another;
- return fqn == null && anotherNode.fqn == null || !(fqn == null || anotherNode.fqn == null) && fqn.equals(anotherNode.fqn);
- }
- return false;
- }
-
- public int hashCode()
- {
- return fqn.hashCode();
- }
-}
Deleted: core/trunk/src-old/org/jboss/cache/Cache.java
===================================================================
--- core/trunk/src-old/org/jboss/cache/Cache.java 2007-08-14 19:09:32 UTC (rev 4251)
+++ core/trunk/src-old/org/jboss/cache/Cache.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -1,373 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source
- *
- * Distributable under LGPL license.
- * See terms of license at gnu.org.
- */
-package org.jboss.cache;
-
-import net.jcip.annotations.ThreadSafe;
-import org.jboss.cache.config.Configuration;
-import org.jgroups.Address;
-
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * Interface for a Cache where data mappings are grouped and stored in a tree data
- * structure consisting of {@link Node}s.
- * <p/>
- * This is the central construct and basic client API of JBoss Cache and is used for
- * cache-wide operations.
- * <p/>
- * The cache is constructed using a {@link CacheFactory} and is started
- * using {@link #start}, if not already started by the CacheFactory.
- * <p/>
- * Once constructed, the Cache interface can be used to create or access {@link Node}s, which contain data. Once references
- * to {@link Node}s are obtained, data can be stored in them,
- * <p/>
- * As a convenience (and mainly to provide a familiar API to the older JBoss Cache 1.x.x releases) methods are provided that
- * operate directly on nodes.
- * <ul>
- * <li>{@link #put(Fqn,Object,Object)} </li>
- * <li>{@link #put(Fqn,java.util.Map)} </li>
- * <li>{@link #get(Fqn,Object)} </li>
- * <li>{@link #remove(Fqn,Object)} </li>
- * <li>{@link #removeNode(Fqn)} </li>
- * </ul>
- * <p/>
- * A simple example of usage:
- * <pre>
- * // creates with default settings and starts the cache
- * Cache cache = DefaultCacheFactory.getInstance().createCache();
- * Fqn personRecords = Fqn.fromString("/org/mycompany/personRecords");
- * <p/>
- * Node rootNode = cache.getRoot();
- * Node personRecordsNode = rootNode.addChild(personRecords);
- * <p/>
- * // now add some person records.
- * Fqn peterGriffin = Fqn.fromString("/peterGriffin");
- * Fqn stewieGriffin = Fqn.fromString("/stewieGriffin");
- * <p/>
- * // the addChild() API uses relative Fqns
- * Node peter = personRecordsNode.addChild(peterGriffin);
- * Node stewie = personRecordsNode.addChild(stewieGriffin);
- * <p/>
- * peter.put("name", "Peter Griffin");
- * peter.put("ageGroup", "MidLifeCrisis");
- * peter.put("homicidal", Boolean.FALSE);
- * <p/>
- * stewie.put("name", "Stewie Griffin");
- * stewie.put("ageGroup", "Infant");
- * stewie.put("homicidal", Boolean.TRUE);
- * <p/>
- * peter.getFqn().toString(); // will print out /org/mycompany/personRecords/peterGriffin
- * stewie.getFqn().toString(); // will print out /org/mycompany/personRecords/stewieGriffin
- * <p/>
- * peter.getFqn().getParent().equals(stewie.getFqn().getParent()); // will return true
- * <p/>
- * </pre>
- * <p/>
- * For more information, please read the JBoss Cache user guide and tutorial, available on <a href="http://labs.jboss.com/portal/jbosscache/docs/index.html" target="_BLANK">the JBoss Cache documentation site</a>,
- * and look through the examples <a href="http://labs.jboss.com/portal/jbosscache/download/index.html" target="_BLANK">shipped with the JBoss Cache distribution</a>.
- *
- * @author <a href="mailto:manik at jboss.org">Manik Surtani (manik at jboss.org)</a>
- * @see Node
- * @see CacheFactory
- * @since 2.0.0
- */
- at ThreadSafe
-public interface Cache<K, V>
-{
- /**
- * Retrieves the configuration of this cache.
- *
- * @return the configuration.
- */
- Configuration getConfiguration();
-
- /**
- * Returns the root node of this cache.
- *
- * @return the root node
- */
- Node<K, V> getRoot();
-
- /**
- * Adds a {@link @org.jboss.cache.notifications.annotation.CacheListener}-annotated object to the entire cache. The object passed in needs to be properly annotated with the
- * {@link @org.jboss.cache.notifications.annotation.CacheListener} annotation otherwise an {@link org.jboss.cache.notifications.IncorrectCacheListenerException} will be thrown.
- *
- * @param listener listener to add
- */
- void addCacheListener(Object listener);
-
- /**
- * Adds a {@link @org.jboss.cache.notifications.annotation.CacheListener}-annotated object to a given region. The object passed in needs to be properly annotated with the
- * {@link @org.jboss.cache.notifications.annotation.CacheListener} annotation otherwise an {@link org.jboss.cache.notifications.IncorrectCacheListenerException} will be thrown.
- *
- * @param region region to add listener to
- * @param listener listener to add
- */
- void addCacheListener(Fqn<?> region, Object listener);
-
- /**
- * Removes a {@link @org.jboss.cache.notifications.annotation.CacheListener}-annotated object from the cache. The object passed in needs to be properly annotated with the
- * {@link @org.jboss.cache.notifications.annotation.CacheListener} annotation otherwise an {@link org.jboss.cache.notifications.IncorrectCacheListenerException} will be thrown.
- *
- * @param listener listener to remove
- */
- void removeCacheListener(Object listener);
-
- /**
- * Removes a {@link @org.jboss.cache.notifications.annotation.CacheListener}-annotated object from a given region. The object passed in needs to be properly annotated with the
- * {@link @org.jboss.cache.notifications.annotation.CacheListener} annotation otherwise an {@link org.jboss.cache.notifications.IncorrectCacheListenerException} will be thrown.
- *
- * @param region region from which to remove listener
- * @param listener listener to remove
- */
- void removeCacheListener(Fqn<?> region, Object listener);
-
- /**
- * Retrieves an immutable {@link List} of objects annotated as {@link org.jboss.cache.notifications.annotation.CacheListener}s attached to the cache.
- *
- * @return an immutable {@link List} of objects annotated as {@link org.jboss.cache.notifications.annotation.CacheListener}s attached to the cache.
- */
- Set<Object> getCacheListeners();
-
- /**
- * Retrieves an immutable {@link List} of objects annotated as {@link org.jboss.cache.notifications.annotation.CacheListener}s attached to a specific region.
- *
- * @return an immutable {@link List} of objects annotated as {@link org.jboss.cache.notifications.annotation.CacheListener}s attached to a specific region.
- */
- Set<Object> getCacheListeners(Fqn<?> region);
-
- /**
- * Associates the specified value with the specified key for a {@link Node} in this cache.
- * If the {@link Node} previously contained a mapping for this key, the old value is replaced by the specified value.
- *
- * @param fqn <b><i>absolute</i></b> {@link Fqn} to the {@link Node} to be accessed.
- * @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 <code>null</code> if there was no mapping for key.
- * A <code>null</code> return can also indicate that the Node previously associated <code>null</code> with the specified key, if the implementation supports null values.
- */
- V put(Fqn<?> fqn, K key, V value);
-
- /**
- * Under special operating behavior, associates the value with the specified key for a node identified by the Fqn passed in.
- * <ul>
- * <li> Only goes through if the node specified does not exist; no-op otherwise.</i>
- * <li> Force asynchronous mode for replication or invalidation to prevent any blocking.</li>
- * <li> 0ms lock timeout to prevent any blocking here either. If the lock is not acquired, this method is a no-op, and swallows the timeout exception.</li>
- * <li> Ongoing transactions are suspended before this call, so failures here will not affect any ongoing transactions.</li>
- * <li> Errors and exceptions are 'silent' - logged at a much lower level than normal, and this method does not throw exceptions</li>
- * </ul>
- * This method is for caching data that has an external representation in storage, where, concurrent modification and
- * transactions are not a consideration, and failure to put the data in the cache should be treated as a 'suboptimal outcome'
- * rather than a 'failing outcome'.
- * <p/>
- * An example of when this method is useful is when data is read from, for example, a legacy datastore, and is cached before
- * returning the data to the caller. Subsequent calls would prefer to get the data from the cache and if the data doesn't exist
- * in the cache, fetch again from the legacy datastore.
- * <p/>
- * See <a href="http://jira.jboss.com/jira/browse/JBCACHE-848">JBCACHE-848</a> for details around this feature.
- * <p/>
- *
- * @param fqn <b><i>absolute</i></b> {@link Fqn} to the {@link Node} to be accessed.
- * @param key key with which the specified value is to be associated.
- * @param value value to be associated with the specified key.
- */
- void putForExternalRead(Fqn<?> fqn, K key, V value);
-
- /**
- * Copies all of the mappings from the specified map to a {@link Node}.
- *
- * @param fqn <b><i>absolute</i></b> {@link Fqn} to the {@link Node} to copy the data to
- * @param data mappings to copy
- */
- void put(Fqn<?> fqn, Map<K, V> data);
-
- /**
- * Removes the mapping for this key from a Node.
- * Returns the value to which the Node previously associated the key, or
- * <code>null</code> if the Node contained no mapping for this key.
- *
- * @param fqn <b><i>absolute</i></b> {@link Fqn} to the {@link Node} to be accessed.
- * @param key key whose mapping is to be removed from the Node
- * @return previous value associated with specified Node's key
- */
- V remove(Fqn<?> fqn, K key);
-
- /**
- * Removes a {@link Node} indicated by absolute {@link Fqn}.
- *
- * @param fqn {@link Node} to remove
- * @return true if the node was removed, false if the node was not found
- */
- boolean removeNode(Fqn<?> fqn);
-
- /**
- * Convenience method that allows for direct access to the data in a {@link Node}.
- *
- * @param fqn <b><i>absolute</i></b> {@link Fqn} to the {@link Node} to be accessed.
- * @param key key under which value is to be retrieved.
- * @return returns data held under specified key in {@link Node} denoted by specified Fqn.
- */
- V get(Fqn<?> fqn, K key);
-
- /**
- * Eviction call that evicts the specified {@link Node} from memory.
- *
- * @param fqn <b><i>absolute</i></b> {@link Fqn} to the {@link Node} to be evicted.
- * @param recursive evicts children as well
- */
- void evict(Fqn<?> fqn, boolean recursive);
-
- /**
- * Retrieves a {@link Region} for a given {@link Fqn}. If the region does not exist,
- * and <li>createIfAbsent</li> is true, then one is created.
- * <p/>
- * If not, parent Fqns will be consulted in turn for registered regions, gradually working up to
- * Fqn.ROOT. If no regions are defined in any of the parents either, a null is returned.
- *
- * @param fqn Fqn that is contained in a region.
- * @param createIfAbsent If true, will create a new associated region if not found.
- * @return a MarshRegion. Null if none is found.
- * @throws UnsupportedOperationException if the region cannot be defined.
- * @see Region
- */
- Region getRegion(Fqn<?> fqn, boolean createIfAbsent);
-
- /**
- * Removes a region denoted by the Fqn passed in.
- *
- * @param fqn of the region to remove
- * @return true if a region did exist and was removed; false otherwise.
- */
- boolean removeRegion(Fqn<?> fqn);
-
- /**
- * Lifecycle method that initializes configuration state, the root node, etc.
- *
- * @throws CacheException if there are creation problems
- */
- void create() throws CacheException;
-
- /**
- * Lifecycle method that starts the cache loader,
- * starts cache replication, starts the region manager, etc., and (if configured) warms the cache using a
- * state transfer or cache loader preload.
- *
- * @throws CacheException if there are startup problems
- */
- void start() throws CacheException;
-
- /**
- * Lifecycle method that stops the cache, including replication,
- * clustering, cache loading, notifications, etc., and clears all cache in-memory state.
- * <p/>
- * State can be reconstituted by using either a cache loader or state transfer when the cache starts again.
- */
- void stop();
-
- /**
- * Lifecycle method that destroys the cache and removes any interceptors/configuration elements.
- * Cache can then be restarted (potentially after reconfiguring) using {@link #create()} and {@link #start()}.
- */
- void destroy();
-
- /**
- * Gets where the cache currently is its lifecycle transitions.
- *
- * @return the CacheStatus. Will not return <code>null</code>.
- */
- CacheStatus getCacheStatus();
-
- /**
- * @return the current invocation context for the current invocation and cache instance.
- * @see org.jboss.cache.InvocationContext
- */
- InvocationContext getInvocationContext();
-
- /**
- * Sets the passed in {@link org.jboss.cache.InvocationContext} as current.
- *
- * @param ctx invocation context to use
- */
- void setInvocationContext(InvocationContext ctx);
-
- /**
- * Returns the local address of this cache in a cluster, or <code>null</code>
- * if running in local mode.
- *
- * @return the local address of this cache in a cluster, or <code>null</code>
- * if running in local mode.
- */
- Address getLocalAddress();
-
- /**
- * Returns a list of members in the cluster, or <code>null</code>
- * if running in local mode.
- *
- * @return a {@link List} of members in the cluster, or <code>null</code>
- * if running in local mode.
- */
- List<Address> getMembers();
-
- /**
- * Moves a part of the cache to a different subtree.
- * <p/>
- * E.g.:
- * <p/>
- * assume a cache structure such as:
- * <p/>
- * <pre>
- * /a/b/c
- * /a/b/d
- * /a/b/e
- * <p/>
- * <p/>
- * Fqn f1 = Fqn.fromString("/a/b/c");
- * Fqn f2 = Fqn.fromString("/a/b/d");
- * <p/>
- * cache.move(f1, f2);
- * </pre>
- * <p/>
- * Will result in:
- * <pre>
- * <p/>
- * /a/b/d/c
- * /a/b/e
- * <p/>
- * </pre>
- * <p/>
- * and now
- * <p/>
- * <pre>
- * Fqn f3 = Fqn.fromString("/a/b/e");
- * Fqn f4 = Fqn.fromString("/a");
- * cache.move(f3, f4);
- * </pre>
- * <p/>
- * will result in:
- * <pre>
- * /a/b/d/c
- * /a/e
- * </pre>
- * No-op if the node to be moved is the root node.
- *
- * @param nodeToMove the Fqn of the node to move.
- * @param newParent new location under which to attach the node being moved.
- * @throws NodeNotExistsException may throw one of these if the target node does not exist or if a different thread has moved this node elsewhere already.
- */
- void move(Fqn<?> nodeToMove, Fqn<?> newParent) throws NodeNotExistsException;
-
- /**
- * Returns the version of the cache as a string.
- *
- * @return the version string of the cache.
- * @see Version#printVersion
- */
- String getVersion();
-}
Deleted: core/trunk/src-old/org/jboss/cache/CacheException.java
===================================================================
--- core/trunk/src-old/org/jboss/cache/CacheException.java 2007-08-14 19:09:32 UTC (rev 4251)
+++ core/trunk/src-old/org/jboss/cache/CacheException.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -1,45 +0,0 @@
-// $Id$
-
-/*
- * JBoss, the OpenSource J2EE webOS
- *
- * Distributable under LGPL license.
- * See terms of license at gnu.org.
- */
-
-package org.jboss.cache;
-
-/**
- * Thrown when operations on {@link org.jboss.cache.Cache} or {@link org.jboss.cache.Node} fail unexpectedly.
- * <p/>
- * Specific subclasses such as {@link org.jboss.cache.lock.TimeoutException}, {@link org.jboss.cache.config.ConfigurationException} and {@link org.jboss.cache.lock.LockingException}
- * have more specific uses.
- *
- * @author <a href="mailto:bela at jboss.org">Bela Ban</a>
- * @author <a href="mailto:manik at jboss.org">Manik Surtani</a>
- */
-public class CacheException extends RuntimeException
-{
-
- private static final long serialVersionUID = -4386393072593859164L;
-
- public CacheException()
- {
- super();
- }
-
- public CacheException(Throwable cause)
- {
- super(cause);
- }
-
- public CacheException(String msg)
- {
- super(msg);
- }
-
- public CacheException(String msg, Throwable cause)
- {
- super(msg, cause);
- }
-}
Deleted: core/trunk/src-old/org/jboss/cache/CacheFactory.java
===================================================================
--- core/trunk/src-old/org/jboss/cache/CacheFactory.java 2007-08-14 19:09:32 UTC (rev 4251)
+++ core/trunk/src-old/org/jboss/cache/CacheFactory.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -1,112 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source
- *
- * Distributable under LGPL license.
- * See terms of license at gnu.org.
- */
-package org.jboss.cache;
-
-import net.jcip.annotations.ThreadSafe;
-import org.jboss.cache.config.Configuration;
-import org.jboss.cache.config.ConfigurationException;
-
-/**
- * This factory constructs a cache from a given or default configuration set.
- * <p/>
- * Typical usage would be:
- * <p/>
- * <pre>
- * CacheFactory factory = DefaultCacheFactory.getInstance();
- * Cache cache = factory.createCache("replSync-service.xml"); // expects this file to be in classpath
- * cache.stop();
- * </pre>
- * Factory methods provide options for creating a cache using
- * <ul>
- * <li>default configuration settings</li>
- * <li>an XML file containing the configuration</li>
- * <li>a constructed and populated {@link org.jboss.cache.config.Configuration} object</li>
- * </ul>
- * In addition, methods provide anadditional option to create and return a cache without starting it.
- *
- * @author <a href="mailto:manik at jboss.org">Manik Surtani (manik at jboss.org)</a>
- * @see org.jboss.cache.Cache
- * @see org.jboss.cache.DefaultCacheFactory
- * @see org.jboss.cache.pojo.PojoCacheFactory
- * @since 2.0.0
- */
- at ThreadSafe
-public interface CacheFactory<K, V>
-{
- /**
- * Creates and starts a {@link Cache} instance using default configuration settings. See {@link Configuration} for default values.
- *
- * @return a cache
- * @throws ConfigurationException if there are problems with the default configuration
- */
- Cache<K, V> createCache() throws ConfigurationException;
-
- /**
- * Creates and optionally starts a {@link Cache} instance using default configuration settings. See {@link Configuration} for default values.
- *
- * @param start if true, starts the cache
- * @return a cache
- * @throws ConfigurationException if there are problems with the default configuration
- */
- Cache<K, V> createCache(boolean start) throws ConfigurationException;
-
- /**
- * Creates and starts a {@link org.jboss.cache.Cache} instance. The following are all valid calls:
- * <pre>
- * factory.createCache("myCacheService.xml"); // file is in class path
- * factory.createCache("etc/myCacheService.xml"); // file is in etc/ relative to the directory you started the JVM
- * factory.createCache("/home/jbosscache/myCacheService.xml"); // file is in the /home/jbosscache directory
- * </pre>
- *
- * @param configFileName the named XML file should exist in the classpath or should be a fully qualified or relative (to your JVM working directory) path to a file on the local file system. Note that the classpath is checked first for the existence of this file.
- * @return a running {@link org.jboss.cache.Cache} instance
- * @throws org.jboss.cache.config.ConfigurationException
- * if there are problems with the configuration
- */
- Cache<K, V> createCache(String configFileName) throws ConfigurationException;
-
- /**
- * Creates {@link Cache} instance, and optionally starts it.
- *
- * @param configFileName the named XML file should exist in the classpath or should be a fully qualified or relative (to your JVM working directory) path to a file on the local file system. Note that the classpath is checked first for the existence of this file.
- * @param start if true, the cache is started before returning.
- * @return an optionally running {@link Cache} instance
- * @throws org.jboss.cache.config.ConfigurationException
- * if there are problems with the configuration
- * @see #createCache(String) for examples on valid config file names.
- */
- Cache<K, V> createCache(String configFileName, boolean start) throws ConfigurationException;
-
- /**
- * Creates a {@link Cache} instance based on a {@link org.jboss.cache.config.Configuration} passed in.
- * <p/>
- * Ensure that the Configuration you pass in is not used by another cache instance in the same JVM,
- * as it may be concurrently modified. Clone the configuration, if shared, using
- * {@link org.jboss.cache.config.Configuration#clone()}.
- *
- * @param configuration the {@link Configuration} object that is passed in to setCache the {@link Cache}.
- * @return a running {@link Cache} instance
- * @throws org.jboss.cache.config.ConfigurationException
- * if there are problems with the configuration
- */
- Cache<K, V> createCache(Configuration configuration) throws ConfigurationException;
-
- /**
- * Creates {@link Cache} instance, and optionally starts it, based on a {@link org.jboss.cache.config.Configuration} passed in.
- * <p/>
- * Ensure that the Configuration you pass in is not used by another cache instance in the same JVM,
- * as it may be concurrently modified. Clone the configuration, if shared, using
- * {@link org.jboss.cache.config.Configuration#clone()}.
- *
- * @param configuration the {@link Configuration} object that is passed in to setCache the {@link Cache}.
- * @param start if true, the cache is started before returning.
- * @return an optionally running {@link Cache} instance
- * @throws org.jboss.cache.config.ConfigurationException
- * if there are problems with the configuration
- */
- Cache<K, V> createCache(Configuration configuration, boolean start) throws ConfigurationException;
-}
Deleted: core/trunk/src-old/org/jboss/cache/CacheImpl.java
===================================================================
--- core/trunk/src-old/org/jboss/cache/CacheImpl.java 2007-08-14 19:09:32 UTC (rev 4251)
+++ core/trunk/src-old/org/jboss/cache/CacheImpl.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -1,4411 +0,0 @@
-/*
- * JBoss, the OpenSource J2EE webOS
- *
- * Distributable under LGPL license.
- * See terms of license at gnu.org.
- */
-package org.jboss.cache;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.jboss.cache.buddyreplication.BuddyGroup;
-import org.jboss.cache.buddyreplication.BuddyManager;
-import org.jboss.cache.buddyreplication.BuddyNotInitException;
-import org.jboss.cache.buddyreplication.GravitateResult;
-import org.jboss.cache.config.BuddyReplicationConfig;
-import org.jboss.cache.config.Configuration;
-import org.jboss.cache.config.Configuration.NodeLockingScheme;
-import org.jboss.cache.config.Option;
-import org.jboss.cache.config.RuntimeConfig;
-import org.jboss.cache.factories.InterceptorChainFactory;
-import org.jboss.cache.interceptors.Interceptor;
-import org.jboss.cache.loader.CacheLoader;
-import org.jboss.cache.loader.CacheLoaderManager;
-import org.jboss.cache.lock.IsolationLevel;
-import org.jboss.cache.lock.LockStrategyFactory;
-import org.jboss.cache.lock.LockUtil;
-import org.jboss.cache.lock.LockingException;
-import org.jboss.cache.lock.NodeLock;
-import org.jboss.cache.lock.TimeoutException;
-import org.jboss.cache.marshall.InactiveRegionAwareRpcDispatcher;
-import org.jboss.cache.marshall.Marshaller;
-import org.jboss.cache.marshall.MethodCall;
-import org.jboss.cache.marshall.MethodCallFactory;
-import org.jboss.cache.marshall.MethodDeclarations;
-import org.jboss.cache.marshall.NodeData;
-import org.jboss.cache.marshall.VersionAwareMarshaller;
-import org.jboss.cache.notifications.Notifier;
-import org.jboss.cache.notifications.event.NodeModifiedEvent;
-import org.jboss.cache.optimistic.DataVersion;
-import org.jboss.cache.statetransfer.StateTransferManager;
-import org.jboss.cache.transaction.GlobalTransaction;
-import org.jboss.cache.transaction.OptimisticTransactionEntry;
-import org.jboss.cache.transaction.TransactionEntry;
-import org.jboss.cache.transaction.TransactionManagerLookup;
-import org.jboss.cache.transaction.TransactionTable;
-import org.jboss.cache.util.ExposedByteArrayOutputStream;
-import org.jboss.cache.util.ThreadGate;
-import org.jboss.cache.util.concurrent.ConcurrentHashSet;
-import org.jboss.util.stream.MarshalledValueInputStream;
-import org.jboss.util.stream.MarshalledValueOutputStream;
-import org.jgroups.Address;
-import org.jgroups.Channel;
-import org.jgroups.ChannelClosedException;
-import org.jgroups.ChannelException;
-import org.jgroups.ChannelFactory;
-import org.jgroups.ChannelNotConnectedException;
-import org.jgroups.ExtendedMembershipListener;
-import org.jgroups.ExtendedMessageListener;
-import org.jgroups.JChannel;
-import org.jgroups.Message;
-import org.jgroups.View;
-import org.jgroups.blocks.GroupRequest;
-import org.jgroups.blocks.RpcDispatcher;
-import org.jgroups.util.Rsp;
-import org.jgroups.util.RspList;
-import org.jgroups.util.Util;
-
-import javax.transaction.Status;
-import javax.transaction.SystemException;
-import javax.transaction.Transaction;
-import javax.transaction.TransactionManager;
-import java.io.ByteArrayInputStream;
-import java.io.InputStream;
-import java.io.NotSerializableException;
-import java.io.OutputStream;
-import java.lang.reflect.Method;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.Vector;
-import java.util.concurrent.ConcurrentHashMap;
-
-/**
- * The default implementation class of {@link org.jboss.cache.Cache} and {@link org.jboss.cache.CacheSPI}. This class
- * has its roots in the legacy (JBoss Cache 1.x.x) org.jboss.cache.TreeCache class.
- * <p/>
- * You should not use this class directly, or attempt to cast {@link org.jboss.cache.Cache} or {@link org.jboss.cache.CacheSPI}
- * interfaces directly to this class.
- *
- * @author Bela Ban
- * @author Ben Wang
- * @author <a href="mailto:manik at jboss.org">Manik Surtani (manik at jboss.org)</a>
- * @author Brian Stansberry
- * @author Daniel Huang (dhuang at jboss.org)
- * @see org.jboss.cache.Cache
- */
-public class CacheImpl<K, V> implements CacheSPI<K, V>
-{
-
- /**
- * CacheImpl log.
- */
- private Log log = LogFactory.getLog(CacheImpl.class);
-
- /**
- * Thread gate used to block Dispatcher during JGroups FLUSH protocol
- */
- private final ThreadGate flushBlockGate = new ThreadGate();
-
- /**
- * Root node.
- */
- private NodeSPI<K, V> root;
-
- /**
- * Cache's region manager.
- */
- private RegionManager regionManager = null;
-
- /**
- * The JGroups JChannel in use.
- */
- protected Channel channel = null;
-
- /**
- * True if this CacheImpl is the coordinator.
- */
- private boolean coordinator = false;
-
- /**
- * List of cluster group members.
- */
- private final Vector<Address> members = new Vector<Address>();
-
- /**
- * JGroups RpcDispatcher in use.
- */
- private RpcDispatcher disp = null;
-
- /**
- * JGroups message listener.
- */
- private MessageListenerAdaptor ml = new MessageListenerAdaptor();
-
- /**
- * Maintains mapping of transactions (keys) and Modifications/Undo-Operations
- */
- private final TransactionTable tx_table = new TransactionTable();
-
- /**
- * HashMap<Thread, List<Lock>, maintains locks acquired by threads (used when no TXs are used)
- */
- private Map<Thread, List<NodeLock>> lock_table;
-
- /**
- * Set<Fqn> of Fqns of the topmost node of internal regions that should
- * not included in standard state transfers.
- */
- private Set<Fqn> internalFqns = new ConcurrentHashSet<Fqn>();
-
- /**
- * True if state was initialized during start-up.
- */
- private volatile boolean isStateSet = false;
-
- /**
- * Class name used to handle evictions.
- */
- private String evictionInterceptorClass = "org.jboss.cache.interceptors.EvictionInterceptor";
-
- /**
- * Marshaller if register to handle marshalling
- */
- private Marshaller marshaller_ = null;
-
- /**
- * {@link #invokeMethod(org.jboss.cache.marshall.MethodCall,boolean)} will dispatch to this chain of interceptors.
- * In the future, this will be replaced with JBossAop. This is a first step towards refactoring JBossCache.
- */
- private Interceptor interceptor_chain = null;
-
- /**
- * Method to acquire a TransactionManager. By default we use JBossTransactionManagerLookup. Has
- * to be set before calling {@link #start()}
- */
- private TransactionManagerLookup tm_lookup = null;
-
- /**
- * Used to get the Transaction associated with the current thread
- */
- private TransactionManager tm = null;
-
- /**
- * Cache loader manager.
- */
- private CacheLoaderManager cacheLoaderManager;
-
- /**
- * Queue used to replicate updates when mode is repl-async
- */
- private ReplicationQueue repl_queue = null;
-
- /**
- * The current lifecycle state.
- */
- CacheStatus cacheStatus;
-
- /**
- * Buddy Manager
- */
- private BuddyManager buddyManager;
-
- /**
- * State transfer manager. Do not access this field directly -- use the getter
- */
- private StateTransferManager stateTransferManager;
-
- /**
- * Cache notifier handler class.
- */
- private Notifier notifier;
-
- private ThreadLocal<InvocationContext> invocationContextContainer = new ThreadLocal<InvocationContext>()
- {
- @Override
- protected InvocationContext initialValue()
- {
- return new InvocationContext();
- }
- };
-
- private Configuration configuration;
-
- /**
- * Constructs an uninitialized CacheImpl.
- */
- protected CacheImpl() throws Exception
- {
- configuration = new Configuration(this);
- notifier = new Notifier(this);
- regionManager = new RegionManager(this);
- cacheStatus = CacheStatus.INSTANTIATED;
- }
-
- public StateTransferManager getStateTransferManager()
- {
- if (stateTransferManager == null)
- {
- stateTransferManager = new StateTransferManager(this);
- }
- return stateTransferManager;
- }
-
- public void setStateTransferManager(StateTransferManager manager)
- {
- this.stateTransferManager = manager;
- }
-
- public Configuration getConfiguration()
- {
- return configuration;
- }
-
- /**
- * Returns the CacheImpl implementation version.
- */
- public String getVersion()
- {
- return Version.printVersion();
- }
-
- /**
- * Returns the root node.
- */
- public NodeSPI<K, V> getRoot()
- {
- return root;
- }
-
- /**
- * Returns the local channel address.
- */
- public Address getLocalAddress()
- {
- return channel != null ? channel.getLocalAddress() : null;
- }
-
- /**
- * Returns the members as a List.
- * This list may be concurrently modified.
- */
- public List<Address> getMembers()
- {
- synchronized (members)
- {
- return new ArrayList<Address>(members);
- }
- }
-
- /**
- * Returns <code>true</code> if this node is the group coordinator.
- */
- public boolean isCoordinator()
- {
- return coordinator;
- }
-
- /**
- * Returns the transaction table.
- */
- public TransactionTable getTransactionTable()
- {
- return tx_table;
- }
-
- /**
- * Returns the lock table.
- */
- public Map<Thread, List<NodeLock>> getLockTable()
- {
- if (lock_table == null)
- {
- lock_table = new ConcurrentHashMap<Thread, List<NodeLock>>();
- }
- return lock_table;
- }
-
- /**
- * Returns the contents of the TransactionTable as a string.
- */
- public String dumpTransactionTable()
- {
- return tx_table.toString(true);
- }
-
- /**
- * Used for testing only - sets the interceptor chain.
- */
- public void setInterceptorChain(Interceptor i)
- {
- interceptor_chain = i;
- }
-
- /**
- * @return the list of interceptors.
- */
- public List<Interceptor> getInterceptors()
- {
- return InterceptorChainFactory.getInstance().asList(interceptor_chain);
- }
-
- /**
- * Returns the underlying cache loader in use.
- */
- public CacheLoader getCacheLoader()
- {
- if (cacheLoaderManager == null)
- return null;
- return cacheLoaderManager.getCacheLoader();
- }
-
- public String getEvictionInterceptorClass()
- {
- return this.evictionInterceptorClass;
- }
-
- private void setUseReplQueue(boolean flag)
- {
- if (flag)
- {
- if (repl_queue == null)
- {
- repl_queue = new ReplicationQueue(this, configuration.getReplQueueInterval(), configuration.getReplQueueMaxElements());
- if (configuration.getReplQueueInterval() >= 0)
- {
- repl_queue.start();
- }
- }
- }
- else
- {
- if (repl_queue != null)
- {
- repl_queue.stop();
- repl_queue = null;
- }
- }
- }
-
-
- /**
- * Returns the replication queue.
- */
- public ReplicationQueue getReplicationQueue()
- {
- return repl_queue;
- }
-
- /**
- * Sets the cache locking isolation level.
- */
- private void setIsolationLevel(IsolationLevel level)
- {
- LockStrategyFactory.setIsolationLevel(level);
- }
-
- /**
- * Sets the TransactionManagerLookup object
- */
- public void setTransactionManagerLookup(TransactionManagerLookup l)
- {
- this.tm_lookup = l;
- }
-
- /**
- * Returns the transaction manager in use.
- */
- public TransactionManager getTransactionManager()
- {
- return tm;
- }
-
- /**
- * Fetches the group state from the current coordinator. If successful, this
- * will trigger JChannel setState() call.
- */
- public void fetchState(long timeout) throws ChannelClosedException, ChannelNotConnectedException
- {
- if (channel == null)
- {
- throw new ChannelNotConnectedException();
- }
- boolean rc = channel.getState(null, timeout);
- if (rc)
- {
- log.debug("fetchState(): state was retrieved successfully");
- }
- else
- {
- log.debug("fetchState(): state could not be retrieved (first member)");
- }
- }
-
- void fetchPartialState(List<Address> sources, Fqn sourceTarget, Fqn integrationTarget) throws Exception
- {
- String encodedStateId = sourceTarget + StateTransferManager.PARTIAL_STATE_DELIMITER + integrationTarget;
- fetchPartialState(sources, encodedStateId);
- }
-
- void fetchPartialState(List<Address> sources, Fqn subtree) throws Exception
- {
- if (subtree == null)
- {
- throw new IllegalArgumentException("Cannot fetch partial state. Null subtree.");
- }
- fetchPartialState(sources, subtree.toString());
- }
-
- private void fetchPartialState(List<Address> sources, String stateId) throws Exception
- {
- if (sources == null || sources.isEmpty() || stateId == null)
- {
- // should this really be throwing an exception? Are there valid use cases where partial state may not be available? - Manik
- // Yes -- cache is configured LOCAL but app doesn't know it -- Brian
- //throw new IllegalArgumentException("Cannot fetch partial state, targets are " + sources + " and stateId is " + stateId);
- if (log.isWarnEnabled())
- {
- log.warn("Cannot fetch partial state, targets are " + sources +
- " and stateId is " + stateId);
- }
- return;
- }
-
- List<Address> targets = new LinkedList<Address>(sources);
-
- //skip *this* node as a target
- targets.remove(getLocalAddress());
-
- if (targets.isEmpty())
- {
- // Definitely no exception here -- this happens every time the 1st node in the
- // cluster activates a region!! -- Brian
- log.debug("Cannot fetch partial state. There are no target members specified");
- return;
- }
-
- log.debug("Node " + getLocalAddress() + " fetching partial state " + stateId + " from members " + targets);
- boolean successfulTransfer = false;
- for (Address target : targets)
- {
- log.debug("Node " + getLocalAddress() + " fetching partial state " + stateId + " from member " + target);
- isStateSet = false;
- successfulTransfer = channel.getState(target, stateId, configuration.getStateRetrievalTimeout());
- if (successfulTransfer)
- {
- try
- {
- ml.waitForState();
- }
- catch (Exception transferFailed)
- {
- successfulTransfer = false;
- }
- }
- log.debug("Node " + getLocalAddress() + " fetching partial state " + stateId + " from member " + target + (successfulTransfer ? " successful" : " failed"));
- if (successfulTransfer)
- break;
- }
-
- if (!successfulTransfer)
- {
- log.debug("Node " + getLocalAddress() + " could not fetch partial state " + stateId + " from any member " + targets);
- }
- }
-
- /**
- * Lifecycle method. This is like initialize.
- *
- * @throws Exception
- */
- public void create() throws CacheException
- {
- if (!cacheStatus.createAllowed())
- {
- if (cacheStatus.needToDestroyFailedCache())
- destroy();
- else
- return;
- }
-
- try
- {
- internalCreate();
- }
- catch (Throwable t)
- {
- handleLifecycleTransitionFailure(t);
- }
- }
-
- /**
- * Sets the cacheStatus to FAILED and rethrows the problem as one
- * of the declared types. Converts any non-RuntimeException Exception
- * to CacheException.
- *
- * @param t
- * @throws CacheException
- * @throws RuntimeException
- * @throws Error
- */
- private void handleLifecycleTransitionFailure(Throwable t)
- throws CacheException, RuntimeException, Error
- {
- cacheStatus = CacheStatus.FAILED;
- if (t instanceof CacheException)
- throw (CacheException) t;
- else if (t instanceof RuntimeException)
- throw (RuntimeException) t;
- else if (t instanceof Error)
- throw (Error) t;
- else
- throw new CacheException(t);
- }
-
- /**
- * The actual create implementation.
- *
- * @throws CacheException
- */
- private void internalCreate() throws CacheException
- {
- // Include our clusterName in our log category
- configureLogCategory();
-
- // initialise the node factory and set this in the runtime.
- NodeFactory<K, V> nf;
- if ((nf = configuration.getRuntimeConfig().getNodeFactory()) == null)
- {
- nf = new NodeFactory<K, V>(this);
- configuration.getRuntimeConfig().setNodeFactory(nf);
- }
- else
- {
- // don't create a new one each and every time. After stopping and starting the cache, the old NodeFactory may still be valid.
- nf.init();
- }
-
- if (notifier == null)
- notifier = new Notifier(this);
-
- // create a new root temporarily.
- NodeSPI<K, V> tempRoot = nf.createRootDataNode();
- // if we don't already have a root or the new (temp) root is of a different class (optimistic vs pessimistic) to
- // the current root, then we use the new one. Helps preserve data between cache restarts.
- if (root == null || !root.getClass().equals(tempRoot.getClass()))
- root = tempRoot;
-
- if (configuration.getCacheLoaderConfig() != null && cacheLoaderManager == null)
- {
- initialiseCacheLoaderManager();
- }
- // first set up the Buddy Manager and an RPCManager
- if (configuration.getCacheMode() != Configuration.CacheMode.LOCAL)
- {
- getConfiguration().getRuntimeConfig().setRPCManager(new RPCManagerImpl(this));
- setBuddyReplicationConfig(configuration.getBuddyReplicationConfig());
- }
- // build interceptor chain
- try
- {
- interceptor_chain = InterceptorChainFactory.getInstance().buildInterceptorChain(this);
- }
- catch (Exception e)
- {
- throw new CacheException("Unable to build interceptor chain", e);
- }
-
-
- setUseReplQueue(configuration.isUseReplQueue());
- setIsolationLevel(configuration.getIsolationLevel());
-
- getRegionManager();// make sure we create one
- createEvictionPolicy();
-
- getRegionManager().setDefaultInactive(configuration.isInactiveOnStartup());
-
- cacheStatus = CacheStatus.CREATED;
- }
-
- private void createTransactionManager()
- {
- // See if we had a TransactionManager injected into our config
- this.tm = configuration.getRuntimeConfig().getTransactionManager();
- if (tm == null)
- {
- // Nope. See if we can look it up from JNDI
- if (this.tm_lookup == null && configuration.getTransactionManagerLookupClass() != null)
- {
- try
- {
- Class clazz = Thread.currentThread().getContextClassLoader().loadClass(configuration.getTransactionManagerLookupClass());
- this.tm_lookup = (TransactionManagerLookup) clazz.newInstance();
- }
- catch (Exception e)
- {
- throw new CacheException("Problems creating the cache", e);
- }
- }
-
- try
- {
- if (tm_lookup != null)
- {
- tm = tm_lookup.getTransactionManager();
- configuration.getRuntimeConfig().setTransactionManager(tm);
- }
- else
- {
- if (configuration.getNodeLockingScheme() == NodeLockingScheme.OPTIMISTIC)
- {
- log.fatal("No transaction manager lookup class has been defined. Transactions cannot be used and thus OPTIMISTIC locking cannot be used");
- }
- else
- {
- log.info("No transaction manager lookup class has been defined. Transactions cannot be used");
- }
- }
- }
- catch (Exception e)
- {
- log.debug("failed looking up TransactionManager, will not use transactions", e);
- }
- }
- }
-
- protected boolean shouldFetchStateOnStartup()
- {
- boolean loaderFetch = cacheLoaderManager != null && cacheLoaderManager.isFetchPersistentState();
- return !configuration.isInactiveOnStartup() && buddyManager == null && (configuration.isFetchInMemoryState() || loaderFetch);
- }
-
- /**
- * Lifecyle method.
- *
- * @throws CacheException
- */
- public void start() throws CacheException
- {
- if (!cacheStatus.startAllowed())
- {
- if (cacheStatus.needToDestroyFailedCache())
- destroy(); // this will take us back to DESTROYED
-
- if (cacheStatus.needCreateBeforeStart())
- create();
- else
- return;
- }
-
- try
- {
- internalStart();
- }
- catch (Throwable t)
- {
- handleLifecycleTransitionFailure(t);
- }
- }
-
- /**
- * The actual start implementation.
- *
- * @throws CacheException
- * @throws IllegalArgumentException
- */
- private void internalStart() throws CacheException, IllegalArgumentException
- {
- cacheStatus = CacheStatus.STARTING;
-
- createTransactionManager();
-
- // cache loaders should be initialised *before* any state transfers take place to prevent
- // exceptions involving cache loaders not being started. - Manik
- // create cache loader
- if (cacheLoaderManager != null)
- {
- cacheLoaderManager.startCacheLoader();
- }
- // now that we have a TM we can init the interceptor chain
- InterceptorChainFactory.getInstance().initialiseInterceptors(interceptor_chain, this);
-
- switch (configuration.getCacheMode())
- {
- case LOCAL:
- log.debug("cache mode is local, will not create the channel");
- break;
- case REPL_SYNC:
- case REPL_ASYNC:
- case INVALIDATION_ASYNC:
- case INVALIDATION_SYNC:
- if (log.isDebugEnabled()) log.debug("cache mode is " + configuration.getCacheMode());
- initialiseChannelAndRpcDispatcher();
-
- try
- {
- channel.connect(configuration.getClusterName());
- }
- catch (ChannelException e)
- {
- throw new CacheException("Unable to connect to JGroups channel", e);
- }
-
- if (log.isInfoEnabled())
- {
- log.info("CacheImpl local address is " + channel.getLocalAddress());
- }
- if (shouldFetchStateOnStartup())
- {
- try
- {
- fetchStateOnStartup();
- }
- catch (Exception e)
- {
- // make sure we disconnect from the channel before we throw this exception!
- // JBCACHE-761
- channel.disconnect();
- channel.close();
- throw new CacheException("Unable to fetch state on startup", e);
- }
- }
- if (buddyManager != null)
- {
- buddyManager.init(this);
- if (configuration.isUseReplQueue())
- {
- log.warn("Replication queue not supported when using buddy replication. Disabling repliction queue.");
- configuration.setUseReplQueue(false);
- repl_queue = null;
- }
- }
- break;
- default:
- throw new IllegalArgumentException("cache mode " + configuration.getCacheMode() + " is invalid");
- }
-
- //now attempt to preload the cache from the loader - Manik
- if (cacheLoaderManager != null)
- {
- cacheLoaderManager.preloadCache();
- }
-
- // Find out if we are coordinator (blocks until view is received)
- determineCoordinator();
-
- // start any eviction threads.
- if (regionManager.isUsingEvictions())
- {
- regionManager.startEvictionThread();
- }
-
- notifier.notifyCacheStarted(this, getInvocationContext());
-
- // install a VM shutdown hook
- Thread shutdownHook = new Thread()
- {
- public void run()
- {
- CacheImpl.this.stop();
- }
- };
-
- Runtime.getRuntime().addShutdownHook(shutdownHook);
-
- log.info("JBoss Cache version: " + getVersion());
-
- cacheStatus = CacheStatus.STARTED;
- }
-
- /**
- * Lifecycle method.
- */
- public void destroy()
- {
- if (!cacheStatus.destroyAllowed())
- {
- if (cacheStatus.needStopBeforeDestroy())
- {
- try
- {
- stop();
- }
- catch (CacheException e)
- {
- log.warn("Needed to call stop() before destroying but stop() " +
- "threw exception. Proceeding to destroy", e);
- }
- }
- else
- return;
- }
-
- try
- {
- internalDestroy();
- }
- finally
- {
- // We always progress to destroyed
- cacheStatus = CacheStatus.DESTROYED;
- }
- }
-
- /**
- * The actual destroy implementation.
- */
- private void internalDestroy()
- {
- cacheStatus = CacheStatus.DESTROYING;
- regionManager = null;
- notifier = null;
-
- // The rest of these should have already been taken care of in stop,
- // but we do it here as well in case stop failed.
-
- if (channel != null)
- {
- if (channel.isOpen())
- {
- try
- {
- channel.close();
- channel.disconnect();
- }
- catch (Exception toLog)
- {
- log.error("Problem closing channel; setting it to null", toLog);
- }
- }
- channel = null;
- configuration.getRuntimeConfig().setChannel(null);
- }
- disp = null;
- tm = null;
- }
-
- /**
- * Lifecycle method.
- */
- public void stop()
- {
- if (!cacheStatus.stopAllowed())
- {
- return;
- }
-
- // Trying to stop() from FAILED is valid, but may not work
- boolean failed = cacheStatus == CacheStatus.FAILED;
-
- try
- {
- internalStop();
- }
- catch (Throwable t)
- {
- if (failed)
- {
- log.warn("Attempted to stop() from FAILED state, " +
- "but caught exception; try calling destroy()", t);
- }
- handleLifecycleTransitionFailure(t);
- }
- }
-
- /**
- * The actual stop implementation.
- */
- private void internalStop()
- {
- cacheStatus = CacheStatus.STOPPING;
-
- // before closing the channel stop the buddy manager
- if (buddyManager != null && buddyManager.isEnabled())
- {
- log.debug("stop(): stopping buddy manager");
- buddyManager.stop();
- }
-
- if (channel != null)
- {
- log.info("stop(): closing the channel");
- killChannel();
- channel = null;
- configuration.getRuntimeConfig().setChannel(null);
- }
-
- if (disp != null)
- {
- log.info("stop(): stopping the dispatcher");
- disp.stop();
- disp = null;
- }
- if (members != null)
- {
- synchronized (members)
- {
- members.clear();
- }
- }
-
- coordinator = false;
-
- if (repl_queue != null)
- {
- repl_queue.stop();
- }
-
- if (cacheLoaderManager != null)
- {
- log.debug("stop(): stopping cache loader manager");
- cacheLoaderManager.stopCacheLoader();
- }
-
- if (regionManager.isUsingEvictions()) regionManager.stopEvictionThread();
-
- if (notifier != null)
- {
- notifier.notifyCacheStopped(this, getInvocationContext());
- notifier.removeAllCacheListeners();
- }
-
- // unset transaction manager reference
- tm = null;
-
- cacheStatus = CacheStatus.STOPPED;
-
- // empty in-memory state
- root.clearDataDirect();
- root.removeChildrenDirect();
- }
-
- public CacheStatus getCacheStatus()
- {
- return cacheStatus;
- }
-
- /* ----------------------- End of MBeanSupport ----------------------- */
-
- /* ----------------------- Start of buddy replication specific methods ------------*/
-
- /**
- * Sets the buddy replication configuration element
- *
- * @param config
- */
- private void setBuddyReplicationConfig(BuddyReplicationConfig config)
- {
- if (config != null)
- {
- buddyManager = new BuddyManager(config);
- if (!buddyManager.isEnabled())
- {
- buddyManager = null;
- }
- else
- {
- internalFqns.add(BuddyManager.BUDDY_BACKUP_SUBTREE_FQN);
- }
- }
- }
-
- /**
- * Retrieves the Buddy Manager configured.
- *
- * @return null if buddy replication is not enabled.
- */
- public BuddyManager getBuddyManager()
- {
- return buddyManager;
- }
-
- /**
- * Returns a Set<Fqn> of Fqns of the topmost node of internal regions that
- * should not included in standard state transfers. Will include
- * {@link BuddyManager#BUDDY_BACKUP_SUBTREE} if buddy replication is
- * enabled.
- *
- * @return an unmodifiable Set<Fqn>. Will not return <code>null</code>.
- */
- public Set<Fqn> getInternalFqns()
- {
- return Collections.unmodifiableSet(internalFqns);
- }
-
- /* ----------------------- End of buddy replication specific methods ------------*/
-
- protected void createEvictionPolicy()
- {
- if (configuration.getEvictionConfig() != null
- && configuration.getEvictionConfig().isValidConfig())
- {
- regionManager.setEvictionConfig(configuration.getEvictionConfig());
- regionManager.setUsingEvictions(true);
- }
- else
- {
- regionManager.setUsingEvictions(false);
- log.debug("Not using an EvictionPolicy");
- }
- }
-
- /**
- * Loads the indicated Fqn, plus all parents recursively from the
- * CacheLoader. If no CacheLoader is present, this is a no-op
- *
- * @param fqn
- * @throws Exception
- */
- public void load(String fqn) throws Exception
- {
- if (cacheLoaderManager != null)
- {
- cacheLoaderManager.preload(Fqn.fromString(fqn), true, true);
- }
- }
-
- private void determineCoordinator()
- {
- // Synchronize on members to make the answer atomic for the current view
- synchronized (members)
- {
- Address coord = getCoordinator();
- coordinator = (coord == null ? false : coord.equals(getLocalAddress()));
- }
- }
-
- /**
- * Returns the address of the coordinator or null if there is no
- * coordinator.
- * Waits until the membership view is updated.
- */
- public Address getCoordinator()
- {
- if (channel == null)
- {
- return null;
- }
-
- synchronized (members)
- {
- while (members.isEmpty())
- {
- log.debug("getCoordinator(): waiting on viewAccepted()");
- try
- {
- members.wait();
- }
- catch (InterruptedException e)
- {
- log.error("getCoordinator(): Interrupted while waiting for members to be set", e);
- break;
- }
- }
- return members.size() > 0 ? members.get(0) : null;
- }
- }
-
- // ----------- Marshalling and State Transfer -----------------------
-
- /**
- * Creates a subtree in the local cache.
- * Returns the DataNode created.
- */
- protected Node createSubtreeRootNode(Fqn<?> subtree) throws CacheException
- {
- NodeSPI<K, V> parent = root;
- NodeSPI<K, V> child = null;
- Object owner = getOwnerForLock();
- Object name;
- NodeFactory<K, V> factory = configuration.getRuntimeConfig().getNodeFactory();
-
- for (int i = 0; i < subtree.size(); i++)
- {
- name = subtree.get(i);
- child = parent.getChildDirect(name);
- if (child == null)
- {
- // Lock the parent, create and add the child
- try
- {
- parent.getLock().acquire(owner, configuration.getSyncReplTimeout(), NodeLock.LockType.WRITE);
- }
- catch (InterruptedException e)
- {
- log.error("Interrupted while locking" + parent.getFqn(), e);
- throw new CacheException(e.getLocalizedMessage(), e);
- }
-
- try
- {
- child = factory.createDataNode(name,
- subtree.getAncestor(i + 1),
- parent, null, true);
- parent.addChild(name, child);
- }
- finally
- {
- if (log.isDebugEnabled())
- {
- log.debug("forcing release of locks in " + parent.getFqn());
- }
- try
- {
- parent.getLock().releaseAll();
- }
- catch (Throwable t)
- {
- log.error("failed releasing locks", t);
- }
- }
- }
-
- parent = child;
- }
-
- return child;
- }
-
- /**
- * Evicts the node at <code>subtree</code> along with all descendant nodes.
- *
- * @param subtree Fqn indicating the uppermost node in the
- * portion of the cache that should be evicted.
- * @throws CacheException
- */
- protected void _evictSubtree(Fqn subtree) throws CacheException
- {
-
- if (!exists(subtree))
- {
- return;// node does not exist. Maybe it has been recursively removed.
- }
-
- if (log.isTraceEnabled())
- {
- log.trace("_evictSubtree(" + subtree + ")");
- }
-
- // Recursively remove any children
- Set children = getChildrenNames(subtree);
- if (children != null)
- {
- for (Object s : children)
- {
-
- Fqn<Object> tmp = new Fqn<Object>(subtree, s);
- _remove(null, // no tx
- tmp,
- false, // no undo ops
- false, // no nodeEvent
- true);// is an eviction
- }
- }
-
- // Remove the root node of the subtree
- _remove(null, subtree, false, false, true);
-
- }
-
- private void removeLocksForDeadMembers(NodeSPI<K, V> node, List deadMembers)
- {
- Set<GlobalTransaction> deadOwners = new HashSet<GlobalTransaction>();
- NodeLock lock = node.getLock();
- Object owner = lock.getWriterOwner();
-
- if (isLockOwnerDead(owner, deadMembers))
- {
- deadOwners.add((GlobalTransaction) owner);
- }
-
- for (Object readOwner : lock.getReaderOwners())
- {
- if (isLockOwnerDead(readOwner, deadMembers))
- {
- deadOwners.add((GlobalTransaction) readOwner);
- }
- }
-
- for (GlobalTransaction deadOwner : deadOwners)
- {
- boolean localTx = deadOwner.getAddress().equals(getLocalAddress());
- boolean broken = LockUtil.breakTransactionLock(lock, deadOwner, localTx, this);
-
- if (broken && log.isTraceEnabled())
- {
- log.trace("Broke lock for node " + node.getFqn() +
- " held by " + deadOwner);
- }
- }
-
- // Recursively unlock children
- for (NodeSPI<K, V> child : node.getChildrenDirect())
- {
- removeLocksForDeadMembers(child, deadMembers);
- }
- }
-
- private boolean isLockOwnerDead(Object owner, List deadMembers)
- {
- boolean result = false;
- if (owner != null && owner instanceof GlobalTransaction)
- {
- Object addr = ((GlobalTransaction) owner).getAddress();
- result = deadMembers.contains(addr);
- }
- return result;
- }
-
- protected void fetchStateOnStartup() throws Exception
- {
- long start, stop;
- isStateSet = false;
- start = System.currentTimeMillis();
- boolean rc = channel.getState(null, configuration.getStateRetrievalTimeout());
- if (rc)
- {
- ml.waitForState();
- stop = System.currentTimeMillis();
- if (log.isDebugEnabled())
- {
- log.debug("state was retrieved successfully (in " + (stop - start) + " milliseconds)");
- }
- }
- else
- {
- // No one provided us with state. We need to find out if that's because
- // we are the coordinator. But we don't know if the viewAccepted() callback
- // has been invoked, so call determineCoordinator(), which will block until
- // viewAccepted() is called at least once
- determineCoordinator();
-
- if (isCoordinator())
- {
- log.debug("State could not be retrieved (we are the first member in group)");
- }
- else
- {
- throw new CacheException("Initial state transfer failed: " +
- "Channel.getState() returned false");
- }
- }
- }
-
- // ----------- End Marshalling and State Transfer -----------------------
-
- /**
- * @param fqn fqn String name to retrieve from cache
- * @return DataNode corresponding to the fqn. Null if does not exist. No guarantees wrt replication,
- * cache loading are given if the underlying node is modified
- */
- public Node get(String fqn) throws CacheException
- {
- return get(Fqn.fromString(fqn));
- }
-
- /**
- * Returns a DataNode corresponding to the fully qualified name or null if
- * does not exist.
- * No guarantees wrt replication, cache loading are given if the underlying node is modified
- *
- * @param fqn name of the DataNode to retreive
- */
- public Node<K, V> get(Fqn<?> fqn) throws CacheException
- {
- MethodCall m = MethodCallFactory.create(MethodDeclarations.getNodeMethodLocal, fqn);
- return (Node<K, V>) invokeMethod(m, true);
- }
-
- /**
- * Returns the raw data of the node; called externally internally.
- */
- public Node<K, V> _get(Fqn<?> fqn) throws CacheException
- {
- return findNode(fqn);
- }
-
- /**
- * Returns the raw data of the node; called externally internally.
- */
- public Map _getData(Fqn<?> fqn)
- {
- NodeSPI n = findNode(fqn);
- if (n == null) return null;
- return n.getDataDirect();
- }
-
- /**
- * Returns a set of attribute keys for the Fqn.
- * Returns null if the node is not found, otherwise a Set.
- * The set is a copy of the actual keys for this node.
- *
- * @param fqn name of the node
- */
- public Set getKeys(String fqn) throws CacheException
- {
- return getKeys(Fqn.fromString(fqn));
- }
-
- /**
- * Returns a set of attribute keys for the Fqn.
- * Returns null if the node is not found, otherwise a Set.
- * The set is a copy of the actual keys for this node.
- *
- * @param fqn name of the node
- */
- public Set<K> getKeys(Fqn<?> fqn) throws CacheException
- {
- MethodCall m = MethodCallFactory.create(MethodDeclarations.getKeysMethodLocal, fqn);
- return (Set<K>) invokeMethod(m, true);
- }
-
-
- /**
- * Retrieves a defensively copied data map of the underlying node.
- *
- * @param fqn
- * @return map of data, or an empty map
- * @throws CacheException
- */
- public Map<K, V> getData(Fqn<?> fqn) throws CacheException
- {
- MethodCall m = MethodCallFactory.create(MethodDeclarations.getDataMapMethodLocal, fqn);
- return (Map<K, V>) invokeMethod(m, true);
- }
-
- public Set _getKeys(Fqn<?> fqn) throws CacheException
- {
- NodeSPI<K, V> n = findNode(fqn);
- if (n == null)
- {
- return null;
- }
- Set<K> keys = n.getKeysDirect();
- return new HashSet<K>(keys);
- }
-
- /**
- * Finds a node given its name and returns the value associated with a given key in its <code>data</code>
- * map. Returns null if the node was not found in the cache or the key was not found in the hashmap.
- *
- * @param fqn The fully qualified name of the node.
- * @param key The key.
- */
- public V get(String fqn, K key) throws CacheException
- {
- return get(Fqn.fromString(fqn), key);
- }
-
-
- /**
- * Finds a node given its name and returns the value associated with a given key in its <code>data</code>
- * map. Returns null if the node was not found in the cache or the key was not found in the hashmap.
- *
- * @param fqn The fully qualified name of the node.
- * @param key The key.
- */
- public V get(Fqn<?> fqn, K key) throws CacheException
- {
- return get(fqn, key, true);
- }
-
- public V _get(Fqn<?> fqn, K key, boolean sendNodeEvent) throws CacheException
- {
- InvocationContext ctx = getInvocationContext();
- if (log.isTraceEnabled())
- {
- log.trace(new StringBuffer("_get(").append("\"").append(fqn).append("\", \"").append(key).append("\", \"").
- append(sendNodeEvent).append("\")"));
- }
- if (sendNodeEvent) notifier.notifyNodeVisited(fqn, true, ctx);
- NodeSPI<K, V> n = findNode(fqn);
- if (n == null)
- {
- log.trace("node not found");
- return null;
- }
- if (sendNodeEvent) notifier.notifyNodeVisited(fqn, false, ctx);
- return n.getDirect(key);
- }
-
-
- protected V get(Fqn<?> fqn, K key, boolean sendNodeEvent) throws CacheException
- {
- MethodCall m = MethodCallFactory.create(MethodDeclarations.getKeyValueMethodLocal, fqn, key, sendNodeEvent);
- return (V) invokeMethod(m, true);
- }
-
- /**
- * Checks whether a given node exists in current in-memory state of the cache.
- * Does not acquire any locks in doing so (result may be dirty read). Does
- * not attempt to load nodes from a cache loader (may return false if a
- * node has been evicted).
- *
- * @param fqn The fully qualified name of the node
- * @return boolean Whether or not the node exists
- */
- public boolean exists(String fqn)
- {
- return exists(Fqn.fromString(fqn));
- }
-
-
- /**
- * Checks whether a given node exists in current in-memory state of the cache.
- * Does not acquire any locks in doing so (result may be dirty read). Does
- * not attempt to load nodes from a cache loader (may return false if a
- * node has been evicted).
- *
- * @param fqn The fully qualified name of the node
- * @return boolean Whether or not the node exists
- */
- public boolean exists(Fqn<?> fqn)
- {
- Node n = peek(fqn, false);
- return n != null;
- }
-
- /**
- * Gets node without attempt to load it from CacheLoader if not present
- *
- * @param fqn
- */
- public NodeSPI<K, V> peek(Fqn<?> fqn, boolean includeDeletedNodes)
- {
- if (fqn == null || fqn.size() == 0) return root;
- NodeSPI<K, V> n = root;
- int fqnSize = fqn.size();
- for (int i = 0; i < fqnSize; i++)
- {
- Object obj = fqn.get(i);
- n = n.getChildDirect(obj);
- if (n == null)
- {
- return null;
- }
- else if (!includeDeletedNodes && n.isDeleted())
- {
- return null;
- }
- }
- return n;
- }
-
-
- /**
- * @param fqn
- * @param key
- */
- public boolean exists(String fqn, Object key)
- {
- return exists(Fqn.fromString(fqn), key);
- }
-
-
- /**
- * Checks whether a given key exists in the given node. Does not interact with CacheLoader, so the behavior is
- * different from {@link #get(Fqn,Object)}
- *
- * @param fqn The fully qualified name of the node
- * @param key
- * @return boolean Whether or not the node exists
- */
- public boolean exists(Fqn<?> fqn, Object key)
- {
- NodeSPI n = peek(fqn, false);
- return n != null && n.getKeysDirect().contains(key);
- }
-
-
- /**
- * Adds a new node to the cache and sets its data. If the node doesn not yet exist, it will be created.
- * Also, parent nodes will be created if not existent. If the node already has data, then the new data
- * will override the old one. If the node already existed, a nodeModified() notification will be generated.
- * Otherwise a nodeCreated() motification will be emitted.
- *
- * @param fqn The fully qualified name of the new node
- * @param data The new data. May be null if no data should be set in the node.
- */
- public void put(String fqn, Map data) throws CacheException
- {
- put(Fqn.fromString(fqn), data);
- }
-
- /**
- * Sets a node's data. If the node does not yet exist, it will be created.
- * Also, parent nodes will be created if not existent. If the node already has data, then the new data
- * will override the old one. If the node already existed, a nodeModified() notification will be generated.
- * Otherwise a nodeCreated() motification will be emitted.
- *
- * @param fqn The fully qualified name of the new node
- * @param data The new data. May be null if no data should be set in the node.
- */
- public void put(Fqn<?> fqn, Map<K, V> data) throws CacheException
- {
- put(fqn, data, false);
- }
-
- public void put(Fqn<?> fqn, Map<K, V> data, boolean erase) throws CacheException
- {
- GlobalTransaction tx = getCurrentTransaction();
- MethodCall m;
- if (erase)
- {
- m = MethodCallFactory.create(MethodDeclarations.putDataEraseMethodLocal, tx, fqn, data, true, true);
- }
- else
- {
- m = MethodCallFactory.create(MethodDeclarations.putDataMethodLocal, tx, fqn, data, true);
- }
- invokeMethod(m, true);
- }
-
- /**
- * Adds a key and value to a given node. If the node doesn't exist, it will be created. If the node
- * already existed, a nodeModified() notification will be generated. Otherwise a
- * nodeCreated() motification will be emitted.
- *
- * @param fqn The fully qualified name of the node
- * @param key The key
- * @param value The value
- * @return Object The previous value (if any), if node was present
- */
- public V put(String fqn, K key, V value) throws CacheException
- {
- return put(Fqn.fromString(fqn), key, value);
- }
-
- /**
- * Adds a key and value to a given node. If the node doesn't exist, it will be created. If the node
- * already existed, a nodeModified() notification will be generated. Otherwise a
- * nodeCreated() motification will be emitted.
- *
- * @param fqn The fully qualified name of the node
- * @param key The key
- * @param value The value
- * @return Object The previous value (if any), if node was present
- */
- public V put(Fqn<?> fqn, K key, V value) throws CacheException
- {
- GlobalTransaction tx = getCurrentTransaction();
- MethodCall m = MethodCallFactory.create(MethodDeclarations.putKeyValMethodLocal, tx, fqn, key, value, true);
- return (V) invokeMethod(m, true);
- }
-
- /**
- * Removes the node from the cache.
- *
- * @param fqn The fully qualified name of the node.
- */
- public void remove(String fqn) throws CacheException
- {
- remove(Fqn.fromString(fqn));
- }
-
- /**
- * Removes the node from the cache.
- *
- * @param fqn The fully qualified name of the node.
- */
- public boolean remove(Fqn fqn) throws CacheException
- {
- GlobalTransaction tx = getCurrentTransaction();
- // special case if we are removing the root. Remove all children instead.
- if (fqn.isRoot())
- {
- boolean result = true;
- // we need to preserve options
- InvocationContext ctx = getInvocationContext();
- Option o = ctx.getOptionOverrides();
- for (Object childName : _getChildrenNames(fqn))
- {
- ctx.setOptionOverrides(o);
- result = remove(new Fqn<Object>(fqn, childName)) && result;
- }
-
- return result;
- }
- else
- {
- MethodCall m = MethodCallFactory.create(MethodDeclarations.removeNodeMethodLocal, tx, fqn, true);
- Object retval = invokeMethod(m, true);
- return retval != null && (Boolean) retval;
- }
- }
-
- /**
- * Called by eviction policy provider. Note that eviction is done only in
- * local mode, that is, it doesn't replicate the node removal. This will
- * cause the replication nodes to not be synchronizing, which is fine since
- * the value will be fetched again when {@link #get} returns null. After
- * that, the contents will be in sync.
- *
- * @param fqn Will remove everythign assoicated with this fqn.
- * @throws CacheException
- */
- public void evict(Fqn fqn) throws CacheException
- {
- if (fqn.isRoot())
- {
- // special treatment for root eviction
- // we need to preserve options
- InvocationContext ctx = getInvocationContext();
- Option o = ctx.getOptionOverrides();
- for (Object childName : _getChildrenNames(fqn))
- {
- ctx.setOptionOverrides(o);
- evict(new Fqn<Object>(fqn, childName));
- }
- }
- else
- {
- MethodCall m = MethodCallFactory.create(MethodDeclarations.evictNodeMethodLocal, fqn);
- invokeMethod(m, true);
- }
- }
-
- /**
- * Removes <code>key</code> from the node's hashmap
- *
- * @param fqn The fullly qualified name of the node
- * @param key The key to be removed
- * @return The previous value, or null if none was associated with the given key
- */
- public V remove(String fqn, K key) throws CacheException
- {
- return remove(Fqn.fromString(fqn), key);
- }
-
- /**
- * Removes <code>key</code> from the node's hashmap
- *
- * @param fqn The fullly qualified name of the node
- * @param key The key to be removed
- * @return The previous value, or null if none was associated with the given key
- */
- public V remove(Fqn<?> fqn, K key) throws CacheException
- {
- GlobalTransaction tx = getCurrentTransaction();
- MethodCall m = MethodCallFactory.create(MethodDeclarations.removeKeyMethodLocal, tx, fqn, key, true);
- return (V) invokeMethod(m, true);
- }
-
- /**
- * Removes the keys and properties from a node.
- */
- public void removeData(String fqn) throws CacheException
- {
- removeData(Fqn.fromString(fqn));
- }
-
- /**
- * Removes the keys and properties from a named node.
- */
- public void removeData(Fqn fqn) throws CacheException
- {
- GlobalTransaction tx = getCurrentTransaction();
- MethodCall m = MethodCallFactory.create(MethodDeclarations.removeDataMethodLocal, tx, fqn, true);
- invokeMethod(m, true);
- }
-
- /**
- * Lock a given node (or the entire subtree starting at this node)
- * @param fqn The FQN of the node
- * @param owner The owner. This is simply a key into a hashtable, and can be anything, e.g.
- * a GlobalTransaction, the current thread, or a special object. If null, it is set to Thread.currentThread()
- * @param lock_type The type of lock (RO, RW). Needs to be of type DataNode.LOCK_TYPE_READ or DataNode.LOCK_TYPE_WRITE
- * @param lock_recursive If true, the entire subtree is locked, else only the given node
- * @throws CacheException If node doesn't exist, a NodeNotExistsException is throw. Other exceptions are
- * LockingException, TimeoutException and UpgradeException
- */
- // public void lock(Fqn fqn, Object owner, int lock_type, boolean lock_recursive) throws CacheException {
- //
- // }
-
- /**
- * Unlock a given node (or the entire subtree starting at this node)
- * @param fqn The FQN of the node
- * @param owner The owner. This is simply a key into a hashtable, and can be anything, e.g.
- * a GlobalTransaction, the current thread, or a special object. If null, it is set to Thread.currentThread()
- * @param unlock_recursive If true, the entire subtree is unlocked, else only the given node
- * @param force Release the lock even if we're not the owner
- */
- // public void unlock(Fqn fqn, Object owner, boolean unlock_recursive, boolean force) {
- //
- // }
-
- /**
- * Releases all locks for this node and the entire node subtree.
- */
- public void releaseAllLocks(String fqn)
- {
- releaseAllLocks(Fqn.fromString(fqn));
- }
-
- /**
- * Releases all locks for this node and the entire node subtree.
- */
- public void releaseAllLocks(Fqn fqn)
- {
- MethodCall m = MethodCallFactory.create(MethodDeclarations.releaseAllLocksMethodLocal, fqn);
- try
- {
- invokeMethod(m, true);
- }
- catch (CacheException e)
- {
- log.error("failed releasing all locks for " + fqn, e);
- }
- }
-
- /**
- * Prints a representation of the node defined by <code>fqn</code>.
- * Output includes name, fqn and data.
- */
- public String print(String fqn)
- {
- return print(Fqn.fromString(fqn));
- }
-
- /**
- * Prints a representation of the node defined by <code>fqn</code>.
- * Output includes name, fqn and data.
- */
- public String print(Fqn fqn)
- {
- MethodCall m = MethodCallFactory.create(MethodDeclarations.printMethodLocal, fqn);
- Object retval = null;
- try
- {
- retval = invokeMethod(m, true);
- }
- catch (Throwable e)
- {
- retval = e;
- }
- if (retval != null)
- {
- return retval.toString();
- }
- else
- {
- return "";
- }
- }
-
-
- /**
- * Returns all children of a given node.
- * Returns null of the parent node was not found, or if there are no
- * children.
- * The set is unmodifiable.
- *
- * @param fqn The fully qualified name of the node
- * @return Set A list of child names (as Strings)
- * @see #getChildrenNames(Fqn)
- */
- public Set getChildrenNames(String fqn) throws CacheException
- {
- return getChildrenNames(Fqn.fromString(fqn));
- }
-
- /**
- * Returns all children of a given node. Returns an empty set if there are no children.
- * The set is unmodifiable.
- *
- * @param fqn The fully qualified name of the node
- * @return Set an unmodifiable set of children names, Object.
- */
- public <E> Set<E> getChildrenNames(Fqn<E> fqn) throws CacheException
- {
- MethodCall m = MethodCallFactory.create(MethodDeclarations.getChildrenNamesMethodLocal, fqn);
- Set<E> retval = null;
- retval = (Set<E>) invokeMethod(m, true);
- if (retval != null)
- retval = Collections.unmodifiableSet(new HashSet<E>(retval));
- else
- retval = Collections.emptySet();
- return retval;
- }
-
- public <E> Set<E> _getChildrenNames(Fqn<E> fqn) throws CacheException
- {
- NodeSPI<K, V> n = findNode(fqn);
- if (n == null) return null;
- Set childNames = new HashSet();
- Map childrenMap = n.getChildrenMapDirect();
- if (childrenMap == null || childrenMap.isEmpty()) return Collections.emptySet();
- Collection s = childrenMap.values();
- // prune deleted children - JBCACHE-1136
- for (Object c : s)
- {
- NodeSPI child = (NodeSPI) c;
- if (!child.isDeleted()) childNames.add(child.getFqn().getLastElement());
- }
- return childNames;
- }
-
- /**
- * Returns true if the FQN exists and the node has children.
- */
- public boolean hasChild(Fqn fqn)
- {
- if (fqn == null) return false;
-
- NodeSPI n = findNode(fqn);
- return n != null && n.hasChildrenDirect();
- }
-
- /**
- * Returns a debug string with few details.
- */
- public String toString()
- {
- return toString(true);
- }
-
-
- /**
- * Returns a debug string with optional details of contents.
- */
- public String toString(boolean details)
- {
- StringBuffer sb = new StringBuffer();
- int indent = 0;
-
- if (!details)
- {
- sb.append(getClass().getName()).append(" [").append(getNumberOfNodes()).append(" nodes, ");
- sb.append(getNumberOfLocksHeld()).append(" locks]");
- }
- else
- {
- if (root == null)
- return sb.toString();
- for (NodeSPI n : root.getChildrenDirect())
- {
- n.print(sb, indent);
- sb.append("\n");
- }
- }
- return sb.toString();
- }
-
-
- /**
- * Prints information about the contents of the nodes in the cache's current
- * in-memory state. Does not load any previously evicted nodes from a
- * cache loader, so evicted nodes will not be included.
- */
- public String printDetails()
- {
- StringBuffer sb = new StringBuffer();
- root.printDetails(sb, 0);
- sb.append("\n");
- return sb.toString();
- }
-
- /**
- * Returns lock information.
- */
- public String printLockInfo()
- {
- StringBuffer sb = new StringBuffer("\n");
- int indent = 0;
-
- for (NodeSPI n : root.getChildrenDirect())
- {
- n.getLock().printLockInfo(sb, indent);
- sb.append("\n");
- }
- return sb.toString();
- }
-
- /**
- * Returns the number of read or write locks held across the entire cache.
- */
- public int getNumberOfLocksHeld()
- {
- return numLocks(root);
- }
-
- private int numLocks(NodeSPI<K, V> n)
- {
- int num = 0;
- if (n.getLock().isLocked())
- {
- num++;
- }
- for (NodeSPI<K, V> cn : n.getChildrenDirect(true))
- {
- num += numLocks(cn);
- }
- return num;
- }
-
- /**
- * Returns an <em>approximation</em> of the total number of nodes in the
- * cache. Since this method doesn't acquire any locks, the number might be
- * incorrect, or the method might even throw a
- * ConcurrentModificationException
- */
- public int getNumberOfNodes()
- {
- return numNodes(root) - 1;
- }
-
- private int numNodes(NodeSPI<K, V> n)
- {
- int count = 1;// for n
- for (NodeSPI<K, V> child : n.getChildrenDirect())
- {
- count += numNodes(child);
- }
- return count;
- }
-
- /**
- * Returns an <em>approximation</em> of the total number of attributes in
- * the cache. Since this method doesn't acquire any locks, the number might
- * be incorrect, or the method might even throw a
- * ConcurrentModificationException
- */
- public int getNumberOfAttributes()
- {
- return numAttributes(root);
- }
-
- /**
- * Returns an <em>approximation</em> of the total number of attributes in
- * this sub cache.
- *
- * @see #getNumberOfAttributes
- */
- public int getNumberOfAttributes(Fqn fqn)
- {
- return numAttributes(findNode(fqn));
- }
-
- private int numAttributes(NodeSPI<K, V> n)
- {
- int count = 0;
- for (NodeSPI<K, V> child : n.getChildrenDirect())
- {
- count += numAttributes(child);
- }
- count += n.getDataDirect().size();
- return count;
- }
-
- /* ---------------------- Remote method calls -------------------- */
-
- /**
- * @param mbrs
- * @param method_call
- * @param synchronous
- * @param exclude_self
- * @param timeout
- * @return
- * @throws Exception
- * @deprecated Note this is due to be moved to an interceptor.
- */
- @Deprecated
- public List callRemoteMethods(List<Address> mbrs, MethodCall method_call,
- boolean synchronous, boolean exclude_self, long timeout)
- throws Exception
- {
- return callRemoteMethods(mbrs, method_call, synchronous ? GroupRequest.GET_ALL : GroupRequest.GET_NONE, exclude_self, timeout);
- }
-
-
- /**
- * Overloaded to allow a finer grained control over JGroups mode
- *
- * @param mbrs
- * @param method_call
- * @param mode
- * @param exclude_self
- * @param timeout
- * @return
- * @throws Exception
- * @deprecated Note this is due to be moved to an interceptor.
- */
- @Deprecated
- public List callRemoteMethods(List<Address> mbrs, MethodCall method_call, int mode, boolean exclude_self, long timeout)
- throws Exception
- {
- RspList rsps = null;
- Rsp rsp;
- List retval;
- Vector<Address> validMembers;
-
- if (disp == null)
- {
- return null;
- }
-
- validMembers = null;
- if (mbrs != null)
- validMembers = new Vector<Address>(mbrs);
- else
- {
- synchronized (members)
- {
- validMembers = new Vector<Address>(this.members);
- }
- }
-
- if (exclude_self && !validMembers.isEmpty())
- {
- Object local_addr = getLocalAddress();
- if (local_addr != null)
- {
- validMembers.remove(local_addr);
- }
- }
- if (validMembers.isEmpty())
- {
- if (log.isTraceEnabled())
- {
- log.trace("destination list is empty, discarding call");
- }
- return null;
- }
-
- if (log.isTraceEnabled())
- {
- log.trace("callRemoteMethods(): valid members are " + validMembers + " methods: " + method_call.getArgs()[0]);
- }
-
- if (channel.flushSupported())
- {
- flushBlockGate.await(configuration.getStateRetrievalTimeout());
- rsps = disp.callRemoteMethods(validMembers, method_call, mode, timeout, buddyManager != null && buddyManager.isEnabled());
- }
- else
- {
- rsps = disp.callRemoteMethods(validMembers, method_call, mode, timeout, buddyManager != null && buddyManager.isEnabled());
- }
-
- // a null response is 99% likely to be due to a marshalling problem - we throw a NSE, this needs to be changed when
- // JGroups supports http://jira.jboss.com/jira/browse/JGRP-193
- if (rsps == null)
- {
- // return null;
- throw new NotSerializableException("RpcDispatcher returned a null. This is most often caused by args for " + method_call + " not being serializable.");
- }
- if (mode == GroupRequest.GET_NONE)
- {
- return Collections.EMPTY_LIST;// async case
- }
-
- if (log.isTraceEnabled())
- {
- log.trace("(" + getLocalAddress() + "): responses for method " + method_call.getName() + ":\n" + rsps);
- }
-
- retval = new ArrayList(rsps.size());
- for (int i = 0; i < rsps.size(); i++)
- {
- rsp = (Rsp) rsps.elementAt(i);
- if (rsp.wasSuspected() || !rsp.wasReceived())
- {
- CacheException ex;
- if (rsp.wasSuspected())
- {
- ex = new SuspectException("Suspected member: " + rsp.getSender());
- }
- else
- {
- ex = new TimeoutException("Replication timeout for " + rsp.getSender());
- }
- retval.add(new ReplicationException("rsp=" + rsp, ex));
- }
- else
- {
- retval.add(rsp.getValue());
- }
- }
- return retval;
- }
-
- /**
- * @param members
- * @param method
- * @param args
- * @param synchronous
- * @param exclude_self
- * @param timeout
- * @return
- * @throws Exception
- * @deprecated Note this is due to be moved to an interceptor.
- */
- @Deprecated
- public List callRemoteMethods(List<Address> members, Method method, Object[] args,
- boolean synchronous, boolean exclude_self, long timeout)
- throws Exception
- {
- return callRemoteMethods(members, MethodCallFactory.create(method, args), synchronous, exclude_self, timeout);
- }
-
- /**
- * @param members
- * @param method_name
- * @param types
- * @param args
- * @param synchronous
- * @param exclude_self
- * @param timeout
- * @return
- * @throws Exception
- * @deprecated Note this is due to be moved to an interceptor.
- */
- @Deprecated
- public List callRemoteMethods(Vector<Address> members, String method_name,
- Class[] types, Object[] args,
- boolean synchronous, boolean exclude_self, long timeout)
- throws Exception
- {
- Method method = getClass().getDeclaredMethod(method_name, types);
- return callRemoteMethods(members, method, args, synchronous, exclude_self, timeout);
- }
-
- /* -------------------- End Remote method calls ------------------ */
-
- /* --------------------- Callbacks -------------------------- */
-
- /* ----- These are VERSIONED callbacks to facilitate JBCACHE-843. Also see docs/design/DataVersion.txt --- */
-
- public void _putForExternalRead(GlobalTransaction gtx, Fqn fqn, K key, V value, DataVersion dv) throws CacheException
- {
- _putForExternalRead(gtx, fqn, key, value);
- }
-
- public void _put(GlobalTransaction tx, Fqn fqn, Map<K, V> data, boolean create_undo_ops, DataVersion dv) throws CacheException
- {
- _put(tx, fqn, data, create_undo_ops, false, dv);
- }
-
- public void _put(GlobalTransaction tx, Fqn fqn, Map<K, V> data, boolean create_undo_ops, boolean erase_contents, DataVersion dv) throws CacheException
- {
- _put(tx, fqn, data, create_undo_ops, erase_contents);
- }
-
- public Object _put(GlobalTransaction tx, Fqn fqn, K key, V value, boolean create_undo_ops, DataVersion dv) throws CacheException
- {
- return _put(tx, fqn, key, value, create_undo_ops);
- }
-
- public boolean _remove(GlobalTransaction tx, Fqn fqn, boolean create_undo_ops, DataVersion dv) throws CacheException
- {
- return _remove(tx, fqn, create_undo_ops, true);
- }
-
- public Object _remove(GlobalTransaction tx, Fqn fqn, K key, boolean create_undo_ops, DataVersion dv) throws CacheException
- {
- return _remove(tx, fqn, key, create_undo_ops);
- }
-
- public void _removeData(GlobalTransaction tx, Fqn fqn, boolean create_undo_ops, DataVersion dv) throws CacheException
- {
-
- _removeData(tx, fqn, create_undo_ops, true);
- }
-
- /* ----- End VERSIONED callbacks - Now for the NORMAL callbacks. -------- */
-
- /**
- * Internal put method.
- * Does the real work. Needs to acquire locks if accessing nodes, depending on
- * the value of <tt>locking</tt>. If run inside a transaction, needs to (a) add
- * newly acquired locks to {@link TransactionEntry}'s lock list, (b) add nodes
- * that were created to {@link TransactionEntry}'s node list and (c) create
- * {@link Modification}s and add them to {@link TransactionEntry}'s modification
- * list and (d) create compensating modifications to undo the changes in case
- * of a rollback
- *
- * @param fqn
- * @param data
- * @param create_undo_ops If true, undo operations will be created (default is true).
- * Otherwise they will not be created (used by rollback()).
- */
- public void _put(GlobalTransaction tx, String fqn, Map<K, V> data, boolean create_undo_ops)
- throws CacheException
- {
- _put(tx, Fqn.fromString(fqn), data, create_undo_ops);
- }
-
-
- /**
- * Internal put method.
- * Does the real work. Needs to acquire locks if accessing nodes, depending on
- * the value of <tt>locking</tt>. If run inside a transaction, needs to (a) add
- * newly acquired locks to {@link TransactionEntry}'s lock list, (b) add nodes
- * that were created to {@link TransactionEntry}'s node list and (c) create
- * {@link Modification}s and add them to {@link TransactionEntry}'s modification
- * list and (d) create compensating modifications to undo the changes in case
- * of a rollback
- *
- * @param fqn
- * @param data
- * @param create_undo_ops If true, undo operations will be created (default is true).
- * Otherwise they will not be created (used by rollback()).
- */
- public void _put(GlobalTransaction tx, Fqn fqn, Map<K, V> data, boolean create_undo_ops)
- throws CacheException
- {
- _put(tx, fqn, data, create_undo_ops, false);
- }
-
- /**
- * Internal put method.
- * Does the real work. Needs to acquire locks if accessing nodes, depending on
- * the value of <tt>locking</tt>. If run inside a transaction, needs to (a) add
- * newly acquired locks to {@link TransactionEntry}'s lock list, (b) add nodes
- * that were created to {@link TransactionEntry}'s node list and (c) create
- * {@link Modification}s and add them to {@link TransactionEntry}'s modification
- * list and (d) create compensating modifications to undo the changes in case
- * of a rollback
- *
- * @param fqn
- * @param data
- * @param create_undo_ops If true, undo operations will be created (default is true).
- * @param erase_contents Clear the existing hashmap before putting the new data into it
- * Otherwise they will not be created (used by rollback()).
- */
- public void _put(GlobalTransaction tx, Fqn fqn, Map<K, V> data, boolean create_undo_ops, boolean erase_contents)
- throws CacheException
- {
- if (log.isTraceEnabled())
- {
- log.trace("_put(" + tx + ", \"" + fqn + "\", " + data + " undo=" + create_undo_ops + " erase=" + erase_contents + ")");
- }
- InvocationContext ctx = getInvocationContext();
- boolean isRollback = checkIsRollingBack(ctx.getTransaction());
- NodeSPI<K, V> n = findNodeCheck(tx, fqn);
- Map<K, V> rawData = n.getDataDirect();
- if (!isRollback) notifier.notifyNodeModified(fqn, true, NodeModifiedEvent.ModificationType.PUT_MAP, rawData, ctx);
-
- // create a compensating method call (reverting the effect of
- // this modification) and put it into the TX's undo list.
- if (tx != null && create_undo_ops)
- {
- // erase and set to previous hashmap contents
- MethodCall undo_op = MethodCallFactory.create(MethodDeclarations.putDataEraseMethodLocal, tx, fqn, new HashMap(rawData), false, true);
- tx_table.addUndoOperation(tx, undo_op);
- }
-
- if (erase_contents)
- n.clearDataDirect();
- n.putAllDirect(data);
-
- if (!isRollback)
- notifier.notifyNodeModified(fqn, false, NodeModifiedEvent.ModificationType.PUT_MAP, n.getDataDirect(), ctx);
- }
-
- /**
- * Internal put method.
- *
- * @return Previous value (if any)
- */
- public Object _put(GlobalTransaction tx, String fqn, K key, V value, boolean create_undo_ops)
- throws CacheException
- {
- return _put(tx, Fqn.fromString(fqn), key, value, create_undo_ops);
- }
-
- private boolean checkIsRollingBack(Transaction tx)
- {
- try
- {
- return tx != null && (
- tx.getStatus() == javax.transaction.Status.STATUS_ROLLEDBACK ||
- tx.getStatus() == javax.transaction.Status.STATUS_ROLLING_BACK ||
- tx.getStatus() == javax.transaction.Status.STATUS_MARKED_ROLLBACK);
- }
- catch (Exception e)
- {
- // can't get a hold of a transaction - probably no tx rolling back
- return false;
- }
- }
-
- /**
- * Internal put method.
- *
- * @return Previous value (if any)
- */
- public Object _put(GlobalTransaction tx, Fqn fqn, K key, V value, boolean create_undo_ops)
- throws CacheException
- {
- if (log.isTraceEnabled())
- {
- log.trace(new StringBuffer("_put(").append(tx).append(", \"").
- append(fqn).append("\", k=").append(key).append(", v=").append(value).append(")"));
- }
-
-
- InvocationContext ctx = getInvocationContext();
- // if this is a rollback then don't fire notifications.
- boolean isRollback = checkIsRollingBack(ctx.getTransaction());
-
- NodeSPI<K, V> n = findNodeCheck(tx, fqn);
- Map<K, V> rawData = n.getDataDirect();
- if (!isRollback)
- notifier.notifyNodeModified(fqn, true, NodeModifiedEvent.ModificationType.PUT_DATA, rawData, ctx);
-
- V old_value = n.putDirect(key, value);
-
- // create a compensating method call (reverting the effect of
- // this modification) and put it into the TX's undo list.
- if (tx != null && create_undo_ops)
- {
- MethodCall undo_op;
- if (old_value == null)
- {
- undo_op = MethodCallFactory.create(MethodDeclarations.removeKeyMethodLocal, tx, fqn, key, false);
- }
- else
- {
- undo_op = MethodCallFactory.create(MethodDeclarations.putKeyValMethodLocal, tx, fqn, key, old_value, false);
- }
- // 1. put undo-op in TX' undo-operations list (needed to rollback TX)
- tx_table.addUndoOperation(tx, undo_op);
- }
-
- Map<K, V> newData = Collections.singletonMap(key, value);
- if (!isRollback)
- notifier.notifyNodeModified(fqn, false, NodeModifiedEvent.ModificationType.PUT_DATA, newData, ctx);
- return old_value;
- }
-
- /**
- * Internal remove method.
- */
- public void _remove(GlobalTransaction tx, String fqn, boolean create_undo_ops) throws CacheException
- {
- _remove(tx, Fqn.fromString(fqn), create_undo_ops);
- }
-
- /**
- * Internal remove method.
- */
- public boolean _remove(GlobalTransaction tx, Fqn fqn, boolean create_undo_ops) throws CacheException
- {
- return _remove(tx, fqn, create_undo_ops, true);
- }
-
- public boolean _remove(GlobalTransaction tx, Fqn fqn, boolean create_undo_ops, boolean sendNodeEvent)
- throws CacheException
- {
- return _remove(tx, fqn, create_undo_ops, sendNodeEvent, false);
- }
-
- /**
- * Internal method to remove a node.
- *
- * @param tx
- * @param fqn
- * @param create_undo_ops
- * @param sendNodeEvent
- */
- public boolean _remove(GlobalTransaction tx, Fqn fqn, boolean create_undo_ops, boolean sendNodeEvent, boolean eviction)
- throws CacheException
- {
- return _remove(tx, fqn, create_undo_ops, sendNodeEvent, eviction, null);
- }
-
- /**
- * Internal method to remove a node.
- * Performs a remove on a node, passing in a {@link DataVersion} which is used with optimistically locked nodes. Pass
- * in a null if optimistic locking is not used.
- *
- * @param tx
- * @param fqn
- * @param create_undo_ops
- * @param sendNodeEvent
- * @param eviction
- * @param version
- * @return true if the node was removed, false if not found
- * @throws CacheException
- */
- public boolean _remove(GlobalTransaction tx, Fqn fqn, boolean create_undo_ops, boolean sendNodeEvent, boolean eviction, DataVersion version)
- throws CacheException
- {
-
- NodeSPI<K, V> n;
- NodeSPI<K, V> parent_node;
- MethodCall undo_op = null;
-
- if (log.isTraceEnabled())
- {
- log.trace("_remove(" + tx + ", \"" + fqn + "\", undo=" + create_undo_ops + ")");
- }
- InvocationContext ctx = getInvocationContext();
- // check if this is triggered by a rollback operation ...
- boolean isRollback = checkIsRollingBack(ctx.getTransaction());
- if (tx != null)
- {
- try
- {
- if (isRollback)
- {
- log.trace("This remove call is triggered by a transaction rollback, as a compensation operation. Do a realRemove() instead.");
- return realRemove(fqn, true);
- }
- }
- catch (Exception e)
- {
- // what do we do here?
- log.warn("Unable to get a hold of the transaction for a supposedly transactional call! This *may* result in stale locks!", e);
- }
- }
-
- // Find the node. This will add the temporarily created parent nodes to the TX's node list if tx != null)
- n = findNode(fqn, version);
- if (n == null)
- {
- if (log.isTraceEnabled())
- {
- log.trace("node " + fqn + " not found");
- }
- return false;
- }
-
- if (!isRollback)
- {
- if (eviction)
- {
- notifier.notifyNodeEvicted(fqn, true, ctx);
- }
- else
- {
- notifier.notifyNodeRemoved(fqn, true, n.getDataDirect(), ctx);
- }
- }
-
- parent_node = n.getParent();
- boolean found;
-
- // remove subtree from parent
- if (eviction || configuration.isNodeLockingOptimistic())
- {
- // if there is no parent node and the fqn is root, found == true otherwise found == false.
- found = parent_node == null ? fqn.isRoot() : parent_node.removeChildDirect(n.getFqn().getLastElement());
- }
- else
- {
- found = !n.isDeleted();
- n.markAsDeleted(true);
- }
-
- if (eviction && parent_node != null)
- {
- parent_node.setChildrenLoaded(false);
- }
-
- // release all locks for the entire subtree
- // n.getNodeSPI().getLock().releaseAll(tx != null ? tx : (Object) Thread.currentThread());
-
- // create a compensating method call (reverting the effect of
- // this modification) and put it into the TX's undo list.
- if (tx != null && create_undo_ops && !eviction)
- {
- undo_op = MethodCallFactory.create(MethodDeclarations.addChildMethodLocal, tx, parent_node.getFqn(), n.getFqn().getLastElement(), n, false);
-
- // 1. put undo-op in TX' undo-operations list (needed to rollback TX)
- tx_table.addUndoOperation(tx, undo_op);
- }
-
- if (!isRollback)
- {
- if (eviction)
- {
- notifier.notifyNodeEvicted(fqn, false, ctx);
- }
- else
- {
- notifier.notifyNodeRemoved(fqn, false, null, ctx);
- }
- }
-
- return found;
- }
-
- /**
- * Internal method to remove a key.
- *
- * @param fqn
- * @param key
- * @return Object
- */
- public V _remove(GlobalTransaction tx, String fqn, K key, boolean create_undo_ops)
- throws CacheException
- {
- return _remove(tx, Fqn.fromString(fqn), key, create_undo_ops);
- }
-
- /**
- * Internal method to remove a key.
- *
- * @param fqn
- * @param key
- * @return Object
- */
- public V _remove(GlobalTransaction tx, Fqn fqn, K key, boolean create_undo_ops)
- throws CacheException
- {
- MethodCall undo_op = null;
- V old_value = null;
-
- if (log.isTraceEnabled())
- {
- log.trace("_remove(" + tx + ", \"" + fqn + "\", key=" + key + ")");
- }
-
- // Find the node. This will lock it (if <tt>locking</tt> is true) and
- // add the temporarily created parent nodes to the TX's node list if tx != null)
- NodeSPI<K, V> n = findNode(fqn);
- if (n == null)
- {
- log.warn("node " + fqn + " not found");
- return null;
- }
- InvocationContext ctx = getInvocationContext();
- boolean isRollback = checkIsRollingBack(ctx.getTransaction());
- if (!isRollback)
- notifier.notifyNodeModified(fqn, true, NodeModifiedEvent.ModificationType.REMOVE_DATA, n.getDataDirect(), ctx);
-
- old_value = n.removeDirect(key);
-
- // create a compensating method call (reverting the effect of
- // this modification) and put it into the TX's undo list.
- if (tx != null && create_undo_ops && old_value != null)
- {
- undo_op = MethodCallFactory.create(MethodDeclarations.putKeyValMethodLocal, tx, fqn, key, old_value, false);
- // 1. put undo-op in TX' undo-operations list (needed to rollback TX)
- tx_table.addUndoOperation(tx, undo_op);
- }
-
- Map<K, V> removedData = Collections.singletonMap(key, old_value);
- if (!isRollback)
- notifier.notifyNodeModified(fqn, false, NodeModifiedEvent.ModificationType.REMOVE_DATA, removedData, ctx);
-
- return old_value;
- }
-
- /**
- * Internal method to remove data from a node.
- */
- public void _removeData(GlobalTransaction tx, String fqn, boolean create_undo_ops)
- throws CacheException
- {
- _removeData(tx, Fqn.fromString(fqn), create_undo_ops);
- }
-
- /**
- * Internal method to remove data from a node.
- */
- public void _removeData(GlobalTransaction tx, Fqn fqn, boolean create_undo_ops)
- throws CacheException
- {
- _removeData(tx, fqn, create_undo_ops, true);
- }
-
- /**
- * Internal method to remove data from a node.
- */
- public void _removeData(GlobalTransaction tx, Fqn fqn, boolean create_undo_ops, boolean sendNodeEvent)
- throws CacheException
- {
- _removeData(tx, fqn, create_undo_ops, sendNodeEvent, false);
- }
-
- /**
- * Internal method to remove data from a node.
- */
- public void _removeData(GlobalTransaction tx, Fqn fqn, boolean create_undo_ops, boolean sendNodeEvent, boolean eviction)
- throws CacheException
- {
- _removeData(tx, fqn, create_undo_ops, sendNodeEvent, eviction, null);
- }
-
- /**
- * Internal method to remove data from a node.
- */
- public void _removeData(GlobalTransaction tx, Fqn fqn, boolean create_undo_ops, boolean sendNodeEvent, boolean eviction, DataVersion version)
- throws CacheException
- {
- MethodCall undo_op = null;
-
- if (log.isTraceEnabled())
- {
- log.trace("_removeData(" + tx + ", \"" + fqn + "\")");
- }
-
- // Find the node. This will lock it (if <tt>locking</tt> is true) and
- // add the temporarily created parent nodes to the TX's node list if tx != null)
- NodeSPI n = findNode(fqn, version);
- if (n == null)
- {
- log.warn("node " + fqn + " not found");
- return;
- }
-
- Map<K, V> data = n.getDataDirect();
- InvocationContext ctx = getInvocationContext();
- boolean isRollback = checkIsRollingBack(ctx.getTransaction());
- // create a compensating method call (reverting the effect of
- // this modification) and put it into the TX's undo list.
- if (tx != null && create_undo_ops && !eviction)
- {
- if (!data.isEmpty())
- {
- undo_op = MethodCallFactory.create(MethodDeclarations.putDataMethodLocal,
- tx, fqn, new HashMap<K,V>(data), false);
- }
- }
-
- if (!isRollback)
- {
- if (eviction)
- {
- notifier.notifyNodeEvicted(fqn, true, ctx);
- }
- else
- {
- notifier.notifyNodeModified(fqn, true, NodeModifiedEvent.ModificationType.REMOVE_DATA, data, ctx);
- }
- }
-
- n.clearDataDirect();
- if (eviction)
- {
- n.setDataLoaded(false);
- }
-
- if (!isRollback)
- {
- if (sendNodeEvent)
- {
- notifier.notifyNodeVisited(fqn, false, ctx);
- }
- else
- {// FIXME Bela did this so GUI view can refresh the view after node is evicted. But this breaks eviction policy, especially AOP!!!!
- if (eviction)
- {
- notifier.notifyNodeEvicted(fqn, false, ctx);
- }
- else
- {
- notifier.notifyNodeModified(fqn, false, NodeModifiedEvent.ModificationType.REMOVE_DATA, data, ctx);
- }
- }
- }
-
- // put undo-op in TX' undo-operations list (needed to rollback TX)
- if (tx != null && create_undo_ops)
- {
- tx_table.addUndoOperation(tx, undo_op);
- }
- }
-
-
- /**
- * Internal evict method called by eviction policy provider.
- *
- * @param fqn removes everything assoicated with this FQN
- * @return <code>true</code> if the node has been completely removed,
- * <code>false</code> if only the data map was removed, due
- * to the presence of children
- * @throws CacheException
- */
- public boolean _evict(Fqn fqn) throws CacheException
- {
- if (!exists(fqn))
- return true;// node does not exist. Maybe it has been recursively removed.
- // use remove method now if there is a child node. Otherwise, it is removed
- boolean create_undo_ops = false;
- boolean sendNodeEvent = false;
- boolean eviction = true;
- if (log.isTraceEnabled())
- {
- log.trace("_evict(" + fqn + ")");
- }
- if (hasChild(fqn))
- {
- _removeData(null, fqn, create_undo_ops, sendNodeEvent, eviction);
- return false;
- }
- else
- {
- _remove(null, fqn, create_undo_ops, sendNodeEvent, eviction);
- return true;
- }
- }
-
- /**
- * Internal evict method called by eviction policy provider.
- *
- * @param fqn
- * @param version
- * @return <code>true</code> if the node has been completely removed,
- * <code>false</code> if only the data map was removed, due
- * to the presence of children
- * @throws CacheException
- */
- public boolean _evict(Fqn fqn, DataVersion version) throws CacheException
- {
- if (!exists(fqn))
- return true;// node does not exist
-
- boolean create_undo_ops = false;
- boolean sendNodeEvent = false;
- boolean eviction = true;
- if (log.isTraceEnabled())
- {
- log.trace("_evict(" + fqn + ", " + version + ")");
- }
- if (hasChild(fqn))
- {
- _removeData(null, fqn, create_undo_ops, sendNodeEvent, eviction, version);
- return false;
- }
- else
- {
- _remove(null, fqn, create_undo_ops, sendNodeEvent, eviction, version);
- return true;
- }
- }
-
- /**
- * Evicts a key/value pair from a node's attributes. Note that this is <em>local</em>, will not be replicated.
- * @param fqn
- * @param key
- * @throws CacheException
- */
- // public void _evict(Fqn fqn, Object key) throws CacheException {
- // if(!exists(fqn)) return;
- // boolean create_undo_ops = false;
- // boolean sendNodeEvent = false;
- // boolean eviction=true;
- // _removeData(null, fqn, create_undo_ops, sendNodeEvent, eviction);
- // }
-
-
- /**
- * Compensating method to {@link #_remove(GlobalTransaction,Fqn,boolean)}.
- */
- public void _addChild(GlobalTransaction gtx, Fqn parent_fqn, Object child_name, Node cn, boolean undoOps)
- throws CacheException
- {
- NodeSPI childNode = (NodeSPI) cn;
- if (log.isTraceEnabled())
- {
- log.trace("_addChild(\"" + parent_fqn + "\", \"" + child_name + "\", node=" + childNode + ")");
- }
-
- if (parent_fqn == null || child_name == null || childNode == null)
- {
- log.error("parent_fqn or child_name or childNode was null");
- return;
- }
- NodeSPI parentNode = findNode(parent_fqn);
- if (parentNode == null)
- {
- log.warn("node " + parent_fqn + " not found");
- return;
- }
- InvocationContext ctx = getInvocationContext();
- boolean isRollback = checkIsRollingBack(ctx.getTransaction());
- Fqn fqn = new Fqn(parent_fqn, child_name);
- if (!isRollback) notifier.notifyNodeCreated(fqn, true, ctx);
- parentNode.addChild(child_name, childNode);
-
- childNode.markAsDeleted(false, true);
-
- if (gtx != null && undoOps)
- {
- // 1. put undo-op in TX' undo-operations list (needed to rollback TX)
- tx_table.addUndoOperation(gtx, MethodCallFactory.create(MethodDeclarations.removeNodeMethodLocal, gtx, fqn, false));
- }
-
- if (!isRollback) notifier.notifyNodeCreated(fqn, false, ctx);
- }
-
-
- /**
- * Replicates changes across to other nodes in the cluster. Invoked by the
- * ReplicationInterceptor. Calls need to be forwarded to the
- * ReplicationInterceptor in this interceptor chain. This method will later
- * be moved entirely into the ReplicationInterceptor.
- */
- public Object _replicate(MethodCall method_call) throws Throwable
- {
- try
- {
- Object retVal = invokeMethod(method_call, false);
- // we only need to return values for a set of remote calls; not every call.
- if (MethodDeclarations.returnValueForRemoteCall(method_call.getMethodId()))
- {
- return retVal;
- }
- else
- {
- return null;
- }
- }
- catch (Throwable ex)
- {
- log.warn("replication failure with method_call " + method_call + " exception", ex);
- throw ex;
- }
- }
-
- /**
- * Replicates a list of method calls.
- */
- public void _replicate(List<MethodCall> methodCalls) throws Throwable
- {
- for (MethodCall methodCall : methodCalls) _replicate(methodCall);
- }
-
- /**
- * A 'clustered get' call, called from a remote ClusteredCacheLoader.
- *
- * @return a List containing 2 elements: (true or false) and a value (Object). If buddy replication
- * is used one further element is added - an Fqn of the backup subtree in which this node may be found.
- */
- public List _clusteredGet(MethodCall methodCall, Boolean searchBackupSubtrees)
- {
- MethodCall call = methodCall;
- if (log.isTraceEnabled()) log.trace("Clustered Get called with params: " + call + ", " + searchBackupSubtrees);
- Method m = call.getMethod();
- Object[] args = call.getArgs();
-
- Object callResults = null;
-
- try
- {
- Fqn fqn = (Fqn) args[0];
-
- if (log.isTraceEnabled()) log.trace("Clustered get: invoking call " + m + " with Fqn " + fqn);
- callResults = m.invoke(this, args);
- boolean found = validResult(callResults, call, fqn);
- if (log.isTraceEnabled()) log.trace("Got result " + callResults + ", found=" + found);
- if (found && callResults == null) callResults = createEmptyResults(call);
- }
- catch (Exception e)
- {
- log.warn("Problems processing clusteredGet call", e);
- }
-
- List<Object> results = new ArrayList<Object>(2);
- if (callResults != null)
- {
- results.add(true);
- results.add(callResults);
- }
- else
- {
- results.add(false);
- results.add(null);
- }
- return results;
- }
-
- /**
- * Used with buddy replication's data gravitation interceptor. If marshalling is necessary, ensure that the cache is
- * configured to use {@link org.jboss.cache.config.Configuration#useRegionBasedMarshalling} and the {@link org.jboss.cache.Region}
- * pertaining to the Fqn passed in is activated, and has an appropriate ClassLoader.
- *
- * @param fqn the fqn to gravitate
- * @param searchSubtrees if true, buddy backup subtrees are searched and if false, they are not.
- * @return a GravitateResult which contains the data for the gravitation
- */
- public GravitateResult gravitateData(Fqn fqn, boolean searchSubtrees)
- throws CacheException
- {
- // we need to get the state for this Fqn and its sub-nodes.
-
- // for now, perform a very simple series of getData calls.
- InvocationContext ctx = getInvocationContext();
-
- log.debug("*****************>>>>> " + printLockInfo());
-
- try
- {
- ctx.setOriginLocal(false);
-
- NodeSPI<K, V> actualNode = findNode(fqn);
- Fqn backupNodeFqn = null;
- if (actualNode == null && searchSubtrees)
- {
- NodeSPI backupSubtree = findNode(BuddyManager.BUDDY_BACKUP_SUBTREE_FQN);
- if (backupSubtree != null)
- {
- // need to loop through backupSubtree's children
- Set childNames = backupSubtree.getChildrenNamesDirect();
- if (childNames != null)
- {
- for (Object childName : childNames)
- {
- // childName is the name of a buddy group since all child names in this
- // collection are direct children of BUDDY_BACKUP_SUBTREE_FQN
- backupNodeFqn = BuddyManager.getBackupFqn(childName.toString(), fqn);
- actualNode = findNode(backupNodeFqn);
- if (actualNode != null) break;
- }
- }
- /*Map children = backupSubtree.getChildrenMapDirect();
- if (children != null)
- {
- Iterator childNames = children.keySet().iterator();
- while (childNames.hasNext() && actualNode == null)
- {
- backupNodeFqn = BuddyManager.getBackupFqn(childNames.next().toString(), fqn);
- actualNode = findNode(backupNodeFqn);
- }
- }*/
- }
- }
-
- if (actualNode == null)
- {
- return GravitateResult.noDataFound();
- }
-
- if (backupNodeFqn == null && searchSubtrees)
- {
- backupNodeFqn = BuddyManager.getBackupFqn(BuddyManager.getGroupNameFromAddress(getLocalAddress()), fqn);
- }
-
- List<NodeData> list = getNodeData(new LinkedList<NodeData>(), actualNode);
-
- return GravitateResult.subtreeResult(list, backupNodeFqn);
- }
- finally
- {
- ctx.setOriginLocal(true);
- }
- }
-
- private List<NodeData> getNodeData(List<NodeData> list, NodeSPI<K, V> node)
- {
- NodeData data = new NodeData(BuddyManager.getActualFqn(node.getFqn()), node.getDataDirect());
- list.add(data);
- for (NodeSPI<K, V> childNode : node.getChildrenDirect())
- {
- getNodeData(list, childNode);
- }
- return list;
- }
-
- // ------------- start: buddy replication specific 'lifecycle' method calls
-
- public void _remoteAssignToBuddyGroup(BuddyGroup group, Map<Fqn, byte[]> state) throws Exception
- {
- if (buddyManager != null)
- buddyManager.handleAssignToBuddyGroup(group, state);
- else if (log.isWarnEnabled())
- log.warn("Received assignToBuddyGroup call from group owner [" + group.getDataOwner() + "] but buddy replication is not enabled on this node!");
- }
-
- public void _remoteRemoveFromBuddyGroup(String groupName) throws BuddyNotInitException
- {
- if (buddyManager != null)
- buddyManager.handleRemoveFromBuddyGroup(groupName);
- else if (log.isWarnEnabled())
- log.warn("Received removeFromBuddyGroup call for group name [" + groupName + "] but buddy replication is not enabled on this node!");
-
- }
-
- public void _remoteAnnounceBuddyPoolName(Address address, String buddyPoolName)
- {
- if (buddyManager != null)
- buddyManager.handlePoolNameBroadcast(address, buddyPoolName);
- else if (log.isWarnEnabled())
- log.warn("Received annouceBuddyPoolName call from [" + address + "] but buddy replication is not enabled on this node!");
- }
-
- public void _dataGravitationCleanup(GlobalTransaction gtx, Fqn primary, Fqn backup) throws Exception
- {
- MethodCall primaryDataCleanup, backupDataCleanup;
- if (buddyManager.isDataGravitationRemoveOnFind())
- {
- if (log.isTraceEnabled())
- log.trace("DataGravitationCleanup: Removing primary (" + primary + ") and backup (" + backup + ")");
- primaryDataCleanup = MethodCallFactory.create(MethodDeclarations.removeNodeMethodLocal, null, primary, false);
- backupDataCleanup = MethodCallFactory.create(MethodDeclarations.removeNodeMethodLocal, null, backup, false);
- }
- else
- {
- if (log.isTraceEnabled())
- log.trace("DataGravitationCleanup: Evicting primary (" + primary + ") and backup (" + backup + ")");
- primaryDataCleanup = MethodCallFactory.create(MethodDeclarations.evictNodeMethodLocal, primary);
- backupDataCleanup = MethodCallFactory.create(MethodDeclarations.evictNodeMethodLocal, backup);
- }
-
- invokeMethod(primaryDataCleanup, true);
- invokeMethod(backupDataCleanup, true);
- }
-
- // ------------- end: buddy replication specific 'lifecycle' method calls
-
-
- /**
- * Returns true if the call results returned a valid result.
- */
- private boolean validResult(Object callResults, MethodCall mc, Fqn fqn)
- {
- switch (mc.getMethodId())
- {
- case MethodDeclarations.getDataMapMethodLocal_id:
- case MethodDeclarations.getChildrenNamesMethodLocal_id:
- return callResults != null || exists(fqn);
- case MethodDeclarations.existsMethod_id:
- return (Boolean) callResults;
- default:
- return false;
- }
- }
-
- /**
- * Creates an empty Collection class based on the return type of the method called.
- */
- private Object createEmptyResults(MethodCall mc)
- {
- switch (mc.getMethodId())
- {
- case MethodDeclarations.getDataMapMethodLocal_id:
- case MethodDeclarations.getChildrenNamesMethodLocal_id:
- return Collections.emptyMap();
- default:
- return null;
- }
- }
-
- /**
- * Releases all locks for a FQN.
- */
- public void _releaseAllLocks(Fqn fqn)
- {
- NodeSPI<K, V> n;
-
- try
- {
- n = findNode(fqn);
- if (n == null)
- {
- log.error("releaseAllLocks(): node " + fqn + " not found");
- return;
- }
- releaseAll(n);
- }
- catch (Throwable t)
- {
- log.error("releaseAllLocks(): failed", t);
- }
- }
-
- private void releaseAll(NodeSPI<K, V> n)
- {
- for (NodeSPI<K, V> child : n.getChildrenDirect())
- {
- releaseAll(child);
- }
- n.getLock().releaseAll();
- }
-
-
- /**
- * Finds and returns the string value for the Fqn.
- * Returns null if not found or upon error.
- */
- public String _print(Fqn fqn)
- {
- try
- {
- Node n = findNode(fqn);
- if (n == null) return null;
- return n.toString();
- }
- catch (Throwable t)
- {
- return null;
- }
- }
-
- /**
- * Should not be called.
- */
- public void _lock(Fqn fqn, NodeLock.LockType lock_type, boolean recursive)
- throws TimeoutException, LockingException
- {
- throw new UnsupportedOperationException("method _lock() should not be invoked on CacheImpl");
- }
-
- /**
- * Throws UnsupportedOperationException.
- */
- public void optimisticPrepare(GlobalTransaction gtx, List modifications, Map data, Address address, boolean onePhaseCommit)
- {
- throw new UnsupportedOperationException("optimisticPrepare() should not be called on CacheImpl directly");
- }
-
- /**
- * Throws UnsupportedOperationException.
- */
- public void prepare(GlobalTransaction global_tx, List modifications, Address coord, boolean onePhaseCommit)
- {
- throw new UnsupportedOperationException("prepare() should not be called on CacheImpl directly");
- }
-
- /**
- * Throws UnsupportedOperationException.
- */
- public void commit(GlobalTransaction tx)
- {
- throw new UnsupportedOperationException("commit() should not be called on CacheImpl directly");
- }
-
- /**
- * Throws UnsupportedOperationException.
- */
- public void rollback(GlobalTransaction tx)//, Boolean hasMods)
- {
- throw new UnsupportedOperationException("rollback() should not be called on CacheImpl directly");
- }
-
- /* ----------------- End of Callbacks ---------------------- */
-
- /**
- * Adds an undo operatoin to the transaction table.
- */
- public void addUndoOperation(GlobalTransaction gtx, MethodCall undo_op)
- {
- tx_table.addUndoOperation(gtx, undo_op);
- }
-
- /**
- * Returns the CacheLoaderManager.
- */
- public CacheLoaderManager getCacheLoaderManager()
- {
- return cacheLoaderManager;
- }
-
- /**
- * Sets the CacheLoaderManager.
- */
- public void setCacheLoaderManager(CacheLoaderManager cacheLoaderManager)
- {
- this.cacheLoaderManager = cacheLoaderManager;
- }
-
- public void setConfiguration(Configuration configuration)
- {
- this.configuration = configuration;
- configuration.setCacheImpl(this);
- }
-
- /**
- * @return an instance of {@link Notifier} which has been configured with this instance of CacheImpl.
- */
- public Notifier getNotifier()
- {
- return notifier;
- }
-
- public InvocationContext getInvocationContext()
- {
- InvocationContext ctx = invocationContextContainer.get();
- if (ctx == null)
- {
- ctx = new InvocationContext();
- invocationContextContainer.set(ctx);
- }
- return ctx;
- }
-
- public void setInvocationContext(InvocationContext ctx)
- {
- invocationContextContainer.set(ctx);
- }
-
- /**
- * New API to efficiently relocate a node
- *
- * @since 2.0.0
- */
- public void move(Fqn<?> nodeToMove, Fqn<?> newParent)
- {
- // this needs to be passed up the interceptor chain
- MethodCall m = MethodCallFactory.create(MethodDeclarations.moveMethodLocal, nodeToMove, newParent);
- invokeMethod(m, true);
- }
-
- /**
- * Called by reflection
- *
- * @param newParentFqn
- * @param nodeToMoveFqn
- */
- public void _move(Fqn nodeToMoveFqn, Fqn newParentFqn)
- {
- // the actual move algorithm.
- NodeSPI<K, V> newParent = findNode(newParentFqn);
-
- if (newParent == null)
- {
- throw new NodeNotExistsException("New parent node " + newParentFqn + " does not exist when attempting to move node!!");
- }
-
- NodeSPI<K, V> node = findNode(nodeToMoveFqn);
-
- if (node == null)
- {
- throw new NodeNotExistsException("Node " + nodeToMoveFqn + " does not exist when attempting to move node!!");
- }
-
- NodeSPI oldParent = node.getParent();
- Object nodeName = nodeToMoveFqn.getLastElement();
-
- // now that we have the parent and target nodes:
- // first correct the pointers at the pruning point
- oldParent.removeChildDirect(nodeName);
- newParent.addChild(nodeName, node);
- InvocationContext ctx = getInvocationContext();
- // parent pointer is calculated on the fly using Fqns.
- boolean isRollback = checkIsRollingBack(ctx.getTransaction());
-
- // notify
- if (!isRollback)
- notifier.notifyNodeMoved(nodeToMoveFqn, new Fqn(newParentFqn, nodeToMoveFqn.getLastElement()), true, ctx);
-
- // now adjust Fqns of node and all children.
- moveFqns(node, newParent.getFqn());
-
- if (!isRollback)
- notifier.notifyNodeMoved(nodeToMoveFqn, new Fqn(newParentFqn, nodeToMoveFqn.getLastElement()), false, ctx);
-
- // now register an undo op
- if (ctx.getTransaction() != null)
- {
- MethodCall undo = MethodCallFactory.create(MethodDeclarations.moveMethodLocal, new Fqn(newParentFqn, nodeToMoveFqn.getLastElement()), oldParent.getFqn());
- tx_table.addUndoOperation(ctx.getGlobalTransaction(), undo);
- }
- }
-
- public void _block()
- {
- //intentionally empty, used only for reflection in MethodDeclarations.blockChannelLocal
- }
-
- public void _unblock()
- {
- //intentionally empty, used only for reflection in MethodDeclarations.unblockChannelLocal
- }
-
- private void moveFqns(NodeSPI node, Fqn newBase)
- {
- Fqn newFqn = new Fqn(newBase, node.getFqn().getLastElement());
- node.setFqn(newFqn);
- }
-
- /**
- * Set our log category to include our clusterName, if we have one.
- */
- private void configureLogCategory()
- {
- StringBuffer category = new StringBuffer(getClass().getName());
- if (configuration != null)
- {
- String clusterName = configuration.getClusterName();
- if (clusterName != null)
- {
- category.append('.');
- category.append(clusterName);
- }
- }
-
- log = LogFactory.getLog(category.toString());
- }
-
- /**
- * Kills the JGroups channel; an unclean channel disconnect
- */
- public void killChannel()
- {
- if (channel != null)
- {
- channel.close();
- channel.disconnect();
- }
- }
-
- protected class MessageListenerAdaptor implements ExtendedMessageListener
- {
- /**
- * Reference to an exception that was raised during
- * state installation on this node.
- */
- protected volatile Exception setStateException;
- private final Object stateLock = new Object();
-
- protected MessageListenerAdaptor()
- {
- }
-
- public void waitForState() throws Exception
- {
- synchronized (stateLock)
- {
- while (!isStateSet)
- {
- if (setStateException != null)
- {
- throw setStateException;
- }
-
- try
- {
- stateLock.wait();
- }
- catch (InterruptedException iex)
- {
- }
- }
- }
- }
-
- protected void stateReceivedSuccess()
- {
- isStateSet = true;
- setStateException = null;
- }
-
- protected void stateReceivingFailed(Throwable t)
- {
- if (t instanceof CacheException)
- {
- log.debug(t);
- }
- else
- {
- log.error("failed setting state", t);
- }
- if (t instanceof Exception)
- {
- setStateException = (Exception) t;
- }
- else
- {
- setStateException = new Exception(t);
- }
- }
-
- protected void stateProducingFailed(Throwable t)
- {
- if (t instanceof CacheException)
- {
- log.debug(t);
- }
- else
- {
- log.error("Caught " + t.getClass().getName()
- + " while responding to state transfer request", t);
- }
- }
-
- /**
- * Callback, does nothing.
- */
- public void receive(Message msg)
- {
- }
-
- public byte[] getState()
- {
- MarshalledValueOutputStream out = null;
- byte[] result = null;
- ExposedByteArrayOutputStream baos = new ExposedByteArrayOutputStream(16 * 1024);
- try
- {
- out = new MarshalledValueOutputStream(baos);
-
- getStateTransferManager().getState(out, Fqn.ROOT, configuration.getStateRetrievalTimeout(), true, true);
- }
- catch (Throwable t)
- {
- stateProducingFailed(t);
- }
- finally
- {
- result = baos.getRawBuffer();
- Util.close(out);
- }
- return result;
- }
-
- public void setState(byte[] new_state)
- {
- if (new_state == null)
- {
- log.debug("transferred state is null (may be first member in cluster)");
- return;
- }
- ByteArrayInputStream bais = new ByteArrayInputStream(new_state);
- MarshalledValueInputStream in = null;
- try
- {
- in = new MarshalledValueInputStream(bais);
- getStateTransferManager().setState(in, Fqn.ROOT);
- stateReceivedSuccess();
- }
- catch (Throwable t)
- {
- stateReceivingFailed(t);
- }
- finally
- {
- Util.close(in);
- synchronized (stateLock)
- {
- // Notify wait that state has been set.
- stateLock.notifyAll();
- }
- }
- }
-
- public byte[] getState(String state_id)
- {
- MarshalledValueOutputStream out = null;
- String sourceRoot = state_id;
- byte[] result = null;
-
- boolean hasDifferentSourceAndIntegrationRoots = state_id.indexOf(StateTransferManager.PARTIAL_STATE_DELIMITER) > 0;
- if (hasDifferentSourceAndIntegrationRoots)
- {
- sourceRoot = state_id.split(StateTransferManager.PARTIAL_STATE_DELIMITER)[0];
- }
-
- ExposedByteArrayOutputStream baos = new ExposedByteArrayOutputStream(16 * 1024);
- try
- {
- out = new MarshalledValueOutputStream(baos);
-
- getStateTransferManager().getState(out, Fqn.fromString(sourceRoot),
- configuration.getStateRetrievalTimeout(), true, true);
- }
- catch (Throwable t)
- {
- stateProducingFailed(t);
- }
- finally
- {
- result = baos.getRawBuffer();
- Util.close(out);
- }
- return result;
- }
-
- public void getState(OutputStream ostream)
- {
- MarshalledValueOutputStream out = null;
- try
- {
- out = new MarshalledValueOutputStream(ostream);
- getStateTransferManager().getState(out, Fqn.ROOT, configuration.getStateRetrievalTimeout(), true, true);
- }
- catch (Throwable t)
- {
- stateProducingFailed(t);
- }
- finally
- {
- Util.close(out);
- }
- }
-
- public void getState(String state_id, OutputStream ostream)
- {
- String sourceRoot = state_id;
- MarshalledValueOutputStream out = null;
- boolean hasDifferentSourceAndIntegrationRoots = state_id.indexOf(StateTransferManager.PARTIAL_STATE_DELIMITER) > 0;
- if (hasDifferentSourceAndIntegrationRoots)
- {
- sourceRoot = state_id.split(StateTransferManager.PARTIAL_STATE_DELIMITER)[0];
- }
- try
- {
- out = new MarshalledValueOutputStream(ostream);
- getStateTransferManager().getState(out, Fqn.fromString(sourceRoot), configuration.getStateRetrievalTimeout(), true, true);
- }
- catch (Throwable t)
- {
- stateProducingFailed(t);
- }
- finally
- {
- Util.close(out);
- }
- }
-
- public void setState(InputStream istream)
- {
- if (istream == null)
- {
- log.debug("stream is null (may be first member in cluster)");
- return;
- }
- MarshalledValueInputStream in = null;
- try
- {
- in = new MarshalledValueInputStream(istream);
- getStateTransferManager().setState(in, Fqn.ROOT);
- stateReceivedSuccess();
- }
- catch (Throwable t)
- {
- stateReceivingFailed(t);
- }
- finally
- {
- Util.close(in);
- synchronized (stateLock)
- {
- // Notify wait that state has been set.
- stateLock.notifyAll();
- }
- }
- }
-
- public void setState(String state_id, byte[] state)
- {
- if (state == null)
- {
- log.debug("partial transferred state is null");
- return;
- }
-
- MarshalledValueInputStream in = null;
- String targetRoot = state_id;
- boolean hasDifferentSourceAndIntegrationRoots = state_id.indexOf(StateTransferManager.PARTIAL_STATE_DELIMITER) > 0;
- if (hasDifferentSourceAndIntegrationRoots)
- {
- targetRoot = state_id.split(StateTransferManager.PARTIAL_STATE_DELIMITER)[1];
- }
- try
- {
- log.debug("Setting received partial state for subroot " + state_id);
- Fqn subroot = Fqn.fromString(targetRoot);
-// Region region = regionManager.getRegion(subroot, false);
-// ClassLoader cl = null;
-// if (region != null)
-// {
-// // If a classloader is registered for the node's region, use it
-// cl = region.getClassLoader();
-// }
- ByteArrayInputStream bais = new ByteArrayInputStream(state);
- in = new MarshalledValueInputStream(bais);
- //getStateTransferManager().setState(in, subroot, cl);
- getStateTransferManager().setState(in, subroot);
- stateReceivedSuccess();
- }
- catch (Throwable t)
- {
- stateReceivingFailed(t);
- }
- finally
- {
- Util.close(in);
- synchronized (stateLock)
- {
- // Notify wait that state has been set.
- stateLock.notifyAll();
- }
- }
- }
-
- public void setState(String state_id, InputStream istream)
- {
- String targetRoot = state_id;
- MarshalledValueInputStream in = null;
- boolean hasDifferentSourceAndIntegrationRoots = state_id.indexOf(StateTransferManager.PARTIAL_STATE_DELIMITER) > 0;
- if (hasDifferentSourceAndIntegrationRoots)
- {
- targetRoot = state_id.split(StateTransferManager.PARTIAL_STATE_DELIMITER)[1];
- }
- if (istream == null)
- {
- log.debug("stream is null (may be first member in cluster). State is not set");
- return;
- }
-
- try
- {
- log.debug("Setting received partial state for subroot " + state_id);
- in = new MarshalledValueInputStream(istream);
- Fqn subroot = Fqn.fromString(targetRoot);
-// Region region = regionManager.getRegion(subroot, false);
-// ClassLoader cl = null;
-// if (region != null)
-// {
-// // If a classloader is registered for the node's region, use it
-// cl = region.getClassLoader();
-// }
- //getStateTransferManager().setState(in, subroot, cl);
- getStateTransferManager().setState(in, subroot);
- stateReceivedSuccess();
- }
- catch (Throwable t)
- {
- stateReceivingFailed(t);
- }
- finally
- {
- Util.close(in);
- synchronized (stateLock)
- {
- // Notify wait that state has been set.
- stateLock.notifyAll();
- }
- }
- }
- }
-
- /*-------------------- End of MessageListener ----------------------*/
-
- /*----------------------- MembershipListener ------------------------*/
-
- protected class MembershipListenerAdaptor implements ExtendedMembershipListener
- {
-
- public void viewAccepted(View new_view)
- {
- Vector<Address> new_mbrs = new_view.getMembers();
- if (log.isInfoEnabled()) log.info("viewAccepted(): " + new_view);
- synchronized (members)
- {
- boolean needNotification = false;
- if (new_mbrs != null)
- {
- // Determine what members have been removed
- // and roll back any tx and break any locks
- Vector<Address> removed = new Vector<Address>(members);
- removed.removeAll(new_mbrs);
- removeLocksForDeadMembers(root, removed);
-
- members.removeAllElements();
- members.addAll(new_mbrs);
-
- needNotification = true;
- }
-
- // Now that we have a view, figure out if we are the coordinator
- coordinator = (members.size() != 0 && members.get(0).equals(getLocalAddress()));
-
- // now notify listeners - *after* updating the coordinator. - JBCACHE-662
- if (needNotification && notifier != null)
- {
- InvocationContext ctx = getInvocationContext();
- notifier.notifyViewChange(new_view, ctx);
- }
-
- // Wake up any threads that are waiting to know who the members
- // are so they can figure out who the coordinator is
- members.notifyAll();
- }
- }
-
- /**
- * Called when a member is suspected.
- */
- public void suspect(Address suspected_mbr)
- {
- }
-
- /**
- * Indicates that a channel has received a BLOCK event from FLUSH protocol.
- */
- public void block()
- {
- flushBlockGate.close();
- if (log.isDebugEnabled())
- {
- log.debug("Block received at " + getLocalAddress());
- }
- MethodCall m = MethodCallFactory.create(MethodDeclarations.blockChannelLocal);
- getInvocationContext().getOptionOverrides().setSkipCacheStatusCheck(true);
- invokeMethod(m, true);
- if (log.isDebugEnabled())
- {
- log.debug("Block processed at " + getLocalAddress());
- }
- }
-
- /**
- * Indicates that a channel has received a UNBLOCK event from FLUSH protocol.
- */
- public void unblock()
- {
- if (log.isDebugEnabled())
- {
- log.debug("UnBlock received at " + getLocalAddress());
- }
- MethodCall m = MethodCallFactory.create(MethodDeclarations.unblockChannelLocal);
- getInvocationContext().getOptionOverrides().setSkipCacheStatusCheck(true);
- invokeMethod(m, true);
- if (log.isDebugEnabled())
- {
- log.debug("UnBlock processed at " + getLocalAddress());
- }
- flushBlockGate.open();
- }
-
- }
-
- /*------------------- End of MembershipListener ----------------------*/
-
- /* ------------------------------ Private methods --------------------------- */
-
- /**
- * Returns the transaction associated with the current thread. We get the
- * initial context and a reference to the TransactionManager to get the
- * transaction. This method is used by {@link #getCurrentTransaction()}
- */
- protected Transaction getLocalTransaction()
- {
- if (tm == null)
- {
- return null;
- }
- try
- {
- return tm.getTransaction();
- }
- catch (Throwable t)
- {
- return null;
- }
- }
-
-
- /**
- * Returns true if transaction is ACTIVE or PREPARING, false otherwise.
- */
- private boolean isValid(Transaction tx)
- {
- if (tx == null) return false;
- int status = -1;
- try
- {
- status = tx.getStatus();
- return status == Status.STATUS_ACTIVE || status == Status.STATUS_PREPARING;
- }
- catch (SystemException e)
- {
- log.error("failed getting transaction status", e);
- return false;
- }
- }
-
-
- /**
- * Returns the transaction associated with the current thread.
- * If a local transaction exists, but doesn't yet have a mapping to a
- * GlobalTransaction, a new GlobalTransaction will be created and mapped to
- * the local transaction. Note that if a local transaction exists, but is
- * not ACTIVE or PREPARING, null is returned.
- *
- * @return A GlobalTransaction, or null if no (local) transaction was associated with the current thread
- */
- public GlobalTransaction getCurrentTransaction()
- {
- return getCurrentTransaction(true);
- }
-
- /**
- * Returns the transaction associated with the thread; optionally creating
- * it if is does not exist.
- */
- public GlobalTransaction getCurrentTransaction(boolean createIfNotExists)
- {
- Transaction tx;
-
- if ((tx = getLocalTransaction()) == null)
- {// no transaction is associated with the current thread
- return null;
- }
-
- if (!isValid(tx))
- {// we got a non-null transaction, but it is not active anymore
- int status = -1;
- try
- {
- status = tx.getStatus();
- }
- catch (SystemException e)
- {
- }
-
- // JBCACHE-982 -- don't complain if COMMITTED
- if (status != Status.STATUS_COMMITTED)
- {
- log.warn("status is " + status + " (not ACTIVE or PREPARING); returning null)", new Throwable());
- }
- else
- {
- log.trace("status is COMMITTED; returning null");
- }
-
- return null;
- }
-
- return getCurrentTransaction(tx, createIfNotExists);
- }
-
- /**
- * Returns the global transaction for this local transaction.
- */
- public GlobalTransaction getCurrentTransaction(Transaction tx)
- {
- return getCurrentTransaction(tx, true);
- }
-
- /**
- * Returns the global transaction for this local transaction.
- *
- * @param createIfNotExists if true, if a global transaction is not found; one is created
- */
- public GlobalTransaction getCurrentTransaction(Transaction tx, boolean createIfNotExists)
- {
- // removed synchronization on tx_table because underlying implementation is thread safe
- // and JTA spec (section 3.4.3 Thread of Control, par 2) says that only one thread may
- // operate on the transaction at one time so no concern about 2 threads trying to call
- // this method for the same Transaction instance at the same time
- //
- GlobalTransaction gtx = tx_table.get(tx);
- if (gtx == null && createIfNotExists)
- {
- Address addr = getLocalAddress();
- gtx = GlobalTransaction.create(addr);
- tx_table.put(tx, gtx);
- TransactionEntry ent = configuration.isNodeLockingOptimistic() ? new OptimisticTransactionEntry() : new TransactionEntry();
- ent.setTransaction(tx);
- tx_table.put(gtx, ent);
- if (log.isTraceEnabled())
- {
- log.trace("created new GTX: " + gtx + ", local TX=" + tx);
- }
- }
- return gtx;
- }
-
-
- /**
- * Invokes a method against this object. Contains the logger_ic for handling
- * the various use cases, e.g. mode (local, repl_async, repl_sync),
- * transaction (yes or no) and locking (yes or no).
- * <p/>
- * Only sets originLocal on the invocation context IF this is explicitly passed in as <tt>false</tt>
- * If passed in as <tt>true</tt> then it is not set; but whatever default exists in the invocation
- * context is used. For example, it may be set prior to calling invokeMethod()
- */
- protected Object invokeMethod(MethodCall m, boolean originLocal) throws CacheException
- {
- // don't create a new one; get it from ThreadLocal just this once, in case a user has added any overrides.
- InvocationContext ctx = getInvocationContext();
-
- // BR methods should NOT block on the cache being started, since the cache depends on these completing to start.
- if (!MethodDeclarations.isBuddyGroupOrganisationMethod(m.getMethodId()) && !cacheStatus.allowInvocations() && !ctx.getOptionOverrides().isSkipCacheStatusCheck())
- throw new IllegalStateException("Cache not in STARTED state!");
-
- MethodCall oldCall = null;
- try
- {
- // check if we had a method call lurking around
- oldCall = ctx.getMethodCall();
- ctx.setMethodCall(m);
- // only set this if originLocal is EXPLICITLY passed in as FALSE. Otherwise leave it as a default.
- if (!originLocal) ctx.setOriginLocal(false);
- return interceptor_chain.invoke(ctx);
- }
- catch (CacheException e)
- {
- throw e;
- }
- catch (RuntimeException e)
- {
- throw e;
- }
- catch (Throwable t)
- {
- throw new RuntimeException(t);
- }
- finally
- {
- if (!originLocal) ctx.setOriginLocal(true);
- // reset old method call
- ctx.setMethodCall(oldCall);
- }
- }
-
- /**
- * Returns an object suitable for use in node locking, either the current
- * transaction or the current thread if there is no transaction.
- */
- protected Object getOwnerForLock()
- {
- Object owner = getCurrentTransaction();
- if (owner == null)
- {
- owner = Thread.currentThread();
- }
-
- return owner;
- }
-
- /**
- * Finds a node given a fully qualified name.
- * Whenever nodes are created, and the global transaction is not null, the created
- * nodes have to be added to the transaction's {@link TransactionEntry}
- * field.<br>
- * When a lock is acquired on a node, a reference to the lock has to be
- * {@link TransactionEntry#addLock(org.jboss.cache.lock.NodeLock) added to the list of locked nodes}
- * in the {@link TransactionEntry}.
- * <p>This operation will also apply different locking to the cache nodes, depending on
- * <tt>operation_type</tt>. If it is <tt>read</tt> type, all nodes will be acquired with
- * read lock. Otherwise, the operation is <tt>write</tt> type, all parent nodes will be acquired
- * with read lock while the destination node acquires write lock.</p>
- *
- * @param fqn Fully qualified name for the corresponding node.
- * @return DataNode
- */
- public NodeSPI<K, V> findNode(Fqn fqn)
- {
- try
- {
- return findNode(fqn, null);
- }
- catch (CacheException e)
- {
- log.warn("Unexpected error", e);
- return null;
- }
- }
-
- private NodeSPI<K, V> findNodeCheck(GlobalTransaction tx, Fqn fqn)
- {
- NodeSPI<K, V> n = findNode(fqn);
- if (n == null)
- {
- String errStr = "node " + fqn + " not found (gtx=" + tx + ", caller=" + Thread.currentThread() + ")";
- if (log.isTraceEnabled())
- {
- log.trace(errStr);
- }
- throw new NodeNotExistsException(errStr);
- }
- return n;
- }
-
- /**
- * Internal method; not to be used externally.
- * Returns true if the node was found, false if not.
- *
- * @param f
- */
- public boolean realRemove(Fqn f, boolean skipMarkerCheck)
- {
- NodeSPI n = peek(f, true);
- if (n == null)
- {
- return false;
- }
-
- if (log.isTraceEnabled()) log.trace("Performing a real remove for node " + f + ", marked for removal.");
- if (skipMarkerCheck || n.isDeleted())
- {
- if (n.getFqn().isRoot())
- {
- // do not actually delete; just remove deletion marker
- n.markAsDeleted(true);
- // but now remove all children, since the call has been to remove("/")
- n.removeChildrenDirect();
- return true;
- }
- else
- {
- return n.getParent().removeChildDirect(n.getFqn().getLastElement());
- }
- }
- else
- {
- if (log.isDebugEnabled()) log.debug("Node " + f + " NOT marked for removal as expected, not removing!");
- return false;
- }
- }
-
- /**
- * Finds a node given a fully qualified name and DataVersion.
- */
- private NodeSPI<K, V> findNode(Fqn fqn, DataVersion version) throws CacheException
- {
- if (fqn == null) return null;
-
- NodeSPI<K, V> toReturn = peek(fqn, false);
-
- if (version != null && configuration.isNodeLockingOptimistic())
- {
- // we need to check the version of the data node...
- DataVersion nodeVersion = toReturn.getVersion();
- if (log.isTraceEnabled())
- {
- log.trace("looking for optimistic node [" + fqn + "] with version [" + version + "]. My version is [" + nodeVersion + "]");
- }
- if (nodeVersion.newerThan(version))
- {
- // we have a versioning problem; throw an exception!
- throw new CacheException("Unable to validate versions.");
- }
- }
- return toReturn;
- }
-
- public synchronized RegionManager getRegionManager()
- {
- if (regionManager == null)
- {
- regionManager = new RegionManager(this);
- }
- return regionManager;
- }
-
-
- public Marshaller getMarshaller()
- {
- if (marshaller_ == null)
- {
- synchronized (this)
- {
- if (marshaller_ == null)
- {
- if (configuration.getMarshallerClass() == null || configuration.getMarshallerClass().equals(VersionAwareMarshaller.class.getName()))
- {
- marshaller_ = new VersionAwareMarshaller(getRegionManager(), configuration);
- }
- else
- {
- try
- {
- marshaller_ = (Marshaller) org.jboss.cache.util.Util.loadClass(configuration.getMarshallerClass()).newInstance();
- }
- catch (Exception e)
- {
- log.error("Unable to load marshaller " + configuration.getMarshallerClass() + ". Falling back to default (" + VersionAwareMarshaller.class.getName() + ")");
- marshaller_ = new VersionAwareMarshaller(getRegionManager(), configuration);
- }
- }
- if (log.isTraceEnabled()) log.trace("Using marshaller " + marshaller_.getClass().getName());
- }
- }
- }
- return marshaller_;
- }
-
- /**
- * Returns the default JGroup properties.
- * Subclasses may wish to override this method.
- */
- protected String getDefaultProperties()
- {
- return "UDP(mcast_addr=224.0.0.36;mcast_port=55566;ip_ttl=32;" +
- "mcast_send_buf_size=150000;mcast_recv_buf_size=80000):" +
- "PING(timeout=1000;num_initial_members=2):" +
- "MERGE2(min_interval=5000;max_interval=10000):" +
- "FD_SOCK:" +
- "VERIFY_SUSPECT(timeout=1500):" +
- "pbcast.NAKACK(gc_lag=50;max_xmit_size=8192;retransmit_timeout=600,1200,2400,4800):" +
- "UNICAST(timeout=600,1200,2400,4800):" +
- "pbcast.STABLE(desired_avg_gossip=20000):" +
- "FRAG(frag_size=8192;down_thread=false;up_thread=false):" +
- "pbcast.GMS(join_timeout=5000;join_retry_timeout=2000;" +
- "shun=false;print_local_addr=true):" +
- "pbcast.STATE_TRANSFER";
- }
-
- private void initialiseCacheLoaderManager() throws CacheException
- {
- if (cacheLoaderManager == null)
- {
- cacheLoaderManager = new CacheLoaderManager();
- }
- cacheLoaderManager.setConfig(configuration.getCacheLoaderConfig(), this);
- }
-
- /**
- * Sets the CacheLoader to use.
- * Provided for backwards compatibility.
- *
- * @param loader
- * @deprecated only provided for backward compat
- */
- @Deprecated
- public void setCacheLoader(CacheLoader loader)
- {
- log.warn("Using deprecated config method setCacheLoader. This element will be removed in future, please use CacheLoaderConfiguration instead.");
-
- try
- {
- if (cacheLoaderManager == null) initialiseCacheLoaderManager();
- }
- catch (Exception e)
- {
- log.warn("Problem setting cache loader. Perhaps your cache loader config has not been set yet?");
- }
- cacheLoaderManager.setCacheLoader(loader);
- }
-
- /**
- * Purges the contents of all configured {@link CacheLoader}s
- */
- public void purgeCacheLoaders() throws Exception
- {
- if (cacheLoaderManager != null) cacheLoaderManager.purgeLoaders(true);
- }
-
- // ---------------------------------------------------------------
- // END: Methods to provide backward compatibility with older cache loader config settings
- // ---------------------------------------------------------------
-
- private void initialiseChannelAndRpcDispatcher() throws CacheException
- {
- channel = configuration.getRuntimeConfig().getChannel();
- if (channel == null)
- {
- // Try to create a multiplexer channel
- channel = getMultiplexerChannel();
-
- if (channel != null)
- {
- configuration.setUsingMultiplexer(true);
- if (log.isDebugEnabled())
- {
- log.debug("Created Multiplexer Channel for cache cluster " + configuration.getClusterName() +
- " using stack " + configuration.getMultiplexerStack());
- }
- }
- else
- {
- if (configuration.getClusterConfig() == null)
- {
- log.debug("setting cluster properties to default value");
- configuration.setClusterConfig(getDefaultProperties());
- }
- try
- {
- channel = new JChannel(configuration.getClusterConfig());
- }
- catch (Exception e)
- {
- throw new CacheException("Unable to create JGroups channel", e);
- }
- if (log.isTraceEnabled())
- {
- log.trace("cache properties: " + configuration.getClusterConfig());
- }
- }
-
- configuration.getRuntimeConfig().setChannel(channel);
- }
-
- channel.setOpt(Channel.AUTO_RECONNECT, true);
- channel.setOpt(Channel.AUTO_GETSTATE, true);
- channel.setOpt(Channel.BLOCK, true);
-
- // always use the InactiveRegionAwareRpcDispatcher - exceptions due to regions not being active should not propagate to remote
- // nodes as errors. - Manik
- disp = new InactiveRegionAwareRpcDispatcher(channel, ml, new MembershipListenerAdaptor(), this);
- // disp = new RpcDispatcher(channel, ml, this, this);
-
- disp.setRequestMarshaller(getMarshaller());
- disp.setResponseMarshaller(getMarshaller());
- }
-
- private JChannel getMultiplexerChannel() throws CacheException
- {
- String stackName = configuration.getMultiplexerStack();
-
- RuntimeConfig rtc = configuration.getRuntimeConfig();
- ChannelFactory channelFactory = rtc.getMuxChannelFactory();
- JChannel muxchannel = null;
-
- if (channelFactory != null)
- {
- try
- {
- muxchannel = (JChannel) channelFactory.createMultiplexerChannel(stackName, configuration.getClusterName());
- }
- catch (Exception e)
- {
- throw new CacheException("Failed to create multiplexed channel using stack " + stackName, e);
- }
- }
-
- return muxchannel;
- }
-
- // ================== methods to implement Cache and CacheSPI interfaces ============================
-
- public List<Interceptor> getInterceptorChain()
- {
- List<Interceptor> modifiable = getInterceptors();
- return modifiable == null ? null : Collections.unmodifiableList(modifiable);
- }
-
- public void addCacheListener(Object listener)
- {
- getNotifier().addCacheListener(listener);
- }
-
- public void addCacheListener(Fqn<?> region, Object listener)
- {
- throw new UnsupportedOperationException("Not implemented in this release");
- }
-
- public void removeCacheListener(Object listener)
- {
- // BES 2007/5/23 workaround to avoid NPE while we decide whether
- // to remove notifier in destroy()
- Notifier n = getNotifier();
- if (n != null)
- n.removeCacheListener(listener);
- }
-
- public void removeCacheListener(Fqn<?> region, Object listener)
- {
- throw new UnsupportedOperationException("Not implemented in this release");
- }
-
- public Set<Object> getCacheListeners()
- {
- return getNotifier().getCacheListeners();
- }
-
- public Set<Object> getCacheListeners(Fqn<?> region)
- {
- throw new UnsupportedOperationException("Not implemented in this release");
- }
-
- public synchronized void addInterceptor(Interceptor i, int position)
- {
- List<Interceptor> interceptors = getInterceptors();
-
- i.setCache(this);
-
- interceptors.add(position, i);
-
- // now correct the chaining of interceptors...
- Interceptor linkedChain = InterceptorChainFactory.getInstance().correctInterceptorChaining(interceptors);
-
- setInterceptorChain(linkedChain);
- }
-
- public synchronized void removeInterceptor(int position)
- {
- List<Interceptor> i = getInterceptors();
- i.remove(position);
- setInterceptorChain(InterceptorChainFactory.getInstance().correctInterceptorChaining(i));
- }
-
- public RPCManager getRPCManager()
- {
- return configuration.getRuntimeConfig().getRPCManager();
- }
-
- public String getClusterName()
- {
- return getConfiguration().getClusterName();
- }
-
- public void evict(Fqn<?> fqn, boolean recursive)
- {
- if (recursive)
- {
- Node<K, V> n = get(fqn);
- if (n != null)
- {
- evictChildren((NodeSPI<K, V>) n);
- }
- }
- else
- {
- evict(fqn);
- }
- }
-
- private void evictChildren(NodeSPI<K, V> n)
- {
- for (NodeSPI<K, V> child : n.getChildrenDirect())
- {
- evictChildren(child);
- }
- evict(n.getFqn());
- }
-
- public Region getRegion(Fqn<?> fqn, boolean createIfAbsent)
- {
- return getRegionManager().getRegion(fqn, createIfAbsent);
- }
-
- public boolean removeRegion(Fqn<?> fqn)
- {
- return getRegionManager().removeRegion(fqn);
- }
-
- public boolean removeNode(Fqn<?> fqn)
- {
- return remove(fqn);
- }
-
- public void putForExternalRead(Fqn<?> fqn, K key, V value)
- {
- // if the node exists then this should be a no-op.
- if (!exists(fqn))
- {
- getInvocationContext().getOptionOverrides().setFailSilently(true);
- GlobalTransaction tx = getCurrentTransaction();
- MethodCall m = MethodCallFactory.create(MethodDeclarations.putForExternalReadMethodLocal, tx, fqn, key, value);
- invokeMethod(m, true);
- }
- else
- {
- if (log.isDebugEnabled())
- log.debug("putForExternalRead() called with Fqn " + fqn + " and this node already exists. This method is hence a no op.");
- }
- }
-
- public void _putForExternalRead(GlobalTransaction gtx, Fqn fqn, K key, V value)
- {
- _put(gtx, fqn, key, value, true);
- }
-
- public boolean isStarted()
- {
- return getCacheStatus() == CacheStatus.STARTED;
- }
-
- protected void setMessageListener(MessageListenerAdaptor ml)
- {
- this.ml = ml;
- }
-
-}
Deleted: core/trunk/src-old/org/jboss/cache/CacheSPI.java
===================================================================
--- core/trunk/src-old/org/jboss/cache/CacheSPI.java 2007-08-14 19:09:32 UTC (rev 4251)
+++ core/trunk/src-old/org/jboss/cache/CacheSPI.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -1,186 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source
- *
- * Distributable under LGPL license.
- * See terms of license at gnu.org.
- */
-package org.jboss.cache;
-
-import net.jcip.annotations.ThreadSafe;
-import org.jboss.cache.buddyreplication.BuddyManager;
-import org.jboss.cache.buddyreplication.GravitateResult;
-import org.jboss.cache.interceptors.Interceptor;
-import org.jboss.cache.loader.CacheLoader;
-import org.jboss.cache.loader.CacheLoaderManager;
-import org.jboss.cache.lock.NodeLock;
-import org.jboss.cache.marshall.Marshaller;
-import org.jboss.cache.notifications.Notifier;
-import org.jboss.cache.statetransfer.StateTransferManager;
-import org.jboss.cache.transaction.GlobalTransaction;
-import org.jboss.cache.transaction.TransactionTable;
-
-import javax.transaction.Transaction;
-import javax.transaction.TransactionManager;
-import java.util.List;
-import java.util.Map;
-
-/**
- * A more detailed interface to {@link Cache}, which is used when writing plugins for or extending JBoss Cache. A reference
- * to this interface should only be obtained when it is passed in to your code, for example when you write an
- * {@link Interceptor} or {@link CacheLoader}.
- * <p/>
- * <B><I>You should NEVER attempt to directly cast a {@link Cache} instance to this interface. In future, the implementation may not allow it.</I></B>
- * <p/>
- * This interface contains overridden method signatures of some methods from {@link Cache}, overridden to ensure return
- * types of {@link Node} are replaced with {@link NodeSPI}.
- * <p/>
- *
- * @author <a href="mailto:manik at jboss.org">Manik Surtani (manik at jboss.org)</a>
- * @see NodeSPI
- * @see Cache
- * @see org.jboss.cache.loader.CacheLoader
- * @see org.jboss.cache.interceptors.Interceptor
- * @since 2.0.0
- */
- at ThreadSafe
-public interface CacheSPI<K, V> extends Cache<K, V>
-{
- /**
- * Overrides {@link org.jboss.cache.Cache#getRoot()} to return a {@link org.jboss.cache.NodeSPI} instead of a {@link org.jboss.cache.Node}.
- */
- NodeSPI<K, V> getRoot();
-
- /**
- * Retrieves a reference to a running {@link javax.transaction.TransactionManager}, if one is configured.
- *
- * @return a TransactionManager
- */
- TransactionManager getTransactionManager();
-
- /**
- * @return an immutable {@link List} of {@link Interceptor}s configured for this cache, or
- * <code>null</code> if {@link Cache#create() create()} has not been invoked
- * and the interceptors thus do not exist.
- */
- List<Interceptor> getInterceptorChain();
-
- /**
- * Adds a custom interceptor to the interceptor chain, at specified position, where the first interceptor in the chain
- * is at position 0 and the last one at getInterceptorChain().size() - 1.
- *
- * @param i the interceptor to add
- * @param position the position to add the interceptor
- */
- void addInterceptor(Interceptor i, int position);
-
- /**
- * Removes the interceptor at a specified position, where the first interceptor in the chain
- * is at position 0 and the last one at getInterceptorChain().size() - 1.
- *
- * @param position the position at which to remove an interceptor
- */
- void removeInterceptor(int position);
-
- /**
- * @return Retrieves a reference to the currently configured {@link org.jboss.cache.loader.CacheLoaderManager} if one or more cache loaders are configured, null otherwise.
- */
- CacheLoaderManager getCacheLoaderManager();
-
- /**
- * @return an instance of {@link BuddyManager} if buddy replication is enabled, null otherwise.
- */
- BuddyManager getBuddyManager();
-
- /**
- * @return the current {@link TransactionTable}
- */
- TransactionTable getTransactionTable();
-
- /**
- * Gets a handle of the RPC manager.
- *
- * @return the {@link org.jboss.cache.RPCManager} configured.
- */
- RPCManager getRPCManager();
-
- /**
- * @return the current {@link org.jboss.cache.statetransfer.StateTransferManager}
- */
- StateTransferManager getStateTransferManager();
-
- /**
- * @return the name of the cluster. Null if running in local mode.
- */
- String getClusterName();
-
- /**
- * @return the number of attributes in the cache.
- */
- int getNumberOfAttributes();
-
- /**
- * @return the number of nodes in the cache.
- */
- int getNumberOfNodes();
-
- /**
- * Retrieves the current table of locks.
- *
- * @return lock table.
- */
- Map<Thread, List<NodeLock>> getLockTable();
-
- /**
- * @return the {@link org.jboss.cache.RegionManager}
- */
- RegionManager getRegionManager();
-
- /**
- * Returns the global transaction for this local transaction.
- * Optionally creates a new global transaction if it does not exist.
- *
- * @param tx the current transaction
- * @param createIfNotExists if true creates a new transaction if none exists
- * @return a GlobalTransaction
- */
- GlobalTransaction getCurrentTransaction(Transaction tx, boolean createIfNotExists);
-
- /**
- * @return the notifier attached with this instance of the cache. See {@link Notifier}, a class
- * that is responsible for emitting notifications to registered CacheListeners.
- */
- Notifier getNotifier();
-
- /**
- * Returns a node without accessing the interceptor chain.
- *
- * @param fqn the Fqn to look up.
- * @param includeDeletedNodes if you intend to see nodes marked as deleted within the current tx, set this to true
- * @return a node if one exists or null
- */
- NodeSPI<K, V> peek(Fqn<?> fqn, boolean includeDeletedNodes);
-
- /**
- * Used with buddy replication's data gravitation interceptor. If marshalling is necessary, ensure that the cache is
- * configured to use {@link org.jboss.cache.config.Configuration#useRegionBasedMarshalling} and the {@link org.jboss.cache.Region}
- * pertaining to the Fqn passed in is activated, and has an appropriate ClassLoader.
- *
- * @param fqn the fqn to gravitate
- * @param searchBuddyBackupSubtrees if true, buddy backup subtrees are searched and if false, they are not.
- * @return a GravitateResult which contains the data for the gravitation
- */
- GravitateResult gravitateData(Fqn<?> fqn, boolean searchBuddyBackupSubtrees);
-
- /**
- * Retrieves an instance of a {@link Marshaller}, which is capable of
- * converting Java objects to bytestreams and back in an efficient manner, which is
- * also interoperable with bytestreams produced/consumed by other versions of JBoss
- * Cache.
- * <p/>
- * The use of this marshaller is the <b>recommended</b> way of creating efficient,
- * compatible, byte streams from objects.
- *
- * @return an instance of {@link Marshaller}
- */
- Marshaller getMarshaller();
-}
Deleted: core/trunk/src-old/org/jboss/cache/CacheStatus.java
===================================================================
--- core/trunk/src-old/org/jboss/cache/CacheStatus.java 2007-08-14 19:09:32 UTC (rev 4251)
+++ core/trunk/src-old/org/jboss/cache/CacheStatus.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -1,224 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source.
- * Copyright 2006, 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 org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-/**
- * Various states that an object that has a four stage lifecycle
- * (i.e. <code>create()</code>, <code>start()</code>, <code>stop()</code>
- * and <code>destroy()</code>) might be in.
- *
- * @author <a href="brian.stansberry at jboss.com">Brian Stansberry</a>
- * @version $Revision$
- */
-public enum CacheStatus
-{
- /**
- * Object has been instantiated, but create() has not been called.
- */
- INSTANTIATED,
- /**
- * The <code>create()</code> method has been called but not yet completed.
- */
- CREATING,
- /**
- * The <code>create()</code> method has been completed but
- * <code>start()</code> has not been called.
- */
- CREATED,
- /**
- * The <code>start()</code> method has been called but has not yet completed.
- */
- STARTING,
- /**
- * The <code>start()</code> method has completed.
- */
- STARTED,
- /**
- * The <code>stop()</code> method has been called but has not yet completed.
- */
- STOPPING,
- /**
- * The <code>stop()</code> method has completed but <code>destroy()</code>
- * has not yet been called. Conceptually equivalent to {@link #CREATED}.
- */
- STOPPED,
- /**
- * The <code>destroy()</code> method has been called but has not yet completed.
- */
- DESTROYING,
- /**
- * The <code>destroy()</code> method has completed.
- * Conceptually equivalent to {@link #INSTANTIATED}.
- */
- DESTROYED,
- /**
- * A failure occurred during the execution of <code>create()</code>,
- * <code>start()</code>, <code>stop()</code> or <code>destroy()</code>.
- * The next logical transition is to call <code>destroy()</code>.
- */
- FAILED;
-
- private static final Log log = LogFactory.getLog(CacheStatus.class);
-
- public boolean createAllowed()
- {
- switch (this)
- {
- case CREATING:
- case CREATED:
- case STARTING:
- case STARTED:
- case STOPPED:
- log.debug("Ignoring call to create() as current state is " + this);
- // fall through
- case FAILED:
- return false;
- case STOPPING:
- case DESTROYING:
- log.warn("Ignoring call to create() while cache is " + this);
- return false;
- case INSTANTIATED:
- case DESTROYED:
- default:
- return true;
- }
- }
-
- public boolean needToDestroyFailedCache()
- {
- if (this == CacheStatus.FAILED)
- {
- log.debug("need to call destroy() since current state is " +
- this);
- return true;
- }
-
- return false;
- }
-
- public boolean startAllowed()
- {
- switch (this)
- {
- case INSTANTIATED:
- case DESTROYED:
- case STARTING:
- case STARTED:
- log.debug("Ignoring call to start() as current state is " + this);
- // fall through
- case FAILED:
- return false;
- case STOPPING:
- case DESTROYING:
- log.warn("Ignoring call to start() as current state is " + this);
- return false;
- case CREATED:
- case STOPPED:
- default:
- return true;
- }
- }
-
- public boolean needCreateBeforeStart()
- {
- switch (this)
- {
- case INSTANTIATED:
- case DESTROYED:
- log.debug("start() called while current state is " +
- this + " -- call create() first");
- return true;
- default:
- return false;
- }
- }
-
- public boolean stopAllowed()
- {
- switch (this)
- {
- case INSTANTIATED:
- case CREATED:
- case STOPPED:
- case DESTROYED:
- log.debug("Ignoring call to stop() as current state is " + this);
- return false;
- case CREATING:
- case STARTING:
- case STOPPING:
- case DESTROYING:
- log.warn("Ignoring call to stop() as current state is " + this);
- return false;
- case FAILED:
- case STARTED:
- default:
- return true;
- }
-
- }
-
- public boolean destroyAllowed()
- {
- switch (this)
- {
- case INSTANTIATED:
- case DESTROYED:
- log.debug("Ignoring call to destroy() as current state is " + this);
- return false;
- case CREATING:
- case STARTING:
- case STOPPING:
- case DESTROYING:
- log.warn("Ignoring call to destroy() as current state iswhile cache is " + this);
- return false;
- case STARTED:
- // stop first
- return false;
- case CREATED:
- case STOPPED:
- case FAILED:
- default:
- return true;
- }
- }
-
- public boolean needStopBeforeDestroy()
- {
- if (this == CacheStatus.STARTED)
- {
- log.warn("destroy() called while current state is " +
- this + " -- call stop() first");
- return true;
- }
-
- return false;
- }
-
- public boolean allowInvocations()
- {
- return (this == CacheStatus.STARTED);
- }
-}
Deleted: core/trunk/src-old/org/jboss/cache/ConsoleListener.java
===================================================================
--- core/trunk/src-old/org/jboss/cache/ConsoleListener.java 2007-08-14 19:09:32 UTC (rev 4251)
+++ core/trunk/src-old/org/jboss/cache/ConsoleListener.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -1,230 +0,0 @@
-package org.jboss.cache;
-
-import org.jboss.cache.notifications.annotation.CacheListener;
-import org.jboss.cache.notifications.annotation.CacheStarted;
-import org.jboss.cache.notifications.annotation.CacheStopped;
-import org.jboss.cache.notifications.annotation.NodeActivated;
-import org.jboss.cache.notifications.annotation.NodeCreated;
-import org.jboss.cache.notifications.annotation.NodeEvicted;
-import org.jboss.cache.notifications.annotation.NodeLoaded;
-import org.jboss.cache.notifications.annotation.NodeModified;
-import org.jboss.cache.notifications.annotation.NodeMoved;
-import org.jboss.cache.notifications.annotation.NodePassivated;
-import org.jboss.cache.notifications.annotation.NodeRemoved;
-import org.jboss.cache.notifications.annotation.NodeVisited;
-import org.jboss.cache.notifications.annotation.ViewChanged;
-import org.jboss.cache.notifications.event.Event;
-import org.jboss.cache.notifications.event.NodeEvent;
-import org.jboss.cache.notifications.event.ViewChangedEvent;
-
-/**
- * This class provides a non-graphical view of <em>JBossCache</em> replication
- * events for a replicated cache.
- * <p/>
- * It can be utilized as a standalone application or as a component in other
- * applications.
- * <p/>
- * <strong>WARNING</strong>: take care when using this class in conjunction with
- * transactionally replicated cache's as it can cause deadlock situations due to
- * the reading of values for nodes in the cache.
- *
- * @author Jimmy Wilson 12-2004
- */
- at CacheListener
-public class ConsoleListener
-{
- private CacheImpl _cache;
- private boolean _startCache;
-
- /**
- * Constructor.
- * <p/>
- * When using this constructor, this class with attempt to start and stop
- * the specified cache.
- *
- * @param cache the cache to monitor for replication events.
- */
- public ConsoleListener(CacheImpl cache)
- throws Exception
- {
- this(cache, true, true);
- }
-
- /**
- * Constructor.
- *
- * @param cache the cache to monitor for replication events.
- * @param startCache indicates whether or not the cache should be started by
- * this class.
- * @param stopCache indicates whether or not the cache should be stopped by
- * this class.
- */
- public ConsoleListener(CacheImpl cache,
- boolean startCache, boolean stopCache)
- throws Exception
- {
- _cache = cache;
- _startCache = startCache;
-
- if (stopCache)
- {
- new ListenerShutdownHook().register();
- }
- }
-
- /**
- * Instructs this class to listen for cache replication events.
- * <p/>
- * This method waits indefinately. Use the notify method of this class
- * (using traditional Java thread notification semantics) to cause this
- * method to return.
- */
- public void listen()
- throws Exception
- {
- listen(true);
- }
-
- /**
- * Instructs this class to listen for cache replication events.
- *
- * @param wait whether or not this method should wait indefinately.
- * <p/>
- * If this parameter is set to <code>true</code>, using the
- * notify method of this class (using traditional Java thread
- * notification semantics) will cause this method to return.
- */
- public void listen(boolean wait)
- throws Exception
- {
- _cache.getNotifier().addCacheListener(this);
-
- if (_startCache)
- {
- _cache.start();
- }
-
- synchronized (this)
- {
- while (wait)
- {
- wait();
- }
- }
- }
-
-
- @CacheStarted
- @CacheStopped
- public void printDetails(Event e)
- {
- printEvent("Cache started.");
- }
-
-
- @NodeCreated
- @NodeLoaded
- @NodeModified
- @NodeRemoved
- @NodeVisited
- @NodeMoved
- @NodeEvicted
- @NodeActivated
- @NodePassivated
- public void printDetailsWithFqn(NodeEvent e)
- {
- if (e.isPre())
- {
- printEvent("Event " + e.getType() + " on node [" + e.getFqn() + "] about to be invoked");
- }
- else
- {
- printEvent("Event " + e.getType() + " on node [" + e.getFqn() + "] invoked");
- }
- }
-
- @ViewChanged
- public void printNewView(ViewChangedEvent e)
- {
- printEvent("View change: " + e.getNewView());
- }
-
- /**
- * Prints an event message.
- *
- * @param eventSuffix the suffix of the event message.
- */
- private void printEvent(String eventSuffix)
- {
- System.out.print("EVENT");
- System.out.print(' ');
-
- System.out.println(eventSuffix);
- }
-
- /**
- * This class provides a shutdown hook for shutting down the cache.
- */
- private class ListenerShutdownHook extends Thread
- {
- /**
- * Registers this hook for invocation during shutdown.
- */
- public void register()
- {
- Runtime.getRuntime().addShutdownHook(this);
- }
-
- /*
- * Thread overrides.
- */
-
- public void run()
- {
- _cache.stop();
- }
- }
-
- /**
- * The main method.
- *
- * @param args command line arguments dictated by convention.
- * <p/>
- * The first command line argument is the name of the
- * <code>JBossCache</code> configuration file to be utilized
- * for configuration of the cache. Only the name of the
- * configuration file is necessary as it is read off of the
- * classpath.
- * <p/>
- * If a configuration file is not specified on the command line,
- * <code>jboss-cache.xml</code> will be the assumed file name.
- * <p/>
- * All command line arguments after the first are ignored.
- */
- public static void main(String[] args)
- {
- final String DEFAULT_CONFIG_FILE_NAME = "jboss-cache.xml";
-
- try
- {
- String configFileName = DEFAULT_CONFIG_FILE_NAME;
-
- if (args.length >= 1)
- {
- configFileName = args[0];
- }
- else
- {
- System.out.print("No xml config file argument is supplied. Will use jboss-cache.xml from classpath");
- }
-
- CacheImpl cache = (CacheImpl) DefaultCacheFactory.getInstance().createCache(configFileName);
- ConsoleListener listener = new ConsoleListener(cache);
- listener.listen();
- }
- catch (Throwable throwable)
- {
- throwable.printStackTrace();
- }
- }
-}
Deleted: core/trunk/src-old/org/jboss/cache/DefaultCacheFactory.java
===================================================================
--- core/trunk/src-old/org/jboss/cache/DefaultCacheFactory.java 2007-08-14 19:09:32 UTC (rev 4251)
+++ core/trunk/src-old/org/jboss/cache/DefaultCacheFactory.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -1,95 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source
- *
- * Distributable under LGPL license.
- * See terms of license at gnu.org.
- */
-package org.jboss.cache;
-
-import org.jboss.cache.config.Configuration;
-import org.jboss.cache.config.ConfigurationException;
-import org.jboss.cache.factories.XmlConfigurationParser;
-
-/**
- * Default (singleton) implementation of the {@link org.jboss.cache.CacheFactory} interface.
- * Use {@link #getInstance()} to obtain an instance.
- *
- * @author <a href="mailto:manik at jboss.org">Manik Surtani (manik at jboss.org)</a>
- */
-public class DefaultCacheFactory<K, V> implements CacheFactory<K, V>
-{
- private static CacheFactory singleton = new DefaultCacheFactory();
-
- /**
- * @return a singleton instance of this class.
- */
- public static <K, V> CacheFactory<K, V> getInstance()
- {
- return singleton;
- }
-
- public Cache<K, V> createCache() throws ConfigurationException
- {
- return createCache(true);
- }
-
- public Cache<K, V> createCache(boolean start) throws ConfigurationException
- {
- return createCache(new Configuration(), start);
- }
-
- public Cache<K, V> createCache(String configFileName) throws ConfigurationException
- {
- return createCache(configFileName, true);
- }
-
- public Cache<K, V> createCache(String configFileName, boolean start) throws ConfigurationException
- {
- XmlConfigurationParser parser = new XmlConfigurationParser();
- Configuration c = parser.parseFile(configFileName);
- return createCache(c, start);
- }
-
- /**
- * This implementation clones the configuration passed in before using it.
- *
- * @param configuration to use
- * @return a cache
- * @throws ConfigurationException if there are problems with the cfg
- */
- public Cache<K, V> createCache(Configuration configuration) throws ConfigurationException
- {
- return createCache(configuration, true);
- }
-
- /**
- * This implementation clones the configuration passed in before using it.
- *
- * @param configuration to use
- * @param start whether to start the cache
- * @return a cache
- * @throws ConfigurationException if there are problems with the cfg
- */
- public Cache<K, V> createCache(Configuration configuration, boolean start) throws ConfigurationException
- {
- try
- {
- CacheImpl<K, V> cache = new CacheImpl<K, V>();
- cache.setConfiguration(configuration);
- if (start) cache.start();
- return cache;
- }
- catch (ConfigurationException ce)
- {
- throw ce;
- }
- catch (RuntimeException re)
- {
- throw re;
- }
- catch (Exception e)
- {
- throw new RuntimeException(e);
- }
- }
-}
Deleted: core/trunk/src-old/org/jboss/cache/Fqn.java
===================================================================
--- core/trunk/src-old/org/jboss/cache/Fqn.java 2007-08-14 19:09:32 UTC (rev 4251)
+++ core/trunk/src-old/org/jboss/cache/Fqn.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -1,518 +0,0 @@
-/*
- * JBoss, the OpenSource J2EE webOS
- *
- * Distributable under LGPL license.
- * See terms of license at gnu.org.
- */
-package org.jboss.cache;
-
-
-import net.jcip.annotations.Immutable;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
-import java.io.Externalizable;
-import java.io.IOException;
-import java.io.ObjectInput;
-import java.io.ObjectOutput;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-import java.util.StringTokenizer;
-
-/**
- * A Fully Qualified Name (Fqn) is a list of names (typically Strings but can be any Object),
- * which represent a path to a particular {@link Node} or sometimes a {@link Region} in a {@link Cache}.
- * <p/>
- * This name can be absolute (i.e., relative from the root node - {@link #ROOT}), or relative to any node in the cache. Reading the
- * documentation on each API call that makes use of {@link org.jboss.cache.Fqn}s will tell you whether the API expects a
- * relative or absolute Fqn.
- * <p/>
- * For instance, using this class to fetch a particular node might look like
- * this. (Here data on "Joe" is kept under the "Smith" surname node, under
- * the "people" tree.)
- * <pre>
- * Fqn<String> abc = Fqn.fromString("/people/Smith/Joe/");
- * Node joesmith = Cache.getRoot().getChild(abc);
- * </pre>
- * Alternatively, the same Fqn could be constructed using an array:
- * <pre>
- * Fqn<String> abc = new Fqn<String>(new String[] { "people", "Smith", "Joe" });
- * </pre>
- * This is a bit more efficient to construct.
- * <p/>
- * <p/>
- * Note that<br>
- * <p/>
- * <code>Fqn<String> f = new Fqn<String>("/a/b/c");</code>
- * <p/>
- * is <b>not</b> the same as
- * <p/>
- * <code>Fqn<String> f = Fqn.fromString("/a/b/c");</code>
- * <p/>
- * The former will result in a single Fqn, called "/a/b/c" which hangs directly under Fqn.ROOT.
- * <p/>
- * The latter will result in 3 Fqns, called "a", "b" and "c", where "c" is a child of "b", "b" is a child of "a", and "a" hangs off Fqn.ROOT.
- * <p/>
- * Another way to look at it is that the "/" separarator is only parsed when it forms
- * part of a String passed in to Fqn.fromString() and not otherwise.
- *
- * @version $Revision$
- */
- at Immutable
-public class Fqn<E> implements Cloneable, Externalizable, Comparable<Fqn>
-{
-
- /**
- * Separator between FQN elements.
- */
- public static final String SEPARATOR = "/";
- private static final long serialVersionUID = -5351930616956603651L;
- private List<E> elements;
- private transient int hash_code = 0;
-
- /**
- * Immutable root FQN.
- */
- public static final Fqn ROOT = new Fqn();
- private static Log log = LogFactory.getLog(Fqn.class);
- // a cached string representation of this Fqn, used by toString to it isn't calculated again every time.
- private String cachedStringRep;
-
- /**
- * Constructs a root Fqn
- */
- public Fqn()
- {
- elements = Collections.emptyList();
- }
-
- /**
- * Constructs a FQN from a list of names.
- *
- * @param names List of names
- */
- public Fqn(List<E> names)
- {
- // the list is unsafe - may be referenced externally
- this(names, false);
- }
-
- /**
- * If safe is false, Collections.unmodifiableList() is used to wrap the list passed in. This is an optimisation so
- * Fqn.fromString(), probably the most frequently used factory method, doesn't end up needing to use the unmodifiableList()
- * since it creates the list internally.
- *
- * @param names List of names
- * @param safe whether this list is referenced externally (safe = false) or not (safe = true).
- */
- protected Fqn(List<E> names, boolean safe)
- {
- if (names != null)
- {
- // if not safe make a defensive copy
- elements = safe ? names : new ArrayList<E>(names);
- }
- else
- {
- elements = Collections.emptyList();
- }
- }
-
-
- /**
- * Constructs a Fqn from an array of names.
- *
- * @param names Names that comprose this Fqn
- */
- public Fqn(E... names)
- {
- // safe - the list is created here.
- this(Arrays.asList(names), true);
- }
-
- /**
- * Constructs a Fqn from a base and relative Fqn.
- *
- * @param base parent Fqn
- * @param relative Sub-Fqn relative to the parent
- */
- public Fqn(Fqn<E> base, Fqn<E> relative)
- {
- this(base, relative.elements);
- }
-
- /**
- * Constructs a Fqn from a base and a list of relative names.
- *
- * @param base parent Fqn
- * @param relative List of elements that identify the child Fqn, relative to the parent
- */
- public Fqn(Fqn<E> base, List<E> relative)
- {
- List<E> elements = new ArrayList<E>(base.elements.size() + relative.size());
- elements.addAll(base.elements);
- elements.addAll(relative);
- this.elements = elements;
- }
-
- /**
- * Constructs a Fqn from a base and two relative names.
- *
- * @param base parent Fqn
- * @param childNames elements that denote the path to the Fqn, under the parent
- */
- public Fqn(Fqn<E> base, E... childNames)
- {
- List<E> elements = new ArrayList<E>(base.elements.size() + childNames.length);
- elements.addAll(base.elements);
- elements.addAll(Arrays.asList(childNames));
- this.elements = elements;
- }
-
- /**
- * Returns a new Fqn from a string, where the elements are deliminated by
- * one or more separator ({@link #SEPARATOR}) characters.<br><br>
- * Example use:<br>
- * <pre>
- * Fqn.fromString("/a/b/c/");
- * </pre><br>
- * is equivalent to:<br>
- * <pre>
- * new Fqn("a", "b", "c");
- * </pre><br>
- * but not<br>
- * <pre>
- * new Fqn("/a/b/c");
- * </pre>
- *
- * @param stringRepresentation String representation of the Fqn
- * @return an Fqn<String> constructed from the string representation passed in
- * @see #Fqn(Object[])
- */
- public static Fqn<String> fromString(String stringRepresentation)
- {
- if (stringRepresentation == null)
- {
- return Fqn.ROOT;
- }
- List<String> list = new ArrayList<String>();
- StringTokenizer tok = new StringTokenizer(stringRepresentation, SEPARATOR);
- while (tok.hasMoreTokens()) list.add(tok.nextToken());
- return new Fqn<String>(list, true);
- }
-
- /**
- * Obtains an ancestor of the current Fqn. Literally performs <code>elements.subList(0, generation)</code>
- * such that if
- * <code>
- * generation == Fqn.size()
- * </code>
- * then the return value is the Fqn itself (current generation), and if
- * <code>
- * generation == Fqn.size() - 1
- * </code>
- * then the return value is the same as
- * <code>
- * Fqn.getParent()
- * </code>
- * i.e., just one generation behind the current generation.
- * <code>
- * generation == 0
- * </code>
- * would return Fqn.ROOT.
- *
- * @param generation the generation of the ancestor to retrieve
- * @return an ancestor of the current Fqn
- */
- public Fqn<E> getAncestor(int generation)
- {
- if (generation == 0) return Fqn.ROOT;
- return getSubFqn(0, generation);
- }
-
- /**
- * Obtains a sub-Fqn from the given Fqn. Literally performs <code>elements.subList(startIndex, endIndex)</code>
- */
- public Fqn<E> getSubFqn(int startIndex, int endIndex)
- {
- return new Fqn<E>(elements.subList(startIndex, endIndex));
- }
-
- /**
- * @return the number of elements in the Fqn. The root node contains zero.
- */
- public int size()
- {
- return elements.size();
- }
-
- /**
- * @param n index of the element to return
- * @return Returns the nth element in the Fqn.
- */
- public E get(int n)
- {
- return elements.get(n);
- }
-
- /**
- * @return the last element in the Fqn.
- * @see #getLastElementAsString
- */
- public E getLastElement()
- {
- if (isRoot()) return null;
- return elements.get(elements.size() - 1);
- }
-
- /**
- * @param element element to find
- * @return true if the Fqn contains this element, false otherwise.
- */
- public boolean hasElement(E element)
- {
- return elements.lastIndexOf(element) != -1;
- }
-
- /**
- * Clones the Fqn.
- */
- public Fqn<E> clone() throws CloneNotSupportedException
- {
- try
- {
- return (Fqn<E>) super.clone();
- }
- catch (CloneNotSupportedException e)
- {
- log.error("Unable to clone Fqn " + this, e);
- return null;
- }
- }
-
- /**
- * Returns true if obj is a Fqn with the same elements.
- */
- public boolean equals(Object obj)
- {
- if (this == obj)
- {
- return true;
- }
- if (!(obj instanceof Fqn))
- {
- return false;
- }
- Fqn other = (Fqn) obj;
- return elements.equals(other.elements);
- }
-
- /**
- * Returns a hash code with Fqn elements.
- */
- public int hashCode()
- {
- if (hash_code == 0)
- {
- hash_code = _hashCode();
- }
- return hash_code;
- }
-
- /**
- * Returns this Fqn as a string, prefixing the first element with a {@link Fqn#SEPARATOR} and
- * joining each subsequent element with a {@link Fqn#SEPARATOR}.
- * If this is the root Fqn, returns {@link Fqn#SEPARATOR}.
- * Example:
- * <pre>
- * new Fqn(new Object[] { "a", "b", "c" }).toString(); // "/a/b/c"
- * Fqn.ROOT.toString(); // "/"
- * </pre>
- */
- public String toString()
- {
- if (cachedStringRep == null)
- {
- if (isRoot())
- {
- cachedStringRep = SEPARATOR;
- }
- else
- {
- StringBuffer sb = new StringBuffer();
- for (E element : elements)
- {
- sb.append(SEPARATOR).append(element);
- }
- cachedStringRep = sb.toString();
- }
- }
- return cachedStringRep;
- }
-
- public void writeExternal(ObjectOutput out) throws IOException
- {
- out.writeShort(elements.size());
- for (E element : elements)
- {
- out.writeObject(element);
- }
- }
-
- public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException
- {
- short length = in.readShort();
- this.elements = new ArrayList<E>(length);
- for (int i = 0; i < length; i++)
- {
- elements.add((E) in.readObject());
- }
- }
-
-
- /**
- * Returns true if this Fqn is child of parentFqn.
- * Example usage:
- * <pre>
- * Fqn<String> f1 = Fqn.fromString("/a/b");
- * Fqn<String> f2 = Fqn.fromString("/a/b/c");
- * assertTrue(f1.isChildOf(f2));
- * assertFalse(f1.isChildOf(f1));
- * assertFalse(f2.isChildOf(f1));
- * </pre>
- *
- * @param parentFqn candidate parent to test against
- * @return true if the target is a child of parentFqn
- */
- public boolean isChildOf(Fqn<E> parentFqn)
- {
- return parentFqn.elements.size() != elements.size() && isChildOrEquals(parentFqn);
- }
-
- /**
- * Returns true if this Fqn is equals or the child of parentFqn.
- * Example usage:
- * <pre>
- * Fqn<String> f1 = Fqn.fromString("/a/b");
- * Fqn<String> f2 = Fqn.fromString("/a/b/c");
- * assertTrue(f1.isChildOrEquals(f2));
- * assertTrue(f1.isChildOrEquals(f1));
- * assertFalse(f2.isChildOrEquals(f1));
- * </pre>
- *
- * @param parentFqn candidate parent to test against
- * @return true if this Fqn is equals or the child of parentFqn.
- */
- public boolean isChildOrEquals(Fqn<E> parentFqn)
- {
- List<E> parentList = parentFqn.elements;
- if (parentList.size() > elements.size())
- {
- return false;
- }
- for (int i = parentList.size() - 1; i >= 0; i--)
- {
- if (!parentList.get(i).equals(elements.get(i)))
- {
- return false;
- }
- }
- return true;
- }
-
- /**
- * Calculates a hash code by summing the hash code of all elements.
- *
- * @return a cached hashcode
- */
- private int _hashCode()
- {
- int hashCode = 0;
- int count = 1;
- Object o;
- for (E element : elements)
- {
- o = element;
- hashCode += (o == null) ? 0 : o.hashCode() * count++;
- }
- if (hashCode == 0)// fix degenerate case
- {
- hashCode = 0xFEED;
- }
- return hashCode;
- }
-
- /**
- * Returns the parent of this Fqn.
- * The parent of the root node is {@link #ROOT}.
- * Examples:
- * <pre>
- * Fqn<String> f1 = Fqn.fromString("/a");
- * Fqn<String> f2 = Fqn.fromString("/a/b");
- * assertEquals(f1, f2.getParent());
- * assertEquals(Fqn.ROOT, f1.getParent().getParent());
- * assertEquals(Fqn.ROOT, Fqn.ROOT.getParent());
- * </pre>
- *
- * @return the parent Fqn
- */
- public Fqn<E> getParent()
- {
- switch (elements.size())
- {
- case 0:
- case 1:
- return ROOT;
- default:
- return new Fqn<E>(elements.subList(0, elements.size() - 1));
- }
- }
-
- /**
- * Returns true if this is a root Fqn.
- *
- * @return true if the Fqn is Fqn.ROOT.
- */
- public boolean isRoot()
- {
- return elements.isEmpty();
- }
-
- /**
- * If this is the root, returns {@link Fqn#SEPARATOR}.
- *
- * @return a String representation of the last element that makes up this Fqn.
- */
- public String getLastElementAsString()
- {
- if (isRoot())
- {
- return SEPARATOR;
- }
- else
- {
- return String.valueOf(getLastElement());
- }
- }
-
- /**
- * Peeks into the elements that build up this Fqn. The list returned is
- * read-only, to maintain the immutable nature of Fqn.
- *
- * @return an unmodifiable list
- */
- public List<E> peekElements()
- {
- return elements;
- }
-
- /**
- * Compares this Fqn to another using {@link FqnComparator}.
- */
- public int compareTo(Fqn Fqn)
- {
- return FqnComparator.INSTANCE.compare(this, Fqn);
- }
-}
\ No newline at end of file
Deleted: core/trunk/src-old/org/jboss/cache/FqnComparator.java
===================================================================
--- core/trunk/src-old/org/jboss/cache/FqnComparator.java 2007-08-14 19:09:32 UTC (rev 4251)
+++ core/trunk/src-old/org/jboss/cache/FqnComparator.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -1,106 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source
- *
- * Distributable under LGPL license.
- * See terms of license at gnu.org.
- */
-package org.jboss.cache;
-
-import net.jcip.annotations.Immutable;
-
-import java.util.Comparator;
-
-/**
- * Compares the order of two FQN.
- * Sorts by name, then by depth, e.g.
- * <pre>
- * aaa/bbb
- * xxx
- * xxx/ccc
- * </pre>
- *
- * @author Manik Surtani (<a href="mailto:manik at jboss.org">manik at jboss.org</a>)
- * @author Steve Woodcock (<a href="mailto:stevew at jofti.com">stevew at jofti.com</a>)
- */
- at Immutable
-public class FqnComparator implements Comparator<Fqn>
-{
- public static final FqnComparator INSTANCE = new FqnComparator();
-
- /**
- * Sorts by name, then depth.
- */
- public FqnComparator()
- {
- }
-
- /**
- * Returns -1 if the first comes before; 0 if they are the same; 1 if the
- * second Fqn comes before. <code>null</code> always comes first.
- */
- public int compare(Fqn fqn1, Fqn fqn2)
- {
- int s1 = fqn1.size();
- int s2 = fqn2.size();
-
- if (s1 == 0)
- {
- return (s2 == 0) ? 0 : -1;
- }
-
- if (s2 == 0)
- {
- return 1;
- }
-
- int size = Math.min(s1, s2);
-
- for (int i = 0; i < size; i++)
- {
- Object e1 = fqn1.get(i);
- Object e2 = fqn2.get(i);
- if (e1 == e2)
- {
- continue;
- }
- if (e1 == null)
- {
- return 0;
- }
- if (e2 == null)
- {
- return 1;
- }
- if (!e1.equals(e2))
- {
- int c = compareElements(e1, e2);
- if (c != 0)
- {
- return c;
- }
- }
- }
-
- return s1 - s2;
- }
-
- /**
- * Compares two Fqn elements.
- * If e1 and e2 are the same class and e1 implements Comparable,
- * returns e1.compareTo(e2).
- * Otherwise, returns e1.toString().compareTo(e2.toString()).
- */
- private int compareElements(Object e1, Object e2)
- {
- if (e1.getClass() == e2.getClass() && e1 instanceof Comparable)
- {
- return ((Comparable) e1).compareTo(e2);
- }
- else
- {
- return e1.toString().compareTo(e2.toString());
- }
- }
-
-
-}
Deleted: core/trunk/src-old/org/jboss/cache/InvocationContext.java
===================================================================
--- core/trunk/src-old/org/jboss/cache/InvocationContext.java 2007-08-14 19:09:32 UTC (rev 4251)
+++ core/trunk/src-old/org/jboss/cache/InvocationContext.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -1,257 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source
- *
- * Distributable under LGPL license.
- * See terms of license at gnu.org.
- */
-package org.jboss.cache;
-
-import org.jboss.cache.config.Option;
-import org.jboss.cache.marshall.MethodCall;
-import org.jboss.cache.transaction.GlobalTransaction;
-
-import javax.transaction.Transaction;
-
-/**
- * This context holds information specific to a method invocation.
- *
- * @author <a href="mailto:manik at jboss.org">Manik Surtani (manik at jboss.org)</a>
- */
-public class InvocationContext implements Cloneable
-{
- private Transaction transaction;
- private GlobalTransaction globalTransaction;
- private Option optionOverrides;
- // defaults to true.
- private boolean originLocal = true;
- private boolean txHasMods;
- private boolean localRollbackOnly;
- private MethodCall methodCall;
-
- InvocationContext()
- {
- }
-
- public void setLocalRollbackOnly(boolean localRollbackOnly)
- {
- this.localRollbackOnly = localRollbackOnly;
- }
-
-
- /**
- * Retrieves the transaction associated with this invocation
- *
- * @return The transaction associated with this invocation
- */
- public Transaction getTransaction()
- {
- return transaction;
- }
-
- /**
- * Sets the transaction associated with this invocation
- *
- * @param transaction
- */
- public void setTransaction(Transaction transaction)
- {
- this.transaction = transaction;
- }
-
- /**
- * Retrieves the global transaction associated with this invocation
- *
- * @return the global transaction associated with this invocation
- */
- public GlobalTransaction getGlobalTransaction()
- {
- return globalTransaction;
- }
-
- /**
- * Sets the global transaction associated with this invocation
- *
- * @param globalTransaction
- */
- public void setGlobalTransaction(GlobalTransaction globalTransaction)
- {
- this.globalTransaction = globalTransaction;
- }
-
- /**
- * Retrieves the option overrides associated with this invocation
- *
- * @return the option overrides associated with this invocation
- */
- public Option getOptionOverrides()
- {
- if (optionOverrides == null)
- {
- optionOverrides = new Option();
- }
- return optionOverrides;
- }
-
- /**
- * Sets the option overrides associated with this invocation
- *
- * @param optionOverrides
- */
- public void setOptionOverrides(Option optionOverrides)
- {
- this.optionOverrides = optionOverrides;
- }
-
- /**
- * Tests if this invocation originated locally or from a remote cache.
- *
- * @return true if the invocation originated locally.
- */
- public boolean isOriginLocal()
- {
- return originLocal;
- }
-
- /**
- * If set to true, the invocation is assumed to have originated locally. If set to false,
- * assumed to have originated from a remote cache.
- *
- * @param originLocal
- */
- public void setOriginLocal(boolean originLocal)
- {
- this.originLocal = originLocal;
- }
-
- public String toString()
- {
- return "InvocationContext{" +
- "methodCall=" + methodCall +
- "transaction=" + transaction +
- ", globalTransaction=" + globalTransaction +
- ", optionOverrides=" + optionOverrides +
- ", originLocal=" + originLocal +
- ", txHasMods=" + txHasMods +
- '}';
- }
-
- public boolean isTxHasMods()
- {
- return txHasMods;
- }
-
- public void setTxHasMods(boolean b)
- {
- txHasMods = b;
- }
-
- public boolean isLocalRollbackOnly()
- {
- return localRollbackOnly;
- }
-
- /**
- * Resets this to the defaults used when constructing an invocation context object
- */
- public void reset()
- {
- transaction = null;
- globalTransaction = null;
- optionOverrides = null;
- originLocal = true;
- txHasMods = false;
- }
-
- public InvocationContext clone() throws CloneNotSupportedException
- {
- InvocationContext clone = (InvocationContext) super.clone();
- clone.setOptionOverrides(getOptionOverrides().clone());
- return clone;
- }
-
- /**
- * Sets the state of the InvocationContext based on the template context passed in
- *
- * @param template
- */
- public void setState(InvocationContext template)
- {
- if (template == null)
- {
- throw new NullPointerException("Template InvocationContext passed in to InvocationContext.setState() passed in is null");
- }
-
- this.setGlobalTransaction(template.getGlobalTransaction());
- this.setLocalRollbackOnly(template.isLocalRollbackOnly());
- this.setOptionOverrides(template.getOptionOverrides());
- this.setOriginLocal(template.isOriginLocal());
- this.setTransaction(template.getTransaction());
- this.setTxHasMods(template.isTxHasMods());
- }
-
- public boolean equals(Object o)
- {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
-
- final InvocationContext that = (InvocationContext) o;
-
- if (localRollbackOnly != that.localRollbackOnly) return false;
- if (originLocal != that.originLocal) return false;
- if (txHasMods != that.txHasMods) return false;
- if (globalTransaction != null ? !globalTransaction.equals(that.globalTransaction) : that.globalTransaction != null)
- {
- return false;
- }
- if (optionOverrides != null ? !optionOverrides.equals(that.optionOverrides) : that.optionOverrides != null)
- {
- return false;
- }
- if (transaction != null ? !transaction.equals(that.transaction) : that.transaction != null) return false;
-
- return true;
- }
-
- public int hashCode()
- {
- int result;
- result = (transaction != null ? transaction.hashCode() : 0);
- result = 29 * result + (globalTransaction != null ? globalTransaction.hashCode() : 0);
- result = 29 * result + (optionOverrides != null ? optionOverrides.hashCode() : 0);
- result = 29 * result + (originLocal ? 1 : 0);
- result = 29 * result + (txHasMods ? 1 : 0);
- result = 29 * result + (localRollbackOnly ? 1 : 0);
- return result;
- }
-
- /**
- * @return the method call associated with this invocation
- */
- public MethodCall getMethodCall()
- {
- return methodCall;
- }
-
- /**
- * Sets the method call associated with this invocation.
- *
- * @param methodCall methodcall to set
- */
- public void setMethodCall(MethodCall methodCall)
- {
- this.methodCall = methodCall;
- }
-
- /**
- * Factory method that creates a context with a given method call.
- *
- * @param methodCall methodcall to use
- * @return invocation context
- */
- public static InvocationContext fromMethodCall(MethodCall methodCall)
- {
- InvocationContext ctx = new InvocationContext();
- ctx.methodCall = methodCall;
- return ctx;
- }
-}
Deleted: core/trunk/src-old/org/jboss/cache/Modification.java
===================================================================
--- core/trunk/src-old/org/jboss/cache/Modification.java 2007-08-14 19:09:32 UTC (rev 4251)
+++ core/trunk/src-old/org/jboss/cache/Modification.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -1,290 +0,0 @@
-/*
- * JBoss, the OpenSource J2EE webOS
- *
- * Distributable under LGPL license.
- * See terms of license at gnu.org.
- */
-package org.jboss.cache;
-
-
-import java.io.Externalizable;
-import java.io.IOException;
-import java.io.ObjectInput;
-import java.io.ObjectOutput;
-import java.util.Map;
-
-
-/**
- * Represents a modification in the cache. Contains the nature of the modification
- * (e.g. PUT, REMOVE), the fqn of the node, the new value and the previous value.
- * A list of modifications will be sent to all nodes in a cluster when a transaction
- * has been committed (PREPARE phase). A Modification is also used to roll back changes,
- * e.g. since we know the previous value, we can reconstruct the previous state by
- * applying the changes in a modification listin reverse order.
- *
- * @author <a href="mailto:bela at jboss.org">Bela Ban</a> Apr 12, 2003
- * @version $Revision$
- */
-public class Modification implements Externalizable
-{
-
- private static final long serialVersionUID = 7463314130283897197L;
-
- public enum ModificationType
- {
- PUT_KEY_VALUE,
- PUT_DATA,
- PUT_DATA_ERASE,
- REMOVE_NODE,
- REMOVE_KEY_VALUE,
- REMOVE_DATA,
- MOVE,
- UNKNOWN
- }
-
- private ModificationType type = ModificationType.UNKNOWN;
- private Fqn fqn = null;
- private Fqn fqn2 = null;
- private Object key = null;
- private Object value = null;
- private Object old_value = null;
- private Map data = null;
-
- /**
- * Constructs a new modification.
- */
- public Modification()
- {
- }
-
- /**
- * Constructs a new modification with details.
- */
- public Modification(ModificationType type, Fqn fqn, Object key, Object value)
- {
- this.type = type;
- this.fqn = fqn;
- this.key = key;
- this.value = value;
- }
-
- /**
- * Constructs a new modification with key.
- */
- public Modification(ModificationType type, Fqn fqn, Object key)
- {
- this.type = type;
- this.fqn = fqn;
- this.key = key;
- }
-
- /**
- * Constructs a new modification with data map.
- */
- public Modification(ModificationType type, Fqn fqn, Map data)
- {
- this.type = type;
- this.fqn = fqn;
- this.data = data;
- }
-
- /**
- * Constructs a new modification with fqn only.
- */
- public Modification(ModificationType type, Fqn fqn)
- {
- this.type = type;
- this.fqn = fqn;
- }
-
- /**
- * Constructs a new modification with fqn only.
- */
- public Modification(ModificationType type, Fqn fqn1, Fqn fqn2)
- {
- this.type = type;
- this.fqn = fqn1;
- this.fqn2 = fqn2;
- }
-
-
- /**
- * Returns the type of modification.
- */
- public ModificationType getType()
- {
- return type;
- }
-
- /**
- * Sets the type of modification.
- */
- public void setType(ModificationType type)
- {
- this.type = type;
- }
-
- /**
- * Returns the modification fqn.
- */
- public Fqn getFqn()
- {
- return fqn;
- }
-
- /**
- * Sets the modification fqn.
- */
- public void setFqn(Fqn fqn)
- {
- this.fqn = fqn;
- }
-
- public void setFqn2(Fqn fqn2)
- {
- this.fqn2 = fqn2;
- }
-
- public Fqn getFqn2()
- {
- return fqn2;
- }
-
- /**
- * Returns the modification key.
- */
- public Object getKey()
- {
- return key;
- }
-
- /**
- * Sets the modification key.
- */
- public void setKey(Object key)
- {
- this.key = key;
- }
-
- /**
- * Returns the modification value.
- */
- public Object getValue()
- {
- return value;
- }
-
- /**
- * Sets the modification value.
- */
- public void setValue(Object value)
- {
- this.value = value;
- }
-
- /**
- * Returns the <i>post</i> modification old value.
- */
- public Object getOldValue()
- {
- return old_value;
- }
-
- /**
- * Sets the <i>post</i> modification old value.
- */
- public void setOldValue(Object old_value)
- {
- this.old_value = old_value;
- }
-
- /**
- * Returns the modification Map set.
- */
- public Map getData()
- {
- return data;
- }
-
- /**
- * Sets the modification Map set.
- */
- public void setData(Map data)
- {
- this.data = data;
- }
-
- /**
- * Writes data to an external stream.
- */
- public void writeExternal(ObjectOutput out) throws IOException
- {
- out.writeObject(type);
-
- out.writeBoolean(fqn != null);
- if (fqn != null)
- {
- fqn.writeExternal(out);
- }
-
- out.writeObject(key);
- out.writeObject(value);
- out.writeObject(old_value);
-
- out.writeBoolean(data != null);
- if (data != null)
- {
- out.writeObject(data);
- }
- }
-
- /**
- * Reads data from an external stream.
- */
- public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException
- {
- type = (ModificationType) in.readObject();
-
- if (in.readBoolean())
- {
- fqn = new Fqn();
- fqn.readExternal(in);
- }
-
- key = in.readObject();
- value = in.readObject();
- old_value = in.readObject();
-
- if (in.readBoolean())
- {
- data = (Map) in.readObject();
- }
- }
-
- /**
- * Returns debug information about this modification.
- */
- public String toString()
- {
- StringBuffer sb = new StringBuffer();
- sb.append(type.toString()).append(": ").append(fqn);
- if (key != null)
- {
- sb.append("\nkey=").append(key);
- }
- if (value != null)
- {
- sb.append("\nvalue=").append(value);
- }
- if (old_value != null)
- {
- sb.append("\nold_value=").append(old_value);
- }
- if (data != null)
- {
- sb.append("\ndata=").append(data);
- }
- return sb.toString();
- }
-
-}
Deleted: core/trunk/src-old/org/jboss/cache/Node.java
===================================================================
--- core/trunk/src-old/org/jboss/cache/Node.java 2007-08-14 19:09:32 UTC (rev 4251)
+++ core/trunk/src-old/org/jboss/cache/Node.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -1,280 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source
- *
- * Distributable under LGPL license.
- * See terms of license at gnu.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.
- * <p/>
- * 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.
- * <p/>
- * 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}.)
- * <p/>
- * 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.
- * <p/>
- *
- * @author <a href="mailto:manik at jboss.org">Manik Surtani (manik at jboss.org)</a>
- * @see Cache
- * @since 2.0.0
- */
- at ThreadSafe
-public interface Node<K, V>
-{
- /**
- * Returns the parent node.
- * If this is the root node, this method returns <code>null</code>.
- *
- * @return the parent node, or null if this is the root node
- */
- Node<K, V> 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<Node<K, V>> 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<Object> 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<K, V> 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<K> 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.
- * <p/>
- * If the child exists returns the child node anyway. Guaranteed to return a non-null node.
- * <p/>
- * The {@link Fqn} passed in is relative to the current node. The new child node will have an absolute fqn
- * calculated as follows: <pre>new Fqn(getFqn(), f)</pre>. 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<K, V> addChild(Fqn<?> f);
-
- /**
- * Removes a child node specified by the given relative {@link Fqn}.
- * <p/>
- * 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<K, V> getChild(Fqn<?> f);
-
- /**
- * @param name name of the child
- * @return a direct child of the current node.
- */
- Node<K, V> 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.
- * <p/>
- * Equivalent to calling
- * <pre>
- * if (!node.getKeys().contains(key))
- * return node.put(key, value);
- * else
- * return node.get(key);
- * </pre>
- * <p/>
- * 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
- * <pre>
- * if ((node.getKeys().contains(key))
- * {
- * return node.put(key, value);
- * }
- * else
- * return null;
- * </pre>
- * <p/>
- * 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 <tt>null</tt>
- * 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
- * <pre>
- * if (node.get(key).equals(oldValue))
- * {
- * node.putAll(key, newValue);
- * return true;
- * }
- * else
- * return false;
- * </pre>
- * <p/>
- * 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:
- * <pre>
- * Node node;
- * for (Map.Entry me : map.entrySet())
- * node.put(me.getKey(), me.getValue());
- * </pre>
- *
- * @param map map to copy from
- */
- void putAll(Map<K, 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<K, V> map);
-
-
- /**
- * Returns the value to which this node maps the specified key.
- * Returns <code>null</code> 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 <code>null</code> 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 <code>null</code> 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 <code>null</code>
- * 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 evicted, for example,
- * in which case it should be looked up again from the cache.
- *
- * @return true if the node is valid.
- */
- boolean isValid();
-
-}
Deleted: core/trunk/src-old/org/jboss/cache/NodeFactory.java
===================================================================
--- core/trunk/src-old/org/jboss/cache/NodeFactory.java 2007-08-14 19:09:32 UTC (rev 4251)
+++ core/trunk/src-old/org/jboss/cache/NodeFactory.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -1,97 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source
- *
- * Distributable under LGPL license.
- * See terms of license at gnu.org.
- */
-package org.jboss.cache;
-
-import org.jboss.cache.optimistic.TransactionWorkspace;
-import org.jboss.cache.optimistic.WorkspaceNode;
-import org.jboss.cache.optimistic.WorkspaceNodeImpl;
-
-import java.util.Map;
-
-/**
- * Generates new nodes based on the {@link CacheSPI} configuration.
- *
- * @author <a href="mailto:manik at jboss.org">Manik Surtani (manik at jboss.org)</a>
- */
-public class NodeFactory<K, V>
-{
- public enum NodeType
- {
- UNVERSIONED_NODE, VERSIONED_NODE, WORKSPACE_NODE
- }
-
- private CacheSPI<K, V> cache;
- private boolean optimistic;
-
- /**
- * Constructs an instance of the factory
- */
- public NodeFactory(CacheSPI<K, V> cache)
- {
- this.cache = cache;
- init();
- }
-
- /**
- * Initialises the node factory with the configuration from the cache.
- */
- public void init()
- {
- optimistic = cache.getConfiguration().isNodeLockingOptimistic();
- }
-
-
- /**
- * Creates a new {@link Node} instance.
- *
- * @param childName the new node's name
- * @param fqn the new node's Fqn
- * @param parent the new node's parent
- * @param data the new node's attribute map
- * @param mapSafe <code>true</code> if param <code>data</code> can safely
- * be directly assigned to the new node's data field;
- * <code>false</code> if param <code>data</code>'s contents
- * should be copied into the new node's data field.
- * @return the new node
- */
- public NodeSPI<K, V> createDataNode(Object childName, Fqn fqn, NodeSPI<K, V> parent, Map<K, V> data, boolean mapSafe)
- {
- NodeSPI<K, V> n = optimistic ? new VersionedNode<K, V>(fqn, parent, data, cache) : new UnversionedNode<K, V>(childName, fqn, data, mapSafe, cache);
- // always assume that new nodes do not have data loaded
- n.setDataLoaded(false);
- return n;
- }
-
- public Node<K, V> createNode(Object childName, Node<K, V> parent, Map<K, V> data)
- {
- return createNodeOfType(parent, childName, parent, data);
- }
-
- public Node<K, V> createNodeOfType(Node<K, V> template, Object childName, Node<K, V> parent, Map<K, V> data)
- {
- if (template instanceof WorkspaceNode)
- {
- NodeSPI<K, V> dataNodeParent = ((WorkspaceNode<K, V>) parent).getNode();
- TransactionWorkspace workspace = ((WorkspaceNode) template).getTransactionWorkspace();
- return createWorkspaceNode(dataNodeParent, workspace);
- }
-
- // not a workspace node.
- return createDataNode(childName, new Fqn(parent.getFqn(), childName), (NodeSPI<K, V>) parent, data, false);
- }
-
- public WorkspaceNode<K, V> createWorkspaceNode(NodeSPI<K, V> dataNode, TransactionWorkspace workspace)
- {
- return new WorkspaceNodeImpl<K, V>(dataNode, workspace);
- }
-
- public NodeSPI<K, V> createRootDataNode()
- {
- return createDataNode(null, Fqn.ROOT, null, null, false);
- }
-
-}
Deleted: core/trunk/src-old/org/jboss/cache/NodeNotExistsException.java
===================================================================
--- core/trunk/src-old/org/jboss/cache/NodeNotExistsException.java 2007-08-14 19:09:32 UTC (rev 4251)
+++ core/trunk/src-old/org/jboss/cache/NodeNotExistsException.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -1,42 +0,0 @@
-// $Id$
-
-/*
- * JBoss, the OpenSource J2EE webOS
- *
- * Distributable under LGPL license.
- * See terms of license at gnu.org.
- */
-
-package org.jboss.cache;
-
-
-
-
-/**
- * Thrown when an operation is attempted on a non-existing node in the cache
- *
- * @author <a href="mailto:bela at jboss.com">Bela Ban</a>.
- * @version $Id$
- */
-
-public class NodeNotExistsException extends CacheException {
-
- private static final long serialVersionUID = 779376138690777440L;
-
- public NodeNotExistsException() {
- super();
- }
-
-
- public NodeNotExistsException(String msg) {
- super(msg);
- }
-
-
- public NodeNotExistsException(String msg, Throwable cause) {
- super(msg, cause);
- }
-
-
-
-}
Deleted: core/trunk/src-old/org/jboss/cache/NodeSPI.java
===================================================================
--- core/trunk/src-old/org/jboss/cache/NodeSPI.java 2007-08-14 19:09:32 UTC (rev 4251)
+++ core/trunk/src-old/org/jboss/cache/NodeSPI.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -1,440 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source
- *
- * Distributable under LGPL license.
- * See terms of license at gnu.org.
- */
-package org.jboss.cache;
-
-import net.jcip.annotations.NotThreadSafe;
-import org.jboss.cache.lock.NodeLock;
-import org.jboss.cache.optimistic.DataVersion;
-import org.jboss.cache.transaction.GlobalTransaction;
-
-import java.util.Map;
-import java.util.Set;
-
-/**
- * A more detailed interface to {@link Node}, which is used when writing plugins for or extending JBoss Cache. References are usually
- * obtained by calling methods on {@link org.jboss.cache.CacheSPI}.
- * <p/>
- * <B><I>You should NEVER attempt to directly cast a {@link Node} instance to this interface. In future, the implementation may not allow it.</I></B>
- * <p/>
- * This interface contains overridden method signatures of some methods from {@link Node}, overridden to ensure return
- * types of {@link Node} are replaced with {@link NodeSPI}.
- * <p/>
- * <b><i>An important note</i></b> on the xxxDirect() methods below. These methods are counterparts to similarly named
- * methods in {@link Node} - e.g., {@link NodeSPI#getDirect(Object)} is a direct access counterpart to {@link Node#get(Object)},
- * the difference being that:
- * <p/>
- * <ul>
- * <li>{@link Node#get(Object)} - Passes the call up the interceptor stack, applies all aspects including node locking, cache loading, passivation, etc etc.</li>
- * <li>{@link NodeSPI#getDirect(Object)} - directly works on the underlying data in the node.</li>
- * </ul>
- * <p/>
- * The big difference with the direct access methods are that it is the onus of the caller to ensure proper locks are obtained
- * prior to the call. A proper call should have gone through a locking-capable interceptor first and based on the cache
- * configuration's locking policy, an appropriate lock should be obtained prior to the call. These direct access methods will
- * throw {@link org.jboss.cache.lock.LockingException}s if appropriate locks haven't been obtained by the caller.
- * <p/>
- * It is important to node that the direct <b>read</b> methods, such as getDataDirect(), return unmodifiable collections.
- * In addition to being unmodifiable, they are also defensively copied from the underlying data map to ensure view consistency.
- * <p/>
- *
- * @author <a href="mailto:manik at jboss.org">Manik Surtani (manik at jboss.org)</a>
- * @see Node
- * @see org.jboss.cache.CacheSPI
- * @since 2.0.0
- */
- at NotThreadSafe
-public interface NodeSPI<K, V> extends Node<K, V>
-{
- /**
- * Returns true if the children of this node were loaded from a cache loader.
- *
- * @return true if the children of this node were loaded from a cache loader.
- */
- boolean isChildrenLoaded();
-
- /**
- * Sets if the children of this node were loaded from a cache loader.
- *
- * @param loaded true if loaded, false otherwise
- */
- void setChildrenLoaded(boolean loaded);
-
- /**
- * Returns true if the data was loaded from the cache loader.
- *
- * @return true if the data was loaded from the cache loader.
- */
- public boolean isDataLoaded();
-
- /**
- * Sets if the data was loaded from the cache loader.
- *
- * @param dataLoaded true if loaded, false otherwise
- */
- public void setDataLoaded(boolean dataLoaded);
-
- /**
- * Returns a map to access the raw children.
- * This method may return a null if the node does not have any children. It is important to note that this method
- * returns a direct reference to the underlying child map and is intended for internal use only. Incorrect use
- * may result in very inconsistent state of the cache.
- *
- * @return Map, keyed by child name, values Nodes.
- */
- Map<Object, Node<K, V>> getChildrenMapDirect();
-
- /**
- * Sets the node's children explictly.
- * This method will remove all children currently associated with this node and add all the children passed in.
- *
- * @param children cannot be null
- */
- void setChildrenMapDirect(Map<Object, Node<K, V>> children);
-
- /**
- * Returns an existing child or creates a new one using a global transaction.
- *
- * @param name name of child to create
- * @param tx transaction under which to create child
- * @return newly created node
- */
- NodeSPI<K, V> getOrCreateChild(Object name, GlobalTransaction tx);
-
- /**
- * Returns a lock for this node.
- *
- * @return node lock
- */
- NodeLock getLock();
-
- /**
- * Sets the FQN of this node and resets the names of all children as well.
- *
- * @param f fqn to set
- */
- void setFqn(Fqn<?> f);
-
- /**
- * Returns true if the instance has been deleted in the current transaction.
- *
- * @return true if the instance has been deleted in the current transaction.
- */
- boolean isDeleted();
-
- /**
- * Marks the node as being deleted (or not) in the current transaction. This is not recursive, child nodes are not affected.
- *
- * @param marker true if the node has been deleted, false if not.
- */
- void markAsDeleted(boolean marker);
-
- /**
- * Same as {@link #markAsDeleted(boolean)} except that the option to recurse into children is provided.
- *
- * @param marker true if the node has been deleted, false if not.
- * @param recursive if true, child nodes (and their children) are marked as well.
- */
- void markAsDeleted(boolean marker, boolean recursive);
-
- /**
- * Adds or replaces a child by name.
- *
- * @param nodeName child node name (not an FQN)
- * @param nodeToAdd child node
- */
- void addChild(Object nodeName, Node<K, V> nodeToAdd);
-
- /**
- * Prints details of this node to the StringBuffer passed in.
- *
- * @param sb StringBuffer to print to
- * @param indent depth of this node in the tree. Used to indent details by prepending spaces.
- */
- void printDetails(StringBuffer sb, int indent);
-
- /**
- * Prints basic information of this node to the StringBuffer passed in.
- *
- * @param sb StringBuffer to print to
- * @param indent depth of this node in the tree. Used to indent details by prepending spaces.
- */
-
- void print(StringBuffer sb, int indent);
-
- // versioning
- /**
- * Sets the data version of this node if versioning is supported.
- *
- * @param version data version to apply
- * @throws UnsupportedOperationException if versioning is not supported
- */
- void setVersion(DataVersion version);
-
- /**
- * Returns the data version of this node if versioning is supported.
- *
- * @return data version
- * @throws UnsupportedOperationException if versioning is not supported
- */
- DataVersion getVersion();
-
-
- // ------- these XXXDirect() methods work directly on the node and bypass the interceptor chain.
- /**
- * Functionally the same as {@link #getChildren()} except that it operates directly on the node and bypasses the
- * interceptor chain.
- * <p/>
- * The caller needs to ensure a proper lock has been obtained prior to calling this method, otherwise a
- * {@link org.jboss.cache.lock.LockingException} will be thrown.
- * <p/>
- *
- * @return set of child nodes.
- * @see #getChildren()
- */
- Set<NodeSPI<K, V>> getChildrenDirect();
-
- /**
- * Directly removes all children for this node.
- * The only direct method that does not have a non-direct counterpart.
- */
- void removeChildrenDirect();
-
- /**
- * Retrieves children (directly), optionally including any marked as deleted nodes.
- * <p/>
- * The caller needs to ensure a proper lock has been obtained prior to calling this method.
- *
- * @param includeMarkedAsDeleted if true, the returned set will include nodes marked as deleted
- * @return a set of nodes
- * @throws org.jboss.cache.lock.LockingException
- * if locking was not obtained
- */
- Set<NodeSPI<K, V>> getChildrenDirect(boolean includeMarkedAsDeleted);
-
- /**
- * Retrives a child directly by name.
- * Functionally the same as {@link #getChild(Object)} except that it bypasses the
- * interceptor chain.
- * <p/>
- * The caller needs to ensure a proper lock has been obtained prior to calling this method.
- *
- * @param childName name of child
- * @return child node
- * @throws org.jboss.cache.lock.LockingException
- * if locking was not obtained
- * @see #getChild(Object)
- */
- NodeSPI<K, V> getChildDirect(Object childName);
-
- /**
- * Adds a child directly to a Node.
- * Functionally the same as {@link #addChild(Fqn)} except that it bypasses the
- * interceptor chain.
- * <p/>
- * The caller needs to ensure a proper lock has been obtained prior to calling this method.
- *
- * @param childName name of child
- * @return child node
- * @throws org.jboss.cache.lock.LockingException
- * if locking was not obtained
- * @see #addChild(Fqn)
- */
- NodeSPI<K, V> addChildDirect(Fqn childName);
-
- /**
- * Directly adds the node passed in to the children map of the current node. Will throw a CacheException if
- * <tt>child.getFqn().getParent().equals(getFqn())</tt> returns false.
- *
- * @param child child to add
- */
- void addChildDirect(NodeSPI<K, V> child);
-
- /**
- * Retrives a child directly by fully qualified name.
- * Functionally the same as {@link #getChild(Fqn)} except that it bypasses the
- * interceptor chain.
- * <p/>
- * The caller needs to ensure a proper lock has been obtained prior to calling this method.
- *
- * @param childName name of child
- * @return child node
- * @throws org.jboss.cache.lock.LockingException
- * if locking was not obtained
- * @see #getChild(Fqn)
- */
- NodeSPI<K, V> getChildDirect(Fqn childName);
-
- /**
- * Removes a child directly from a node.
- * Functionally the same as {@link #removeChild(Fqn)} except that it bypasses the
- * interceptor chain.
- * <p/>
- * The caller needs to ensure a proper lock has been obtained prior to calling this method, otherwise a
- *
- * @param fqn of child.
- * @return true if the node was found, false otherwise
- * @throws org.jboss.cache.lock.LockingException
- * if locking was not obtained
- * @see #removeChild(Fqn)
- */
- boolean removeChildDirect(Fqn fqn);
-
- /**
- * Removes a child directly from a node.
- * Functionally the same as {@link #removeChild(Object)} except that bypasses the
- * interceptor chain.
- * <p/>
- * The caller needs to ensure a proper lock has been obtained prior to calling this method.
- *
- * @param childName of child.
- * @return true if the node was found, false otherwise
- * @throws org.jboss.cache.lock.LockingException
- * if locking was not obtained
- * @see #removeChild(Object)
- */
- boolean removeChildDirect(Object childName);
-
-
- /**
- * Removes a data key directly from a node.
- * Functionally the same as {@link #remove(Object)} except that it bypasses the
- * interceptor chain.
- * <p/>
- * The caller needs to ensure a proper lock has been obtained prior to calling this method.
- *
- * @param key to remove
- * @return the old data contained under the key
- * @throws org.jboss.cache.lock.LockingException
- * if locking was not obtained
- * @see #remove(Object)
- */
- V removeDirect(K key);
-
- /**
- * Functionally the same as {@link #put(Object,Object)} except that it operates directly on the node and bypasses the
- * interceptor chain.
- * <p/>
- * The caller needs to ensure a proper lock has been obtained prior to calling this method, otherwise a
- * {@link org.jboss.cache.lock.LockingException} will be thrown.
- * <p/>
- *
- * @param key of data
- * @param value of data
- * @return the previous value under the key passed in, or <tt>null</tt>
- * @see #put(Object,Object)
- */
- V putDirect(K key, V value);
-
- /**
- * Functionally the same as {@link #putAll(Map)} except that it operates directly on the node and bypasses the
- * interceptor chain.
- * <p/>
- * The caller needs to ensure a proper lock has been obtained prior to calling this method, otherwise a
- * {@link org.jboss.cache.lock.LockingException} will be thrown.
- * <p/>
- *
- * @param data to put
- * @see #putAll(Map)
- */
- void putAllDirect(Map<K, V> data);
-
- /**
- * Functionally the same as {@link #getData()} except that it operates directly on the node and bypasses the
- * interceptor chain.
- * <p/>
- * Note that this returns a reference to access the node's data.
- * This data should only be modified by the cache itself.
- * This method should never return null.
- * <p/>
- * Also note that this method returns an unmodifiable reference to the underlying data map.
- * <p/>
- * The caller needs to ensure a proper lock has been obtained prior to calling this method, otherwise a
- * {@link org.jboss.cache.lock.LockingException} will be thrown.
- * <p/>
- *
- * @return map containing data
- * @see #getData()
- */
- Map<K, V> getDataDirect();
-
- /**
- * Functionally the same as {@link #get(Object)} except that it operates directly on the node and bypasses the
- * interceptor chain.
- * <p/>
- * The caller needs to ensure a proper lock has been obtained prior to calling this method, otherwise a
- * {@link org.jboss.cache.lock.LockingException} will be thrown.
- * <p/>
- *
- * @param key data to get
- * @return value under key
- * @see #get(Object)
- */
- V getDirect(K key);
-
-
- /**
- * Functionally the same as {@link #clearData()} except that it operates directly on the node and bypasses the
- * interceptor chain.
- * <p/>
- * The caller needs to ensure a proper lock has been obtained prior to calling this method, otherwise a
- * {@link org.jboss.cache.lock.LockingException} will be thrown.
- * <p/>
- *
- * @see #clearData()
- */
- void clearDataDirect();
-
-
- /**
- * Functionally the same as {@link #getKeys()} except that it operates directly on the node and bypasses the
- * interceptor chain.
- * <p/>
- * The caller needs to ensure a proper lock has been obtained prior to calling this method, otherwise a
- * {@link org.jboss.cache.lock.LockingException} will be thrown.
- * <p/>
- *
- * @return set of keys
- * @see #getKeys()
- */
- Set<K> getKeysDirect();
-
- /**
- * Functionally the same as {@link #getChildrenNames()} except that it operates directly on the node and bypasses the
- * interceptor chain.
- * <p/>
- * The caller needs to ensure a proper lock has been obtained prior to calling this method, otherwise a
- * {@link org.jboss.cache.lock.LockingException} will be thrown.
- * <p/>
- *
- * @return set of children names
- * @see #getChildrenNames()
- */
- Set<Object> getChildrenNamesDirect();
-
- /**
- * Retrieves a reference to the cache in which this Node resides.
- *
- * @return a cache
- */
- CacheSPI<K, V> getCache();
-
- // ----------- these methods override their corresponding methods in Node, so that the return types are NodeSPI rather than Node.
-
- /**
- * Returns the parent node as a {@link NodeSPI}, instead
- * of {@link Node} from {@link Node#getParent()}, and is otherwise identical.
- *
- * @return parent node
- * @see Node#getParent()
- */
- NodeSPI<K, V> getParent();
-
- /**
- * @return true if the node has one or more child nodes; false otherwise.
- */
- boolean hasChildrenDirect();
-}
Deleted: core/trunk/src-old/org/jboss/cache/RPCManager.java
===================================================================
--- core/trunk/src-old/org/jboss/cache/RPCManager.java 2007-08-14 19:09:32 UTC (rev 4251)
+++ core/trunk/src-old/org/jboss/cache/RPCManager.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -1,27 +0,0 @@
-package org.jboss.cache;
-
-import org.jboss.cache.marshall.MethodCall;
-import org.jgroups.Address;
-
-import java.lang.reflect.Method;
-import java.util.List;
-
-public interface RPCManager
-{
- public List callRemoteMethods(List<Address> recipients, MethodCall methodCall, int mode, boolean excludeSelf, long timeout) throws Exception;
-
- public boolean isCoordinator();
-
- public Address getCoordinator();
-
- public List callRemoteMethods(List<Address> recipients, MethodCall methodCall, boolean synchronous, boolean excludeSelf, int timeout) throws Exception;
-
- public List callRemoteMethods(List<Address> recipients, Method method, Object[] arguments, boolean synchronous, boolean excludeSelf, long timeout) throws Exception;
-
- public void setCache(CacheSPI c);
-
- /**
- * @return Returns the replication queue (if one is used), null otherwise.
- */
- public ReplicationQueue getReplicationQueue();
-}
Deleted: core/trunk/src-old/org/jboss/cache/RPCManagerImpl.java
===================================================================
--- core/trunk/src-old/org/jboss/cache/RPCManagerImpl.java 2007-08-14 19:09:32 UTC (rev 4251)
+++ core/trunk/src-old/org/jboss/cache/RPCManagerImpl.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -1,75 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source
- *
- * Distributable under LGPL license.
- * See terms of license at gnu.org.
- */
-package org.jboss.cache;
-
-import org.jboss.cache.marshall.MethodCall;
-import org.jgroups.Address;
-
-import java.lang.reflect.Method;
-import java.util.List;
-
-/**
- * Manager that handles all RPC calls between JBoss Cache instances
- *
- * @author <a href="mailto:manik at jboss.org">Manik Surtani (manik at jboss.org)</a>
- */
-public class RPCManagerImpl implements RPCManager
-{
- private CacheImpl c;
-
- /**
- * Empty ctor for mock object creation/unit testing
- */
- public RPCManagerImpl()
- {
- }
-
- public RPCManagerImpl(CacheSPI c)
- {
- this.c = (CacheImpl) c;
- }
-
- // for now, we delegate RPC calls to deprecated methods in CacheImpl.
-
- public List callRemoteMethods(List<Address> recipients, MethodCall methodCall, int mode, boolean excludeSelf, long timeout) throws Exception
- {
- return c.callRemoteMethods(recipients, methodCall, mode, excludeSelf, timeout);
- }
-
- public boolean isCoordinator()
- {
- return c.isCoordinator();
- }
-
- public Address getCoordinator()
- {
- return c.getCoordinator();
- }
-
- public List callRemoteMethods(List<Address> recipients, MethodCall methodCall, boolean synchronous, boolean excludeSelf, int timeout) throws Exception
- {
- return c.callRemoteMethods(recipients, methodCall, synchronous, excludeSelf, timeout);
- }
-
- public List callRemoteMethods(List<Address> recipients, Method method, Object[] arguments, boolean synchronous, boolean excludeSelf, long timeout) throws Exception
- {
- return c.callRemoteMethods(recipients, method, arguments, synchronous, excludeSelf, timeout);
- }
-
- public void setCache(CacheSPI c)
- {
- this.c = (CacheImpl) c;
- }
-
- /**
- * @return Returns the replication queue (if one is used), null otherwise.
- */
- public ReplicationQueue getReplicationQueue()
- {
- return c.getReplicationQueue();
- }
-}
Deleted: core/trunk/src-old/org/jboss/cache/Region.java
===================================================================
--- core/trunk/src-old/org/jboss/cache/Region.java 2007-08-14 19:09:32 UTC (rev 4251)
+++ core/trunk/src-old/org/jboss/cache/Region.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -1,189 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source
- *
- * Distributable under LGPL license.
- * See terms of license at gnu.org.
- */
-package org.jboss.cache;
-
-import org.jboss.cache.config.EvictionPolicyConfig;
-import org.jboss.cache.config.EvictionRegionConfig;
-import org.jboss.cache.eviction.EvictedEventNode;
-import org.jboss.cache.eviction.EvictionPolicy;
-import org.jboss.cache.eviction.LRUPolicy;
-
-/**
- * Defines characteristics such as class loading and eviction of {@link org.jboss.cache.Node}s belonging to a Region in a {@link Cache}.
- * A Region is described by an {@link #getFqn() Fqn} relative to the root of the cache.
- * All nodes and child nodes of this Fqn belong to this region.
- * <p/>
- * If a region is to be recognised as an eviction region (region of type {@link Type#EVICTION} then
- * it <b>must</b> have an {@link org.jboss.cache.config.EvictionPolicyConfig} set using {@link #setEvictionPolicy(org.jboss.cache.config.EvictionPolicyConfig)}.
- * <p/>
- * Similarly, to be recognised as a marshalling region (region of type {@link Type#MARSHALLING} then it <b>must</b> have a
- * {@link ClassLoader} registered using {@link #registerContextClassLoader(ClassLoader)}.
- * <p/>
- * Note that a single region can be both an eviction and marshalling region at the same time.
- * <p/>
- *
- * @author <a href="mailto:manik at jboss.org">Manik Surtani (manik at jboss.org)</a>
- * @see org.jboss.cache.RegionManager
- * @since 2.0.0
- */
-public interface Region extends Comparable<Region>
-{
-
- /**
- * Types of regions.
- */
- public enum Type
- {
- EVICTION, MARSHALLING, ANY
- }
-
- /**
- * Registers a specific {@link ClassLoader} for this region,
- * overridding the default cache class loader.
- *
- * @param classLoader specific class loader
- */
- void registerContextClassLoader(ClassLoader classLoader);
-
- /**
- * Unregisters a registered {@link ClassLoader}s for this region.
- */
- void unregisterContextClassLoader();
-
- /**
- * Activates this region for replication.
- * By default, the entire cache is activated for replication at start-up.
- *
- * @throws RegionNotEmptyException if the {@link Fqn} that represents this region already exists and contains data or children.
- */
- void activate() throws RegionNotEmptyException;
-
- /**
- * Activates this region for replication, but if the {@link Fqn} that represents this region already exists and
- * either contains data or children, no state transfers take place. The region is simply marked as active in this
- * case.
- */
- public void activateIfEmpty();
-
- /**
- * Deactivates this region from being replicated.
- */
- void deactivate();
-
- /**
- * Sets this region as active - this only marks a flag
- * and does not actually activates or
- * deactivates this region. Use {@link #activate()}
- * and {@link #deactivate()} for the full process.
- *
- * @param b
- */
- void setActive(boolean b);
-
- /**
- * Returns true if this region has been activated.
- *
- * @return true if this region has been activated.
- */
- boolean isActive();
-
- /**
- * Returns the configured {@link ClassLoader} for this region.
- *
- * @return a ClassLoader
- */
- ClassLoader getClassLoader();
-
- /**
- * Configures an eviction policy for this region.
- *
- * @param evictionPolicyConfig configuration to set
- */
- void setEvictionPolicy(EvictionPolicyConfig evictionPolicyConfig);
-
- /**
- * Returns an eviction policy configuration.
- *
- * @return an eviction policy configuration
- */
- EvictionPolicyConfig getEvictionPolicyConfig();
-
- /**
- * Returns an eviction policy.
- *
- * @return an eviction policy
- */
- EvictionPolicy getEvictionPolicy();
-
- /**
- * Returns an eviction region configuration for this region.
- *
- * @return an eviction region configuration
- */
- EvictionRegionConfig getEvictionRegionConfig();
-
- /**
- * Clears the node event queue used for processing eviction.
- *
- * @see #nodeEventQueueSize()
- */
- void resetEvictionQueues();
-
- /**
- * Returns the size of the node event queue, used by the eviction thread.
- *
- * @return number of events
- */
- int nodeEventQueueSize();
-
- /**
- * Returns the most recent {@link org.jboss.cache.eviction.EvictedEventNode} added to the event queue by
- * {@link #putNodeEvent(EvictedEventNode)}.
- *
- * @return the last {@link org.jboss.cache.eviction.EvictedEventNode}, or null if no more events exist
- */
- EvictedEventNode takeLastEventNode();
-
- /**
- * Adds an {@link org.jboss.cache.eviction.EvictedEventNode} to the internal queue for processing
- * by the eviction thread.
- *
- * @param event event to add
- */
- void putNodeEvent(EvictedEventNode event);
-
- /**
- * Marks a {@link org.jboss.cache.Node} as currently in use, by adding an event to the eviction queue.
- * If there is an {@link EvictionPolicy} associated with this region, and
- * it respects this event (e.g., {@link LRUPolicy} does), then the {@link org.jboss.cache.Node} will not
- * be evicted until {@link #unmarkNodeCurrentlyInUse(Fqn)} is invoked.
- * <p/>
- * This mechanism can be used to prevent eviction of data that the application
- * is currently using, in the absence of any locks on the {@link org.jboss.cache.Node} where the
- * data is stored.
- *
- * @param fqn Fqn of the node.
- * @see #unmarkNodeCurrentlyInUse(Fqn)
- */
- void markNodeCurrentlyInUse(Fqn fqn, long timeout);
-
- /**
- * Adds an event to the eviction queue indicating that a node is no longer in use.
- *
- * @param fqn Fqn of the node.
- * @see #markNodeCurrentlyInUse(Fqn,long)
- */
- void unmarkNodeCurrentlyInUse(Fqn fqn);
-
- /**
- * Returns the {@link org.jboss.cache.Fqn} of this region.
- *
- * @return the Fqn
- */
- Fqn getFqn();
-
-}
Deleted: core/trunk/src-old/org/jboss/cache/RegionImpl.java
===================================================================
--- core/trunk/src-old/org/jboss/cache/RegionImpl.java 2007-08-14 19:09:32 UTC (rev 4251)
+++ core/trunk/src-old/org/jboss/cache/RegionImpl.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -1,243 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source
- *
- * Distributable under LGPL license.
- * See terms of license at gnu.org.
- */
-package org.jboss.cache;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.jboss.cache.config.EvictionPolicyConfig;
-import org.jboss.cache.config.EvictionRegionConfig;
-import org.jboss.cache.eviction.EvictedEventNode;
-import org.jboss.cache.eviction.EvictionPolicy;
-import org.jboss.cache.eviction.NodeEventType;
-import org.jboss.cache.util.Util;
-
-import java.util.concurrent.BlockingQueue;
-import java.util.concurrent.LinkedBlockingQueue;
-import java.util.concurrent.TimeUnit;
-
-/**
- * Default implementation of a {@link Region}
- *
- * @author <a href="mailto:manik at jboss.org">Manik Surtani (manik at jboss.org)</a>
- */
-public class RegionImpl implements Region
-{
- private static final Log log = LogFactory.getLog(RegionImpl.class);
-
- private RegionManager regionManager;
- private Fqn fqn;
- private boolean active;
- private ClassLoader classLoader;
- private BlockingQueue<EvictedEventNode> nodeEventQueue = null;
- private int capacityWarnThreshold = 0;
- private EvictionRegionConfig configuration = new EvictionRegionConfig();
- private EvictionPolicy policy;
-
- /**
- * Constructs a marshalling region from an fqn and region manager.
- */
- public RegionImpl(Fqn fqn, RegionManager regionManager)
- {
- this.fqn = fqn;
- this.regionManager = regionManager;
- this.active = !regionManager.isDefaultInactive();
- }
-
- /**
- * Constructs an eviction region from a policy and configuration, defined by an fqn and region manager.
- */
- public RegionImpl(EvictionPolicy policy, EvictionRegionConfig config, Fqn fqn, RegionManager regionManager)
- {
- this(fqn, regionManager);
- this.configuration = config;
- this.policy = policy;
- createQueue();
- }
-
- public void registerContextClassLoader(ClassLoader classLoader)
- {
- this.classLoader = classLoader;
- }
-
- public void unregisterContextClassLoader()
- {
- this.classLoader = null;
- }
-
- public void activate()
- {
- regionManager.activate(fqn);
- active = true;
- }
-
- public void activateIfEmpty()
- {
- regionManager.activateIfEmpty(fqn);
- active = true;
- }
-
- public void deactivate()
- {
- regionManager.deactivate(fqn);
- active = false;
- }
-
- public boolean isActive()
- {
- return active;
- }
-
- public ClassLoader getClassLoader()
- {
- return classLoader;
- }
-
- public Fqn getFqn()
- {
- return fqn;
- }
-
- public void setActive(boolean b)
- {
- active = b;
- }
-
- // -------- eviction stuff -----
-
- public void markNodeCurrentlyInUse(Fqn fqn, long timeout)
- {
- EvictedEventNode markUse = new EvictedEventNode(fqn, NodeEventType.MARK_IN_USE_EVENT);
- markUse.setInUseTimeout(timeout);
- putNodeEvent(markUse);
- }
-
- public void unmarkNodeCurrentlyInUse(Fqn fqn)
- {
- EvictedEventNode markNoUse = new EvictedEventNode(fqn, NodeEventType.UNMARK_USE_EVENT);
- putNodeEvent(markNoUse);
- }
-
- public String toString()
- {
- return "RegionImpl{" +
- "fqn=" + fqn +
- "; classloader="+ classLoader +
- "; active=" + active +
- "; eviction=" + (getEvictionPolicy() != null) +
- "; timerThreadRegistered=" + (getEvictionPolicy() != null && regionManager.getEvictionTimerTask().isRegionRegisteredForProcessing(this)) +
- '}';
- }
-
- public int compareTo(Region other)
- {
- return getFqn().compareTo(other.getFqn());
- }
-
- public void putNodeEvent(EvictedEventNode event)
- {
- try
- {
- if (nodeEventQueue == null) createQueue();// in case the queue does not exist yet.
- if (nodeEventQueue.size() > capacityWarnThreshold)
- {
- log.warn("putNodeEvent(): eviction node event queue size is at 98% threshold value of capacity: " + configuration.getEventQueueSize() +
- " Region: " + fqn +
- " You will need to reduce the wakeUpIntervalSeconds parameter.");
- }
-
- nodeEventQueue.put(event);
- }
- catch (InterruptedException e)
- {
- log.debug("give up put", e);
- }
- }
-
- public EvictedEventNode takeLastEventNode()
- {
- try
- {
- return nodeEventQueue.poll(0, TimeUnit.SECONDS);
- }
- catch (InterruptedException e)
- {
- log.debug("trace", e);
- }
- return null;
- }
-
- public int nodeEventQueueSize()
- {
- return nodeEventQueue.size();
- }
-
- public void resetEvictionQueues()
- {
- nodeEventQueue.clear();
- }
-
- private synchronized void createQueue()
- {
- if (nodeEventQueue == null)
- {
- if (configuration == null)
- {
- throw new IllegalArgumentException("null eviction configuration");
- }
- int size = configuration.getEventQueueSize();
- capacityWarnThreshold = (98 * size) / 100 - 100;
- if (capacityWarnThreshold <= 0)
- {
- throw new RuntimeException("Capacity warn threshold used in eviction is smaller than 1.");
- }
- nodeEventQueue = new LinkedBlockingQueue<EvictedEventNode>(size);
- }
- }
-
- public EvictionRegionConfig getEvictionRegionConfig()
- {
- return this.configuration;
- }
-
- public EvictionPolicyConfig getEvictionPolicyConfig()
- {
- return configuration == null ? null : configuration.getEvictionPolicyConfig();
- }
-
- public EvictionPolicy getEvictionPolicy()
- {
- return policy;
- }
-
- public void setEvictionPolicy(EvictionPolicyConfig evictionPolicyConfig)
- {
- configuration.setEvictionPolicyConfig(evictionPolicyConfig);
- policy = createPolicy(evictionPolicyConfig.getEvictionPolicyClass());
- regionManager.getEvictionTimerTask().addRegionToProcess(this);
- if (nodeEventQueue == null) createQueue();
- }
-
- private EvictionPolicy createPolicy(String className)
- {
- if (className == null)
- {
- throw new IllegalArgumentException("null className");
- }
- try
- {
- if (log.isTraceEnabled()) log.trace("Instantiating " + className);
- EvictionPolicy ep = (EvictionPolicy) Util.loadClass(className).newInstance();
- ep.setCache(regionManager.getCache());
- return ep;
- }
- catch (Exception e)
- {
- log.fatal("Unable to instantiate eviction policy class " + className, e);
- return null;
- }
- }
-}
Deleted: core/trunk/src-old/org/jboss/cache/RegionManager.java
===================================================================
--- core/trunk/src-old/org/jboss/cache/RegionManager.java 2007-08-14 19:09:32 UTC (rev 4251)
+++ core/trunk/src-old/org/jboss/cache/RegionManager.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -1,819 +0,0 @@
-package org.jboss.cache;
-
-import net.jcip.annotations.ThreadSafe;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.jboss.cache.buddyreplication.BuddyManager;
-import org.jboss.cache.config.ConfigurationException;
-import org.jboss.cache.config.EvictionConfig;
-import org.jboss.cache.config.EvictionRegionConfig;
-import org.jboss.cache.eviction.EvictionTimerTask;
-import org.jboss.cache.eviction.RegionNameConflictException;
-import org.jboss.cache.lock.NodeLock;
-import org.jgroups.Address;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-
-/**
- * Manages multiple {@link Region}s for a Cache instance.
- *
- * @author <a href="mailto:manik at jboss.org">Manik Surtani</a>
- * @since 2.0.0
- */
- at ThreadSafe
-public class RegionManager
-{
- /**
- * The default region used in XML configuration files when defining eviction policies. Any
- * eviction settings bound under this 'default' Fqn is appplied to {@link org.jboss.cache.Fqn#ROOT} internally so
- * any region that is not explicitly defined comes under the settings defined for this default.
- */
- public static final Fqn DEFAULT_REGION = new Fqn("_default_");
-
- /**
- * A registry of regions that have been defined.
- */
- private Map<Fqn, Region> regionsRegistry = new ConcurrentHashMap<Fqn, Region>();
- private boolean defaultInactive;
- private Log log = LogFactory.getLog(RegionManager.class);
- private CacheImpl cache;
- private boolean usingEvictions;
- private EvictionConfig evictionConfig;
- private EvictionTimerTask evictionTimerTask = new EvictionTimerTask();
-
- protected final Set<Fqn> activationChangeNodes = Collections.synchronizedSet(new HashSet<Fqn>());
-
- /**
- * Constructs a new instance not attached to a cache.
- */
- public RegionManager()
- {
- }
-
- /**
- * Constructs a new instance attached to a cache.
- */
- public RegionManager(CacheImpl cache)
- {
- this.cache = cache;
- }
-
- /**
- * Returns true if evictions are being processed.
- */
- public boolean isUsingEvictions()
- {
- return usingEvictions;
- }
-
- /**
- * Returns true if replication is by default inactive for new {@link Region}s.
- */
- public boolean isDefaultInactive()
- {
- return defaultInactive;
- }
-
- /**
- * Sets if replication for new {@link Region}s is by default inactive.
- */
- public void setDefaultInactive(boolean defaultInactive)
- {
- this.defaultInactive = defaultInactive;
- }
-
- /**
- * Helper utility that checks for a {@link ClassLoader} registered for the
- * given {@link Fqn}, and if found sets it as the TCCL. If the given Fqn is
- * under the _BUDDY_BACKUP_ region, the equivalent region in the main
- * cache is used to find the {@link ClassLoader}.
- *
- * @param fqn Fqn pointing to a region for which a special classloader
- * may have been registered.
- */
- public void setContextClassLoaderAsCurrent(Fqn fqn)
- {
- if (fqn.isChildOf(BuddyManager.BUDDY_BACKUP_SUBTREE_FQN))
- {
- if (fqn.size() <= 2)
- {
- fqn = Fqn.ROOT;
- }
- else
- {
- fqn = fqn.getSubFqn(2, fqn.size());
- }
- }
- Region region = getRegion(fqn, false);
- ClassLoader regionCL = (region == null) ? null : region.getClassLoader();
- if (regionCL != null)
- {
- Thread.currentThread().setContextClassLoader(regionCL);
- }
-
- }
-
- /**
- * Returns a region by {@link Fqn}, creating it optionally if absent. If the region does not exist and <tt>createIfAbsent</tt>
- * is <tt>false</tt>, a parent region which may apply to the {@link Fqn} is sought.
- */
- public Region getRegion(Fqn fqn, boolean createIfAbsent)
- {
- return getRegion(fqn, Region.Type.ANY, createIfAbsent);
- }
-
- /**
- * An overloaded form of {@link #getRegion(Fqn,boolean)} that takes an additional {@link org.jboss.cache.Region.Type}
- * parameter to force regions of a specific type.
- *
- * @see org.jboss.cache.Region.Type
- */
- public Region getRegion(Fqn fqn, Region.Type type, boolean createIfAbsent)
- {
- Fqn fqnToUse = fqn;
- if (DEFAULT_REGION.equals(fqnToUse)) fqnToUse = Fqn.ROOT;
- // first see if a region for this specific Fqn exists
- if (regionsRegistry.containsKey(fqnToUse))
- {
- Region r = regionsRegistry.get(fqnToUse);
-
- // this is a very poor way of telling whether a region is a marshalling one or an eviction one. :-(
- // mandates that class loaders be registered for marshalling regions.
- if (type == Region.Type.ANY
- || (type == Region.Type.MARSHALLING && r.getClassLoader() != null)
- || (type == Region.Type.EVICTION && r.getEvictionPolicyConfig() != null))
- {
- return r;
- }
- }
-
- // if not, attempt to create one ...
- if (createIfAbsent)
- {
- Region r = new RegionImpl(fqnToUse, this);
- regionsRegistry.put(fqnToUse, r);
- if (type == Region.Type.MARSHALLING)
- {
- // insert current class loader into region so at least it is recognised as a marshalling region
- r.registerContextClassLoader(getClass().getClassLoader());
- }
- return r;
- }
- else
- {
- // first test if the default region has been defined. If not, and if eviction regions
- // are in use, throw an exception since it is required.
- if (isUsingEvictions() && !regionsRegistry.containsKey(Fqn.ROOT))
- {
- throw new RuntimeException("No default eviction region defined!");
- }
- }
-
- // else try and find a parent which has a defined region, may return null if nothing is defined.
- Region nextBestThing = null;
- Fqn nextFqn = fqnToUse;
-
- while (nextBestThing == null)
- {
- nextFqn = nextFqn.getParent();
- if (regionsRegistry.containsKey(nextFqn))
- {
- Region r = regionsRegistry.get(nextFqn);
-
- // this is a very poor way of telling whether a region is a marshalling one or an eviction one. :-(
- // mandates that class loaders be registered for marshalling regions.
- if (type == Region.Type.ANY
- || (type == Region.Type.MARSHALLING && r.getClassLoader() != null)
- || (type == Region.Type.EVICTION && r.getEvictionPolicyConfig() != null))
- {
- nextBestThing = r;
- }
- }
- if (nextFqn.isRoot()) break;
- }
-
- return nextBestThing;
- }
-
- /**
- * Returns a region using Fqn.fromString(fqn), calling {@link #getRegion(Fqn,boolean)}
- *
- * @param fqn
- * @param createIfAbsent
- * @see #getRegion(Fqn,boolean)
- */
- public Region getRegion(String fqn, boolean createIfAbsent)
- {
- return getRegion(Fqn.fromString(fqn), createIfAbsent);
- }
-
- /**
- * Removes a {@link org.jboss.cache.Region} identified by the given fqn.
- *
- * @param fqn fqn of the region to remove
- * @return true if such a region existed and was removed.
- */
- public boolean removeRegion(Fqn fqn)
- {
- Region r = regionsRegistry.remove(fqn);
- if (r == null) return false;
-
- if (isUsingEvictions() && r.getEvictionPolicy() != null)
- {
- evictionTimerTask.removeRegionToProcess(r);
- }
- return true;
- }
-
- /**
- * @return the eviction timer task object associated with this Region Manager.
- */
- protected EvictionTimerTask getEvictionTimerTask()
- {
- return evictionTimerTask;
- }
-
- /**
- * Activates unmarshalling of replication messages for the region
- * rooted in the given Fqn.
- * <p/>
- * <strong>NOTE:</strong> This method will cause the creation of a node
- * in the local cache at <code>subtreeFqn</code> whether or not that
- * node exists anywhere else in the cluster. If the node does not exist
- * elsewhere, the local node will be empty. The creation of this node will
- * not be replicated.
- * <p/>
- *
- * @param fqn representing the region to be activated.
- * @throws RegionNotEmptyException if the node <code>fqn</code>
- * exists and already has either data or children
- */
- public void activate(Fqn fqn) throws RegionNotEmptyException
- {
- activate(fqn, false);
- }
-
- /**
- * Attempts to activate a given region rooted at a given Fqn, similar to {@link #activate(Fqn)} except
- * that if the fqn is currently already in use (probably already been activated) this method is a no-op.
- *
- * @param fqn which represents the region to activate
- */
- public void activateIfEmpty(Fqn fqn)
- {
- activate(fqn, true);
- }
-
- private void activate(Fqn fqn, boolean suppressRegionNotEmptyException)
- {
- try
- {
- if (log.isTraceEnabled()) log.trace("Activating region " + fqn);
- Region r = getRegion(fqn, false);
- if (r != null)
- {
- if (!defaultInactive && r.getClassLoader() == null)
- {
- // This region's state will no match that of a non-existent one
- // So, there is no reason to keep this region any more
-
- // (Brian) We shouldn't do this anymore; now outside code
- // can have a ref to the region!!
- removeRegion(fqn);
- }
- else
- {
- //r.activate();
- r.setActive(true);
- // FIXME - persistent state transfer counts too!
- if (cache.getConfiguration().isFetchInMemoryState())
- {
- activateRegion(r.getFqn(), suppressRegionNotEmptyException);
- }
- }
- }
- else if (defaultInactive)
- {
- // "Active" region is not the default, so create a region
- r = getRegion(fqn, true);
- r.setActive(true);
- // FIXME - persistent state transfer counts too!
- if (cache.getConfiguration().isFetchInMemoryState())
- {
- activateRegion(r.getFqn(), suppressRegionNotEmptyException);
- }
- }
- }
- catch (RuntimeException re)
- {
- throw re;
- }
- catch (Exception e)
- {
- throw new RuntimeException(e);
- }
- }
-
- /**
- * Causes the cache to transfer state for the subtree rooted at
- * <code>subtreeFqn</code> and to begin accepting replication messages
- * for that subtree.
- * <p/>
- * <strong>NOTE:</strong> This method will cause the creation of a node
- * in the local cache at <code>subtreeFqn</code> whether or not that
- * node exists anywhere else in the cluster. If the node does not exist
- * elsewhere, the local node will be empty. The creation of this node will
- * not be replicated.
- *
- * @param fqn Fqn string indicating the uppermost node in the
- * portion of the cache that should be activated.
- * @throws RegionNotEmptyException if the node <code>subtreeFqn</code>
- * exists and has either data or children
- */
- private void activateRegion(Fqn fqn, boolean suppressRegionNotEmptyException)
- {
- // Check whether the node already exists and has data
- Node subtreeRoot = cache.findNode(fqn);
-
- /*
- * Commented out on Nov 16,2006 Manik&Vladimir
- *
- * if (!(cache.isNodeEmpty(subtreeRoot)))
- {
- throw new RegionNotEmptyException("Node " + subtreeRoot.getFqn() + " already exists and is not empty");
- }*/
-
- if (isActivatingDeactivating(fqn))
- {
- throw new CacheException("Region " + subtreeRoot.getFqn() + " is already being activated/deactivated");
- }
-
- if (log.isDebugEnabled())
- {
- log.debug("activating " + fqn);
- }
-
- try
- {
-
- // Add this fqn to the set of those we are activating
- // so calls to _getState for the fqn can return quickly
- activationChangeNodes.add(fqn);
-
- Region region = getRegion(fqn, true);
-
- BuddyManager buddyManager = cache.getBuddyManager();
- // Request partial state from the cluster and integrate it
- if (buddyManager == null)
- {
- // Get the state from any node that has it and put it
- // in the main cache
- if (subtreeRoot == null)
- {
- // We'll update this node with the state we receive
- subtreeRoot = cache.createSubtreeRootNode(fqn);
- }
-
- List<Address> members = cache.getMembers();
- cache.fetchPartialState(members, subtreeRoot.getFqn());
- }
- else
- {
- // Get the state from each DataOwner and integrate in their
- // respective buddy backup cache
- List<Address> buddies = buddyManager.getBuddyAddresses();
- for (Address buddy : buddies)
- {
- List<Address> sources = new ArrayList<Address>(1);
- sources.add(buddy);
- Fqn base = new Fqn(BuddyManager.BUDDY_BACKUP_SUBTREE_FQN, BuddyManager.getGroupNameFromAddress(buddy));
- Fqn buddyRoot = new Fqn(base, fqn);
- subtreeRoot = cache.findNode(buddyRoot);
- if (subtreeRoot == null)
- {
- // We'll update this node with the state we receive
- subtreeRoot = cache.createSubtreeRootNode(buddyRoot);
- }
- cache.fetchPartialState(sources, fqn, subtreeRoot.getFqn());
- }
- }
- }
- catch (Throwable t)
- {
- log.error("failed to activate " + fqn, t);
-
- // "Re-deactivate" the region
- try
- {
- inactivateRegion(fqn);
- }
- catch (Exception e)
- {
- log.error("failed inactivating " + fqn, e);
- // just swallow this one and throw the first one
- }
-
- // Throw the exception on, wrapping if necessary
- if (t instanceof RegionNotEmptyException)
- {
- if (!suppressRegionNotEmptyException) throw (RegionNotEmptyException) t;
- }
- else if (t instanceof CacheException)
- {
- throw (CacheException) t;
- }
- else
- {
- throw new CacheException(t.getClass().getName() + " " +
- t.getLocalizedMessage(), t);
- }
- }
- finally
- {
- activationChangeNodes.remove(fqn);
- }
- }
-
- /**
- * Convenienve method. If the region defined by fqn does not exist, {@link #isDefaultInactive()} is returned, otherwise
- * !{@link Region#isActive()} is returned.
- *
- * @param fqn fqn to test
- * @return true if inactive
- */
- public boolean isInactive(Fqn fqn)
- {
- Region region = getRegion(fqn, false);
- return region == null ? defaultInactive : !region.isActive();
- }
-
-
- /**
- * Causes the cache to stop accepting replication events for the subtree
- * rooted at <code>subtreeFqn</code> and evict all nodes in that subtree.
- * <p/>
- * This is legacy code and should not be called directly. This is a private method for now and will be refactored out.
- * You should be using {@link #activate(Fqn)} and {@link #deactivate(Fqn)}
- * <p/>
- *
- * @param fqn Fqn string indicating the uppermost node in the
- * portion of the cache that should be activated.
- * @throws RegionNameConflictException if <code>subtreeFqn</code> indicates
- * a node that is part of another
- * subtree that is being specially
- * managed (either by activate/inactiveRegion()
- * or by registerClassLoader())
- * @throws CacheException if there is a problem evicting nodes
- * @throws IllegalStateException if {@link org.jboss.cache.config.Configuration#isUseRegionBasedMarshalling()} is <code>false</code>
- */
- private void inactivateRegion(Fqn fqn) throws CacheException
- {
- if (isActivatingDeactivating(fqn))
- {
- throw new CacheException("Region " + fqn + " is already being activated/deactivated");
- }
-
- NodeSPI parent = null;
- NodeSPI subtreeRoot = null;
- boolean parentLocked = false;
- boolean subtreeLocked = false;
- NodeLock parentLock = null;
- NodeLock subtreeLock = null;
-
- try
- {
- // Record that this fqn is in status change, so can't provide state
- activationChangeNodes.add(fqn);
-
- if (!isInactive(fqn))
- {
- deactivate(fqn);
- }
-
- // Create a list with the Fqn in the main cache and any buddy backup trees
- BuddyManager buddyManager = cache.getBuddyManager();
- ArrayList<Fqn> list = new ArrayList<Fqn>();
- list.add(fqn);
-
- if (buddyManager != null)
- {
- Set buddies = cache.getChildrenNames(BuddyManager.BUDDY_BACKUP_SUBTREE_FQN);
- if (buddies != null)
- {
- for (Iterator it = buddies.iterator(); it.hasNext();)
- {
- Fqn base = new Fqn(BuddyManager.BUDDY_BACKUP_SUBTREE_FQN, it.next());
- list.add(new Fqn(base, fqn));
- }
- }
- }
-
- long stateFetchTimeout = cache.getConfiguration().getLockAcquisitionTimeout() + 5000;
- // Remove the subtree from the main cache and any buddy backup trees
- for (Iterator<Fqn> it = list.iterator(); it.hasNext();)
- {
- Fqn subtree = it.next();
- subtreeRoot = cache.findNode(subtree);
- if (subtreeRoot != null)
- {
- // Acquire locks
- Object owner = cache.getOwnerForLock();
- subtreeLock = subtreeRoot.getLock();
- subtreeLock.acquireAll(owner, stateFetchTimeout, NodeLock.LockType.WRITE);
- subtreeLocked = true;
-
- // Lock the parent, as we're about to write to it
- parent = subtreeRoot.getParent();
- if (parent != null)
- {
- parentLock = parent.getLock();
- parentLock.acquire(owner, stateFetchTimeout, NodeLock.LockType.WRITE);
- parentLocked = true;
- }
-
- // Remove the subtree
- cache._evictSubtree(subtree);
-
- // Release locks
- if (parent != null)
- {
- log.debug("forcing release of locks in parent");
- parentLock.releaseAll();
- }
-
- parentLocked = false;
-
- log.debug("forcing release of all locks in subtree");
- subtreeLock.releaseAll();
- subtreeLocked = false;
- }
- }
- }
- catch (InterruptedException ie)
- {
- throw new CacheException("Interrupted while acquiring lock", ie);
- }
- finally
- {
- // If we didn't succeed, undo the marshalling change
- // NO. Since we inactivated, we may have missed changes
- //if (!success && !inactive)
- // marshaller_.activate(subtreeFqn);
-
- // If necessary, release locks
- if (parentLocked)
- {
- log.debug("forcing release of locks in parent");
- try
- {
- parentLock.releaseAll();
- }
- catch (Throwable t)
- {
- log.error("failed releasing locks", t);
- }
- }
- if (subtreeLocked)
- {
- log.debug("forcing release of all locks in subtree");
- try
- {
- subtreeLock.releaseAll();
- }
- catch (Throwable t)
- {
- log.error("failed releasing locks", t);
- }
- }
-
- activationChangeNodes.remove(fqn);
- }
- }
-
- /**
- * <p/>
- * This is legacy code and should not be called directly. This is a private method for now and will be refactored out.
- * You should be using {@link #activate(Fqn)} and {@link #deactivate(Fqn)}
- * <p/>
- *
- * @param fqn fqn of the region
- * @return true if the region defined by the fqn is in the process of activating/deactivating
- */
- private boolean isActivatingDeactivating(Fqn fqn)
- {
- return activationChangeNodes.contains(fqn);
- }
-
- /**
- * Returns true if the region exists
- *
- * @param fqn FQN of the region
- * @param type type of region to search for
- * @return true if the region exists
- */
- public boolean hasRegion(Fqn fqn, Region.Type type)
- {
- Region r = regionsRegistry.get(fqn);
- if (r == null) return false;
- switch (type)
- {
- case ANY:
- return true;
- case EVICTION:
- return r.getEvictionPolicy() != null && evictionTimerTask.isRegionRegisteredForProcessing(r);
- case MARSHALLING:
- return r.isActive() && r.getClassLoader() != null;
- }
- // should never reach here?
- return false;
- }
-
- /**
- * Disables unmarshalling of replication messages for the region
- * rooted in the given Fqn.
- *
- * @param fqn
- */
- public void deactivate(Fqn fqn)
- {
- try
- {
- Region region = getRegion(fqn, false);
-
- if (region != null)
- {
- if (defaultInactive && region.getClassLoader() == null)
- {
- // This region's state will no match that of a non-existent one
- // So, there is no reason to keep this region any more
-
- // FIXME (Brian) We shouldn't do this anymore; now outside code
- // can have a ref to the region!!
- removeRegion(fqn);
- }
- else
- {
- //region.deactivate();
- region.setActive(false);
- // FIXME - we should always clean up; otherwise stale data
- // is in memory!
- if (cache.getConfiguration().isFetchInMemoryState())
- {
- inactivateRegion(fqn);
- }
- }
- }
- else if (!defaultInactive)
- {
- region = getRegion(fqn, true);
- region.setActive(false);
- // FIXME - we should always clean up; otherwise stale data
- // is in memory!
- if (cache.getConfiguration().isFetchInMemoryState())
- {
- inactivateRegion(fqn);
- }
- }
- }
- catch (RuntimeException re)
- {
- throw re;
- }
- catch (Exception e)
- {
- throw new RuntimeException(e);
- }
- }
-
- /**
- * Resets the region manager's regions registry
- */
- public void reset()
- {
- regionsRegistry.clear();
- }
-
- /**
- * Returns an ordered list of all regions.
- * Note that the ordered list returned is sorted according to the natural order defined in the {@link Comparable} interface, which {@link org.jboss.cache.Region} extends.
- *
- * @param type Type of region to return
- * @return an ordered list of all regions, based on the type requested.
- */
- public List<Region> getAllRegions(Region.Type type)
- {
- List<Region> regions;
-
- if (type != Region.Type.ANY)
- {
- regions = new ArrayList<Region>();
- // we need to loop thru the regions and only select specific regions to rtn.
- for (Region r : regionsRegistry.values())
- {
- if ((type == Region.Type.EVICTION && r.getEvictionPolicy() != null && evictionTimerTask.isRegionRegisteredForProcessing(r)) ||
- (type == Region.Type.MARSHALLING && r.isActive() && r.getClassLoader() != null))
- regions.add(r);
- }
- }
- else
- {
- // put all regions
- regions = new ArrayList<Region>(regionsRegistry.values());
- }
-
- Collections.sort(regions);
-
- return regions;
- }
-
- /**
- * Sets if evictions are processed.
- */
- public void setUsingEvictions(boolean usingEvictions)
- {
- this.usingEvictions = usingEvictions;
- }
-
- /**
- * Sets the eviction configuration.
- */
- public void setEvictionConfig(EvictionConfig evictionConfig)
- {
- this.evictionConfig = evictionConfig;
- boolean setDefault = false;
- // create regions for the regions defined in the evictionConfig.
- for (EvictionRegionConfig erc : evictionConfig.getEvictionRegionConfigs())
- {
- Fqn fqn = erc.getRegionFqn();
- if (log.isTraceEnabled()) log.trace("Creating eviction region " + fqn);
-
- if (fqn.equals(DEFAULT_REGION))
- {
- if (setDefault)
- {
- throw new ConfigurationException("A default region for evictions has already been set for this cache");
- }
- if (log.isTraceEnabled()) log.trace("Applying settings for " + DEFAULT_REGION + " to Fqn.ROOT");
- fqn = Fqn.ROOT;
- setDefault = true;
- }
- Region r = getRegion(fqn, true);
- r.setEvictionPolicy(erc.getEvictionPolicyConfig());
- }
- }
-
- /**
- * Starts the eviction processing thread.
- */
- public void startEvictionThread()
- {
- evictionTimerTask.init(evictionConfig.getWakeupIntervalSeconds());
- }
-
- /**
- * Stops the eviction processing thread
- */
- public void stopEvictionThread()
- {
- evictionTimerTask.stop();
- }
-
-
- /**
- * Returns a string containing debug information on every region.
- */
- public String dumpRegions()
- {
- StringBuilder sb = new StringBuilder();
- for (Region r : regionsRegistry.values())
- {
- sb.append("\tRegion " + r);
- sb.append("\n");
- }
- return sb.toString();
- }
-
- /**
- * Returns a string containing debug information on every region.
- */
- public String toString()
- {
- return "RegionManager " + dumpRegions();
- }
-
- /**
- * Returns the cache for this region manager
- */
- public CacheImpl getCache()
- {
- return this.cache;
- }
-
-}
Deleted: core/trunk/src-old/org/jboss/cache/RegionNotEmptyException.java
===================================================================
--- core/trunk/src-old/org/jboss/cache/RegionNotEmptyException.java 2007-08-14 19:09:32 UTC (rev 4251)
+++ core/trunk/src-old/org/jboss/cache/RegionNotEmptyException.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -1,39 +0,0 @@
-/*
- * JBoss, the OpenSource J2EE webOS
- *
- * Distributable under LGPL license.
- * See terms of license at gnu.org.
- */
-
-package org.jboss.cache;
-
-/**
- * Thrown when an attempt is made to {@link RegionManager#activate(Fqn)} activate a subtree}
- * root in Fqn that already has an existing node in the cache.
- *
- * @author <a href="mailto://brian.stansberry@jboss.com">Brian Stansberry</a>
- */
-public class RegionNotEmptyException extends CacheException
-{
-
- /**
- * The serialVersionUID
- */
- private static final long serialVersionUID = 1L;
-
- public RegionNotEmptyException()
- {
- super();
- }
-
- public RegionNotEmptyException(String msg)
- {
- super(msg);
- }
-
- public RegionNotEmptyException(String msg, Throwable cause)
- {
- super(msg, cause);
- }
-
-}
Deleted: core/trunk/src-old/org/jboss/cache/ReplicationException.java
===================================================================
--- core/trunk/src-old/org/jboss/cache/ReplicationException.java 2007-08-14 19:09:32 UTC (rev 4251)
+++ core/trunk/src-old/org/jboss/cache/ReplicationException.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -1,44 +0,0 @@
-// $Id$
-
-/*
- * JBoss, the OpenSource J2EE webOS
- *
- * Distributable under LGPL license.
- * See terms of license at gnu.org.
- */
-
-package org.jboss.cache;
-
-/**
- * Thrown when a replication problem occurred
- */
-public class ReplicationException extends CacheException
-{
-
- private static final long serialVersionUID = 33172388691879866L;
-
- public ReplicationException()
- {
- super();
- }
-
- public ReplicationException(Throwable cause)
- {
- super(cause);
- }
-
- public ReplicationException(String msg)
- {
- super(msg);
- }
-
- public ReplicationException(String msg, Throwable cause)
- {
- super(msg, cause);
- }
-
- public String toString()
- {
- return super.toString();
- }
-}
Deleted: core/trunk/src-old/org/jboss/cache/ReplicationQueue.java
===================================================================
--- core/trunk/src-old/org/jboss/cache/ReplicationQueue.java 2007-08-14 19:09:32 UTC (rev 4251)
+++ core/trunk/src-old/org/jboss/cache/ReplicationQueue.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -1,197 +0,0 @@
-/*
- * JBoss, the OpenSource J2EE webOS
- *
- * Distributable under LGPL license.
- * See terms of license at gnu.org.
- */
-package org.jboss.cache;
-
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.jboss.cache.marshall.MethodCall;
-import org.jboss.cache.marshall.MethodDeclarations;
-
-import java.util.ArrayList;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Timer;
-import java.util.TimerTask;
-
-
-/**
- * Periodically (or when certain size is exceeded) takes elements and replicates them.
- *
- * @author <a href="mailto:bela at jboss.org">Bela Ban</a> May 24, 2003
- * @version $Revision$
- */
-public class ReplicationQueue
-{
-
- private static Log log = LogFactory.getLog(ReplicationQueue.class);
-
- private CacheImpl cache = null;
-
- /**
- * We flush every 5 seconds. Inactive if -1 or 0
- */
- private long interval = 5000;
-
- /**
- * Max elements before we flush
- */
- private long max_elements = 500;
-
- /**
- * Holds the replication jobs: LinkedList<MethodCall>
- */
- private final List<MethodCall> elements = new LinkedList<MethodCall>();
-
- /**
- * For periodical replication
- */
- private Timer timer = null;
-
- /**
- * The timer task, only calls flush() when executed by Timer
- */
- private MyTask task = null;
-
- public ReplicationQueue()
- {
- }
-
- /**
- * Constructs a new ReplicationQueue.
- */
- public ReplicationQueue(CacheImpl cache, long interval, long max_elements)
- {
- this.cache = cache;
- this.interval = interval;
- this.max_elements = max_elements;
- }
-
- /**
- * Returns the flush interval in milliseconds.
- */
- public long getInterval()
- {
- return interval;
- }
-
- /**
- * Sets the flush interval in milliseconds.
- */
- public void setInterval(long interval)
- {
- this.interval = interval;
- stop();
- start();
- }
-
- /**
- * Returns the maximum number of elements to hold.
- * If the maximum number is reached, flushes in the calling thread.
- */
- public long getMax_elements()
- {
- return max_elements;
- }
-
- /**
- * Sets the maximum number of elements to hold.
- */
- public void setMax_elements(long max_elements)
- {
- this.max_elements = max_elements;
- }
-
- /**
- * Starts the asynchronous flush queue.
- */
- public synchronized void start()
- {
- if (interval > 0)
- {
- if (task == null)
- task = new MyTask();
- if (timer == null)
- {
- timer = new Timer(true);
- timer.schedule(task,
- 500, // delay before initial flush
- interval); // interval between flushes
- }
- }
- }
-
- /**
- * Stops the asynchronous flush queue.
- */
- public synchronized void stop()
- {
- if (task != null)
- {
- task.cancel();
- task = null;
- }
- if (timer != null)
- {
- timer.cancel();
- timer = null;
- }
- }
-
-
- /**
- * Adds a new method call.
- */
- public void add(MethodCall job)
- {
- if (job == null)
- throw new NullPointerException("job is null");
- synchronized (elements)
- {
- elements.add(job);
- if (elements.size() >= max_elements)
- flush();
- }
- }
-
- /**
- * Flushes existing method calls.
- */
- public void flush()
- {
- List<MethodCall> l;
- synchronized (elements)
- {
- if (log.isTraceEnabled())
- log.trace("flush(): flushing repl queue (num elements=" + elements.size() + ")");
- l = new ArrayList<MethodCall>(elements);
- elements.clear();
- }
-
- if (l.size() > 0)
- {
- try
- {
- // send to all live nodes in the cluster
- cache.getRPCManager().callRemoteMethods(null, MethodDeclarations.replicateAllMethod, new Object[]{l}, false, true, 5000);
- }
- catch (Throwable t)
- {
- log.error("failed replicating " + l.size() + " elements in replication queue", t);
- }
- }
- }
-
- class MyTask extends TimerTask
- {
- public void run()
- {
- flush();
- }
- }
-
-}
Deleted: core/trunk/src-old/org/jboss/cache/SuspectException.java
===================================================================
--- core/trunk/src-old/org/jboss/cache/SuspectException.java 2007-08-14 19:09:32 UTC (rev 4251)
+++ core/trunk/src-old/org/jboss/cache/SuspectException.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -1,28 +0,0 @@
-package org.jboss.cache;
-
-/**
- * Thrown when a member is suspected during remote method invocation
- * @author Bela Ban
- * @version $Id$
- */
-public class SuspectException extends CacheException
-{
-
- private static final long serialVersionUID = -2965599037371850141L;
-
- public SuspectException() {
- super();
- }
-
- public SuspectException(String msg) {
- super(msg);
- }
-
- public SuspectException(String msg, Throwable cause) {
- super(msg, cause);
- }
-
- public String toString() {
- return super.toString();
- }
-}
Deleted: core/trunk/src-old/org/jboss/cache/TreeCacheViewMBean.java
===================================================================
--- core/trunk/src-old/org/jboss/cache/TreeCacheViewMBean.java 2007-08-14 19:09:32 UTC (rev 4251)
+++ core/trunk/src-old/org/jboss/cache/TreeCacheViewMBean.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -1,34 +0,0 @@
-/*
- * JBoss, the OpenSource J2EE webOS
- *
- * Distributable under LGPL license.
- * See terms of license at gnu.org.
- */
-package org.jboss.cache;
-
-import org.jboss.cache.jmx.CacheJmxWrapperMBean;
-
-
-/**
- * MBean interface.
- *
- * @author <a href="mailto:bela at jboss.org">Bela Ban</a> March 27 2003
- */
-public interface TreeCacheViewMBean
-{
- void create() throws Exception;
-
- void start() throws Exception;
-
- void stop() ;
-
- void destroy() ;
-
- Cache getCache();
-
- void setCache(Cache cache);
-
- CacheJmxWrapperMBean getCacheService();
-
- void setCacheService(CacheJmxWrapperMBean cache_service);
-}
Deleted: core/trunk/src-old/org/jboss/cache/UnversionedNode.java
===================================================================
--- core/trunk/src-old/org/jboss/cache/UnversionedNode.java 2007-08-14 19:09:32 UTC (rev 4251)
+++ core/trunk/src-old/org/jboss/cache/UnversionedNode.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -1,745 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source
- *
- * Distributable under LGPL license.
- * See terms of license at gnu.org.
- */
-package org.jboss.cache;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.jboss.cache.lock.IdentityLock;
-import org.jboss.cache.marshall.MethodCall;
-import org.jboss.cache.marshall.MethodCallFactory;
-import org.jboss.cache.marshall.MethodDeclarations;
-import org.jboss.cache.optimistic.DataVersion;
-import org.jboss.cache.transaction.GlobalTransaction;
-
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-
-/**
- * Basic data node class. Throws {@link UnsupportedOperationException} for version-specific methods like {@link #getVersion()} and
- * {@link #setVersion(org.jboss.cache.optimistic.DataVersion)}, defined in {@link org.jboss.cache.NodeSPI}.
- *
- * @author Manik Surtani (<a href="mailto:manik at jboss.org">manik at jboss.org</a>)
- * @since 2.0.0
- */
-public class UnversionedNode<K, V> extends AbstractNode<K, V> implements NodeSPI<K, V>
-{
-
- /**
- * Default output indent for printing.
- */
- private static final int INDENT = 4;
-
- /**
- * Debug log.
- */
- private static Log log = LogFactory.getLog(UnversionedNode.class);
-
- /**
- * True if all children have been loaded. This is set when CacheImpl.getChildrenNames() is called.
- */
- private boolean childrenLoaded = false;
-
- /**
- * True if data has been loaded from the cache loader.
- */
- private boolean dataLoaded = true;
-
- /**
- * Lock manager that manages locks to be acquired when accessing the node inside a transaction. Lazy set just in case
- * locking is not needed.
- */
- private transient IdentityLock lock_ = null;
-
- /**
- * A reference of the CacheImpl instance.
- */
- private transient CacheImpl<K, V> cache;
-
- /**
- * Map of general data keys to values.
- */
- private final Map<K, V> data = new HashMap<K, V>();
-
- /**
- * Constructs a new node with an FQN of Root.
- */
- public UnversionedNode()
- {
- this.fqn = Fqn.ROOT;
- }
-
- /**
- * Constructs a new node with a name, etc.
- *
- * @param mapSafe <code>true</code> if param <code>data</code> can safely be directly assigned to this object's
- * {@link #data} field; <code>false</code> if param <code>data</code>'s contents should be copied into
- * this object's {@link #data} field.
- */
- protected UnversionedNode(Object child_name, Fqn fqn, Map<K, V> data, boolean mapSafe, CacheSPI<K, V> cache)
- {
- init(child_name, fqn, cache);
- if (data != null)
- {
- this.data.putAll(data);// ? is this safe
- }
- }
-
- /**
- * Initializes with a name and FQN and cache.
- */
- private void init(Object child_name, Fqn fqn, CacheSPI<K, V> cache)
- {
- if (cache == null)
- {
- throw new IllegalArgumentException("no cache init for " + fqn);
- }
- this.cache = (CacheImpl) cache;
- this.fqn = fqn;
- if (!fqn.isRoot() && !child_name.equals(fqn.getLastElement()))
- {
- throw new IllegalArgumentException("Child " + child_name + " must be last part of " + fqn);
- }
- }
-
- /**
- * Returns a parent by checking the TreeMap by name.
- */
- public NodeSPI<K, V> getParent()
- {
- if (fqn.isRoot())
- {
- return null;
- }
- return cache.peek(fqn.getParent(), true);
- }
-
- private synchronized void initLock()
- {
- if (lock_ == null)
- {
- lock_ = new IdentityLock(cache.getConfiguration().getIsolationLevel(), this);
- }
- }
-
- private synchronized Map<Object, Node<K, V>> children()
- {
- if (children == null)
- {
- if (getFqn().isRoot())
- {
- children = new ConcurrentHashMap<Object, Node<K, V>>(64, .5f, 16);
- }
- else
- {
- // Less segments to save memory
- children = new ConcurrentHashMap<Object, Node<K, V>>(4, .75f, 4);
- }
- }
- return children;
- }
-
- public CacheSPI<K, V> getCache()
- {
- return cache;
- }
-
- public boolean isChildrenLoaded()
- {
- return childrenLoaded;
- }
-
- public void setChildrenLoaded(boolean flag)
- {
- childrenLoaded = flag;
- }
-
- public V get(K key)
- {
- return cache.get(getFqn(), key);
- }
-
- public V getDirect(K key)
- {
- return data == null ? null : data.get(key);
- }
-
-
- private boolean isReadLocked()
- {
- return lock_ != null && lock_.isReadLocked();
- }
-
- private boolean isWriteLocked()
- {
- return lock_ != null && lock_.isWriteLocked();
- }
-
- public IdentityLock getLock()
- {
- initLock();
- return lock_;
- }
-
- public Map<K, V> getData()
- {
- if (cache == null) return Collections.emptyMap();
- return cache.getData(getFqn());
-
-/*
- Map<K, V> dMap = new HashMap<K, V>();
- for (K k : cache.getKeys(getFqn()))
- {
- dMap.put(k, cache.get(fqn, k));
- }
- return Collections.unmodifiableMap(dMap);
-*/
- }
-
- public Map<K, V> getDataDirect()
- {
- if (data == null) return Collections.emptyMap();
- return Collections.unmodifiableMap(data);
- }
-
- public V put(K key, V value)
- {
- return cache.put(getFqn(), key, value);
- }
-
- public V putDirect(K key, V value)
- {
- return data.put(key, value);
- }
-
- public NodeSPI getOrCreateChild(Object child_name, GlobalTransaction gtx)
- {
- return getOrCreateChild(child_name, gtx, true);
- }
-
- private NodeSPI getOrCreateChild(Object child_name, GlobalTransaction gtx, boolean createIfNotExists)
- {
-
- NodeSPI child;
- if (child_name == null)
- {
- throw new IllegalArgumentException("null child name");
- }
-
- child = (NodeSPI) children().get(child_name);
- InvocationContext ctx = cache.getInvocationContext();
- if (createIfNotExists && child == null)
- {
- // construct the new child outside the synchronized block to avoid
- // spending any more time than necessary in the synchronized section
- Fqn child_fqn = new Fqn(this.fqn, child_name);
- NodeSPI newChild = (NodeSPI) cache.getConfiguration().getRuntimeConfig().getNodeFactory().createNode(child_name, this, null);
- if (newChild == null)
- {
- throw new IllegalStateException();
- }
- synchronized (this)
- {
- // check again to see if the child exists
- // after acquiring exclusive lock
- child = (NodeSPI) children().get(child_name);
- if (child == null)
- {
- cache.getNotifier().notifyNodeCreated(child_fqn, true, ctx);
- child = newChild;
- children.put(child_name, child);
- if (gtx != null)
- {
- MethodCall undo_op = MethodCallFactory.create(MethodDeclarations.removeNodeMethodLocal, gtx,
- child_fqn, false);
- cache.addUndoOperation(gtx, undo_op);
- // add the node name to the list maintained for the current tx
- // (needed for abort/rollback of transaction)
- // cache.addNode(gtx, child.getFqn());
- }
- }
- }
-
- // notify if we actually created a new child
- if (newChild == child)
- {
- if (log.isTraceEnabled())
- {
- log.trace("created child: fqn=" + child_fqn);
- }
- cache.getNotifier().notifyNodeCreated(child_fqn, false, ctx);
- }
- }
- return child;
-
- }
-
- public V remove(K key)
- {
- return cache.remove(getFqn(), key);
- }
-
- public V removeDirect(K key)
- {
- if (data == null) return null;
- return data.remove(key);
- }
-
- public void printDetails(StringBuffer sb, int indent)
- {
- printDetailsInMap(sb, indent);
- }
-
- /**
- * Returns a debug string.
- */
- @Override
- public String toString()
- {
- StringBuffer sb = new StringBuffer();
- sb.append(getClass().getSimpleName());
- if (deleted)
- {
- sb.append(" (deleted) [ ").append(fqn);
- }
- else
- {
- sb.append("[ ").append(fqn);
- }
- if (data != null)
- {
- synchronized (data)
- {
- sb.append(" data=").append(data.keySet());
- }
- }
- if (children != null && !children.isEmpty())
- {
- sb.append(" child=").append(getChildrenNamesDirect());
- }
- if (lock_ != null)
- {
- if (isReadLocked())
- {
- sb.append(" RL");
- }
- if (isWriteLocked())
- {
- sb.append(" WL");
- }
- }
- sb.append("]");
- return sb.toString();
- }
-
- public Node<K, V> addChild(Fqn f)
- {
- Fqn nf = new Fqn(getFqn(), f);
- cache.put(nf, null);
- return getChild(f);
- }
-
- public void addChildDirect(NodeSPI<K, V> child)
- {
- if (child.getFqn().getParent().equals(getFqn()))
- {
- synchronized (this)
- {
- children().put(child.getFqn().getLastElement(), child);
- }
- }
- else
- throw new CacheException("Attempting to add a child [" + child.getFqn() + "] to [" + getFqn() + "]. Can only add direct children.");
- }
-
- public NodeSPI<K, V> addChildDirect(Fqn f)
- {
- if (f.size() == 1)
- {
- GlobalTransaction gtx = cache.getInvocationContext().getGlobalTransaction();
- return getOrCreateChild(f.getLastElement(), gtx);
- }
- else
- {
- throw new UnsupportedOperationException("Cannot directly create children which aren't directly under the current node.");
- }
-
- }
-
- public void clearData()
- {
- cache.removeData(getFqn());
- }
-
- public void clearDataDirect()
- {
- if (data != null) data.clear();
- }
-
- public Node<K, V> getChild(Fqn fqn)
- {
- return cache.get(new Fqn(getFqn(), fqn));
- }
-
- public NodeSPI<K, V> getChildDirect(Fqn fqn)
- {
- if (fqn.size() == 1)
- {
- return getChildDirect(fqn.getLastElement());
- }
- else
- {
- NodeSPI currentNode = this;
- for (int i = 0; i < fqn.size(); i++)
- {
- Object nextChildName = fqn.get(i);
- currentNode = currentNode.getChildDirect(nextChildName);
- if (currentNode == null) return null;
- }
- return currentNode;
- }
- }
-
- public Set<Object> getChildrenNames()
- {
- return cache.getChildrenNames(getFqn());
- }
-
- public Set<Object> getChildrenNamesDirect()
- {
- return children == null ? Collections.emptySet() : new HashSet(children.keySet());
- //return childrenNames();
- }
-
- public Set<K> getKeys()
- {
- Set<K> keys = cache.getKeys(getFqn());
- return (Set<K>) (keys == null ? Collections.emptySet() : Collections.unmodifiableSet(keys));
- }
-
- public Set<K> getKeysDirect()
- {
- if (data == null)
- {
- return Collections.emptySet();
- }
- return Collections.unmodifiableSet(new HashSet<K>(data.keySet()));
- }
-
- public boolean hasChild(Fqn f)
- {
- return getChild(f) != null;
- }
-
- public boolean hasChild(Object o)
- {
- return getChild(o) != null;
- }
-
- public V putIfAbsent(K k, V v)
- {
- // make sure this is atomic. Not hugely performant at the moment (should use the locking interceptors) but for now ...
- synchronized (this)
- {
- if (!getKeys().contains(k))
- return put(k, v);
- else
- return get(k);
- }
- }
-
- public V replace(K key, V value)
- {
- // make sure this is atomic. Not hugely performant at the moment (should use the locking interceptors) but for now ...
- synchronized (this)
- {
- if (getKeys().contains(key))
- {
- return put(key, value);
- }
- else
- return null;
- }
- }
-
- public boolean replace(K key, V oldValue, V newValue)
- {
- // make sure this is atomic. Not hugely performant at the moment (should use the locking interceptors) but for now ...
- synchronized (this)
- {
- if (oldValue.equals(get(key)))
- {
- put(key, newValue);
- return true;
- }
- else
- return false;
- }
- }
-
- public boolean removeChild(Fqn fqn)
- {
- return cache.removeNode(new Fqn(getFqn(), fqn));
- }
-
- public int dataSize()
- {
- return cache.getKeys(getFqn()).size();
- }
-
- public boolean removeChild(Object childName)
- {
- return removeChild(new Fqn(getFqn(), childName));
- }
-
- public boolean removeChildDirect(Object childName)
- {
- return children != null && children.remove(childName) != null;
- }
-
- public boolean removeChildDirect(Fqn f)
- {
- if (f.size() == 1)
- {
- return removeChildDirect(f.getLastElement());
- }
- else
- {
- NodeSPI child = getChildDirect(f);
- return child != null && child.getParent().removeChildDirect(f.getLastElement());
- }
- }
-
- public Map<Object, Node<K, V>> getChildrenMapDirect()
- {
- return children;
- }
-
- public void setChildrenMapDirect(Map<Object, Node<K, V>> children)
- {
- this.children().clear();
- this.children.putAll(children);
- }
-
- public void putAll(Map data)
- {
- cache.put(fqn, data);
- }
-
- public void replaceAll(Map data)
- {
- cache.put(fqn, data, true);
- }
-
- public void putAllDirect(Map<K, V> data)
- {
- if (data == null) return;
- this.data.putAll(data);
- }
-
- public void removeChildrenDirect()
- {
- if (children != null)
- {
- children.clear();
- }
- children = null;
- }
-
- public void print(StringBuffer sb, int indent)
- {
- printIndent(sb, indent);
- sb.append(Fqn.SEPARATOR).append(getName()).append(" ").append(getDataDirect().size());
- if (children != null)
- {
- for (Node node : children.values())
- {
- sb.append("\n");
- ((NodeSPI) node).print(sb, indent + INDENT);
- }
- }
- }
-
- // versioning
-
- public void setVersion(DataVersion version)
- {
- throw new UnsupportedOperationException("Versioning not supported");
- }
-
- public DataVersion getVersion()
- {
- throw new UnsupportedOperationException("Versioning not supported");
- }
-
- private void printIndent(StringBuffer sb, int indent)
- {
- if (sb != null)
- {
- for (int i = 0; i < indent; i++)
- {
- sb.append(" ");
- }
- }
- }
-
- public void addChild(Object child_name, Node<K, V> n)
- {
- if (child_name != null)
- {
- children().put(child_name, n);
- }
- }
-
- /**
- * Returns the name of this node.
- */
- private Object getName()
- {
- return fqn.getLastElement();
- }
-
- /**
- * Returns the name of this node.
- */
- public Fqn getFqn()
- {
- return fqn;
- }
-
- public void setFqn(Fqn fqn)
- {
- if (log.isTraceEnabled())
- {
- log.trace(getFqn() + " set FQN " + fqn);
- }
- this.fqn = fqn;
-
- if (children == null)
- {
- return;
- }
-
- // process children
- for (Map.Entry<Object, ? extends Node> me : children.entrySet())
- {
- NodeSPI n = (NodeSPI) me.getValue();
- Fqn cfqn = new Fqn(fqn, me.getKey());
- n.setFqn(cfqn);
- }
- }
-
- public Node<K, V> getChild(Object childName)
- {
- return cache.get(new Fqn(getFqn(), childName));
- }
-
- public NodeSPI<K, V> getChildDirect(Object childName)
- {
- if (childName == null) return null;
- return (NodeSPI<K, V>) (children == null ? null : children.get(childName));
- }
-
- public Set<Node<K, V>> getChildren()
- {
- if (cache == null) return Collections.emptySet();
- Set<Node<K, V>> children = new HashSet<Node<K, V>>();
- for (Object c : cache.getChildrenNames(getFqn()))
- {
- Node n = cache.get(new Fqn(getFqn(), c));
- if (n != null) children.add(n);
- }
- return Collections.unmodifiableSet(children);
- }
-
- public Set<NodeSPI<K, V>> getChildrenDirect()
- {
- // strip out deleted child nodes...
- if (children == null || children.size() == 0) return Collections.emptySet();
-
- Set<NodeSPI<K, V>> exclDeleted = new HashSet<NodeSPI<K, V>>();
- for (Node n : children.values())
- {
- NodeSPI spi = (NodeSPI) n;
- if (!spi.isDeleted()) exclDeleted.add(spi);
- }
- return Collections.unmodifiableSet(exclDeleted);
- }
-
- public boolean hasChildrenDirect()
- {
- return children != null && children.size() != 0;
- }
-
- public Set<NodeSPI<K, V>> getChildrenDirect(boolean includeMarkedForRemoval)
- {
- if (includeMarkedForRemoval)
- {
- if (children != null && !children.isEmpty())
- {
- return Collections.unmodifiableSet(new HashSet(children.values()));
- }
- else
- {
- return Collections.emptySet();
- }
- }
- else
- {
- return getChildrenDirect();
- }
- }
-
- /**
- * Adds details of the node into a map as strings.
- */
- private void printDetailsInMap(StringBuffer sb, int indent)
- {
- printIndent(sb, indent);
- indent += 2;// increse it
- if (!(getFqn()).isRoot())
- {
- sb.append(Fqn.SEPARATOR);
- }
- sb.append(getName());
- sb.append(" ");
- sb.append(data);
- if (children != null)
- {
- for (Node n : children.values())
- {
- sb.append("\n");
- ((NodeSPI) n).printDetails(sb, indent);
- }
- }
- }
-
- /**
- * Returns true if the data was loaded from the cache loader.
- */
- public boolean isDataLoaded()
- {
- return dataLoaded;
- }
-
- /**
- * Sets if the data was loaded from the cache loader.
- */
- public void setDataLoaded(boolean dataLoaded)
- {
- this.dataLoaded = dataLoaded;
- }
-
- public boolean isValid()
- {
- // TODO; implement this property, to detect if it has been evicted, removed by another thread, etc. Method added for now as a dummy so it exists in the API
- return true;
- }
-}
Deleted: core/trunk/src-old/org/jboss/cache/Version.java
===================================================================
--- core/trunk/src-old/org/jboss/cache/Version.java 2007-08-14 19:09:32 UTC (rev 4251)
+++ core/trunk/src-old/org/jboss/cache/Version.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -1,172 +0,0 @@
-package org.jboss.cache;
-
-import java.util.StringTokenizer;
-
-/**
- * Contains version information about this release of JBoss Cache.
- *
- * @author Bela Ban
- * @version $Id$
- */
-public class Version
-{
- public static final String version = "2.0.0.GA";
- public static final String codename = "Habanero";
- public static byte[] version_id = {'0', '2', '0', '0'};
- public static final String cvs = "$Id$";
-
- private static final int MAJOR_SHIFT = 11;
- private static final int MINOR_SHIFT = 6;
- private static final int MAJOR_MASK = 0x00f800;
- private static final int MINOR_MASK = 0x0007c0;
- private static final int PATCH_MASK = 0x00003f;
-
- private static final short SHORT_1_2_3 = encodeVersion(1, 2, 3);
- private static final short SHORT_1_2_4_SP2 = encodeVersion(1, 2, 4);
-
- /**
- * Prints version information.
- */
- public static void main(String[] args)
- {
- System.out.println("\nVersion: \t" + version);
- System.out.println("Codename: \t" + codename);
- System.out.println("CVS: \t" + cvs);
- System.out.println("History: \t(see http://jira.jboss.com/jira/browse/JBCACHE for details)\n");
- }
-
- /**
- * Returns version information as a string.
- */
- public static String printVersion()
- {
- return "JBossCache '" + codename + "' " + version + "[ " + cvs + "]";
- }
-
- public static String printVersionId(byte[] v, int len)
- {
- StringBuffer sb = new StringBuffer();
- if (v != null)
- {
- if (len <= 0)
- len = v.length;
- for (int i = 0; i < len; i++)
- sb.append((char) v[i]);
- }
- return sb.toString();
- }
-
- public static String printVersionId(byte[] v)
- {
- StringBuffer sb = new StringBuffer();
- if (v != null)
- {
- for (byte aV : v) sb.append((char) aV);
- }
- return sb.toString();
- }
-
-
- public static boolean compareTo(byte[] v)
- {
- if (v == null)
- return false;
- if (v.length < version_id.length)
- return false;
- for (int i = 0; i < version_id.length; i++)
- {
- if (version_id[i] != v[i])
- return false;
- }
- return true;
- }
-
- public static int getLength()
- {
- return version_id.length;
- }
-
- public static short getVersionShort()
- {
- return getVersionShort(version);
- }
-
- public static short getVersionShort(String versionString)
- {
- if (versionString == null)
- throw new IllegalArgumentException("versionString is null");
-
- // Special cases for version prior to 1.2.4.SP2
- if ("1.2.4".equals(versionString))
- return 124;
- else if ("1.2.4.SP1".equals(versionString))
- return 1241;
-
- StringTokenizer tokenizer = new StringTokenizer(versionString, ".");
-
- int major = 0;
- int minor = 0;
- int patch = 0;
-
- if (tokenizer.hasMoreTokens())
- major = Integer.parseInt(tokenizer.nextToken());
- if (tokenizer.hasMoreTokens())
- minor = Integer.parseInt(tokenizer.nextToken());
- if (tokenizer.hasMoreTokens())
- patch = Integer.parseInt(tokenizer.nextToken());
-
- return encodeVersion(major, minor, patch);
- }
-
- public static String getVersionString(short versionShort)
- {
- if (versionShort == SHORT_1_2_4_SP2)
- return "1.2.4.SP2";
-
- switch (versionShort)
- {
- case 124:
- return "1.2.4";
- case 1241:
- return "1.2.4.SP1";
- default:
- return decodeVersion(versionShort);
- }
- }
-
- public static short encodeVersion(int major, int minor, int patch)
- {
- short version = (short) ((major << MAJOR_SHIFT)
- + (minor << MINOR_SHIFT)
- + patch);
- return version;
- }
-
- public static String decodeVersion(short version)
- {
- int major = (version & MAJOR_MASK) >> MAJOR_SHIFT;
- int minor = (version & MINOR_MASK) >> MINOR_SHIFT;
- int patch = (version & PATCH_MASK);
- String versionString = major + "." + minor + "." + patch;
- return versionString;
- }
-
- public static boolean isBefore124(short version)
- {
- return (version > 1241 && version <= SHORT_1_2_3);
- }
-
- /**
- * Retroweaver version info.
- */
- public static class Retro
- {
- public static void main(String[] args)
- {
- System.out.println("\nVersion: \t" + version + " (Retroweaved for JDK 1.4.x compatibility)");
- System.out.println("Codename: \t" + codename);
- System.out.println("CVS: \t" + cvs);
- System.out.println("History: \t(see http://jira.jboss.com/jira/browse/JBCACHE for details)\n");
- }
- }
-}
Deleted: core/trunk/src-old/org/jboss/cache/VersionedNode.java
===================================================================
--- core/trunk/src-old/org/jboss/cache/VersionedNode.java 2007-08-14 19:09:32 UTC (rev 4251)
+++ core/trunk/src-old/org/jboss/cache/VersionedNode.java 2007-08-14 22:38:44 UTC (rev 4252)
@@ -1,73 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source
- *
- * Distributable under LGPL license.
- * See terms of license at gnu.org.
- */
-package org.jboss.cache;
-
-import org.jboss.cache.optimistic.DataVersion;
-import org.jboss.cache.optimistic.DefaultDataVersion;
-
-import java.util.Map;
-
-/**
- * VersionedNode extends the {@link org.jboss.cache.UnversionedNode} by adding a {@link org.jboss.cache.optimistic.DataVersion} property.
- * <p/>
- * Unlike {@link org.jboss.cache.UnversionedNode}, this node supports {@link #getVersion} and {@link #setVersion(org.jboss.cache.optimistic.DataVersion)}
- * defined in {@link org.jboss.cache.NodeSPI}
- * <p/>
- * Typically used when the cache mode configured is {@link org.jboss.cache.config.Configuration.NodeLockingScheme#OPTIMISTIC}
- *
- * @author <a href="mailto:manik at jboss.org">Manik Surtani (manik at jboss.org)</a>
- * @since 2.0.0
- */
-public class VersionedNode<K, V> extends UnversionedNode<K, V>
-{
- private DataVersion version;
- /**
- * Although this object has a reference to the CacheImpl, the optimistic
- * node is actually disconnected from the CacheImpl itself.
- * The parent could be looked up from the TransactionWorkspace.
- */
- private NodeSPI<K, V> parent;
-
- protected VersionedNode(Fqn fqn, NodeSPI<K, V> parent, Map<K, V> data, CacheSPI<K, V> cache)
- {
- super(fqn.getLastElement(), fqn, data, false, cache);
- if (parent == null && !fqn.isRoot()) throw new NullPointerException("parent");
- this.parent = parent;
- this.version = DefaultDataVersion.ZERO;
- }
-
- /**
- * Returns the version id of this node.
- *
- * @return the version
- */
- @Override
- public DataVersion getVersion()
- {
- return version;
- }
-
- /**
- * Returns the parent.
- */
- @Override
- public NodeSPI<K, V> getParent()
- {
- return parent;
- }
-
- /**
- * Sets the version id of this node.
- *
- * @param version
- */
- @Override
- public void setVersion(DataVersion version)
- {
- this.version = version;
- }
-}
More information about the jbosscache-commits
mailing list