[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