[jbosscache-commits] JBoss Cache SVN: r5850 - in core/trunk/src: main/java/org/jboss/cache/buddyreplication and 15 other directories.

jbosscache-commits at lists.jboss.org jbosscache-commits at lists.jboss.org
Thu May 15 08:44:50 EDT 2008


Author: mircea.markus
Date: 2008-05-15 08:44:49 -0400 (Thu, 15 May 2008)
New Revision: 5850

Added:
   core/trunk/src/main/java/org/jboss/cache/DataContainer.java
   core/trunk/src/main/java/org/jboss/cache/DataContainerImpl.java
   core/trunk/src/main/java/org/jboss/cache/notifications/Notifier.java
   core/trunk/src/main/java/org/jboss/cache/notifications/NotifierImpl.java
   core/trunk/src/test/java/org/jboss/cache/commands/
   core/trunk/src/test/java/org/jboss/cache/commands/read/
   core/trunk/src/test/java/org/jboss/cache/commands/read/AbstractDataCommandTest.java
   core/trunk/src/test/java/org/jboss/cache/commands/read/ExistsCommandTest.java
   core/trunk/src/test/java/org/jboss/cache/commands/read/GetChildrenNamesCommandTest.java
   core/trunk/src/test/java/org/jboss/cache/commands/read/GetDataMapCommandTest.java
   core/trunk/src/test/java/org/jboss/cache/commands/read/GetKeyValueCommandTest.java
   core/trunk/src/test/java/org/jboss/cache/commands/read/GetKeysCommandTest.java
   core/trunk/src/test/java/org/jboss/cache/commands/read/GravitateDataCommandTest.java
   core/trunk/src/test/java/org/jboss/cache/mock/MockNodesFixture.java
Removed:
   core/trunk/src/main/java/org/jboss/cache/DataContainer.java
   core/trunk/src/main/java/org/jboss/cache/notifications/Notifier.java
Modified:
   core/trunk/src/main/java/org/jboss/cache/CacheSPI.java
   core/trunk/src/main/java/org/jboss/cache/RPCManagerImpl.java
   core/trunk/src/main/java/org/jboss/cache/buddyreplication/BuddyManager.java
   core/trunk/src/main/java/org/jboss/cache/buddyreplication/GravitateResult.java
   core/trunk/src/main/java/org/jboss/cache/commands/read/ExistsCommand.java
   core/trunk/src/main/java/org/jboss/cache/commands/read/GetChildrenNamesCommand.java
   core/trunk/src/main/java/org/jboss/cache/commands/read/GetDataMapCommand.java
   core/trunk/src/main/java/org/jboss/cache/commands/read/GetKeyValueCommand.java
   core/trunk/src/main/java/org/jboss/cache/commands/read/GetKeysCommand.java
   core/trunk/src/main/java/org/jboss/cache/commands/read/GravitateDataCommand.java
   core/trunk/src/main/java/org/jboss/cache/commands/remote/ClusteredGetCommand.java
   core/trunk/src/main/java/org/jboss/cache/commands/remote/DataGravitationCleanupCommand.java
   core/trunk/src/main/java/org/jboss/cache/commands/write/AbstractVersionedDataCommand.java
   core/trunk/src/main/java/org/jboss/cache/commands/write/MoveCommand.java
   core/trunk/src/main/java/org/jboss/cache/factories/CommandsFactory.java
   core/trunk/src/main/java/org/jboss/cache/factories/EmptyConstructorFactory.java
   core/trunk/src/main/java/org/jboss/cache/interceptors/CacheLoaderInterceptor.java
   core/trunk/src/main/java/org/jboss/cache/interceptors/CacheMgmtInterceptor.java
   core/trunk/src/main/java/org/jboss/cache/interceptors/CacheStoreInterceptor.java
   core/trunk/src/main/java/org/jboss/cache/interceptors/DataGravitatorInterceptor.java
   core/trunk/src/main/java/org/jboss/cache/interceptors/EvictionInterceptor.java
   core/trunk/src/main/java/org/jboss/cache/interceptors/NotificationInterceptor.java
   core/trunk/src/main/java/org/jboss/cache/interceptors/OptimisticCreateIfNotExistsInterceptor.java
   core/trunk/src/main/java/org/jboss/cache/interceptors/OptimisticNodeInterceptor.java
   core/trunk/src/main/java/org/jboss/cache/interceptors/OptimisticValidatorInterceptor.java
   core/trunk/src/main/java/org/jboss/cache/interceptors/PassivationInterceptor.java
   core/trunk/src/main/java/org/jboss/cache/interceptors/PessimisticLockInterceptor.java
   core/trunk/src/main/java/org/jboss/cache/interceptors/TxInterceptor.java
   core/trunk/src/main/java/org/jboss/cache/invocation/CacheInvocationDelegate.java
   core/trunk/src/main/java/org/jboss/cache/lock/LockManager.java
   core/trunk/src/main/java/org/jboss/cache/util/CachePrinter.java
   core/trunk/src/test/java/org/jboss/cache/DataContainerTest.java
   core/trunk/src/test/java/org/jboss/cache/marshall/ReturnValueMarshallingTest.java
   core/trunk/src/test/java/org/jboss/cache/notifications/AnnotationsTest.java
   core/trunk/src/test/java/org/jboss/cache/notifications/RemoteCacheListenerTest.java
Log:
JBCACHE-1338 - added unit tests for read commands

Modified: core/trunk/src/main/java/org/jboss/cache/CacheSPI.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/CacheSPI.java	2008-05-14 17:05:33 UTC (rev 5849)
+++ core/trunk/src/main/java/org/jboss/cache/CacheSPI.java	2008-05-15 12:44:49 UTC (rev 5850)
@@ -13,7 +13,7 @@
 import org.jboss.cache.loader.CacheLoader;
 import org.jboss.cache.loader.CacheLoaderManager;
 import org.jboss.cache.marshall.Marshaller;
-import org.jboss.cache.notifications.Notifier;
+import org.jboss.cache.notifications.NotifierImpl;
 import org.jboss.cache.statetransfer.StateTransferManager;
 import org.jboss.cache.transaction.GlobalTransaction;
 import org.jboss.cache.transaction.TransactionTable;
@@ -204,10 +204,10 @@
     * From 2.1.0, Interceptor authors should obtain this by injection rather than this method.  See the
     * {@link org.jboss.cache.factories.annotations.Inject} annotation.
     *
-    * @return the notifier attached with this instance of the cache.  See {@link Notifier}, a class
+    * @return the notifier attached with this instance of the cache.  See {@link org.jboss.cache.notifications.NotifierImpl}, a class
     *         that is responsible for emitting notifications to registered CacheListeners.
     */
-   Notifier getNotifier();
+   NotifierImpl getNotifier();
 
    /**
     * @return the name of the cluster.  Null if running in local mode.

Deleted: core/trunk/src/main/java/org/jboss/cache/DataContainer.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/DataContainer.java	2008-05-14 17:05:33 UTC (rev 5849)
+++ core/trunk/src/main/java/org/jboss/cache/DataContainer.java	2008-05-15 12:44:49 UTC (rev 5850)
@@ -1,659 +0,0 @@
-package org.jboss.cache;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.jboss.cache.buddyreplication.BuddyFqnTransformer;
-import org.jboss.cache.buddyreplication.BuddyManager;
-import org.jboss.cache.config.Configuration;
-import org.jboss.cache.factories.annotations.Inject;
-import org.jboss.cache.factories.annotations.NonVolatile;
-import org.jboss.cache.factories.annotations.Start;
-import org.jboss.cache.factories.annotations.Stop;
-import org.jboss.cache.invocation.NodeInvocationDelegate;
-import org.jboss.cache.marshall.NodeData;
-import org.jboss.cache.optimistic.DataVersion;
-import org.jboss.cache.transaction.GlobalTransaction;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * A container for the root node in the cache, which also provides helpers for efficiently accessing nodes, walking trees, etc.
- *
- * @author Mircea.Markus at jboss.com
- * @since 2.2
- */
- at NonVolatile
-public class DataContainer
-{
-   private static final Log log = LogFactory.getLog(DataContainer.class);
-   private static boolean trace = log.isTraceEnabled();
-
-   private Configuration configuration;
-
-   /**
-    * Root node.
-    */
-   private NodeSPI root;
-
-   /**
-    * Set<Fqn> of Fqns of the topmost node of internal regions that should
-    * not included in standard state transfers.
-    */
-   private final Set<Fqn> internalFqns = new HashSet<Fqn>();
-   private NodeFactory nodeFactory;
-
-   @Inject
-   public void injectDependencies(Configuration configuration, NodeFactory nodeFactory)
-   {
-      setDependencies(configuration, nodeFactory);
-
-      // We need to create a root node even at this stage since certain components rely on this being available before
-      // start() is called.
-      // TODO: Investigate which components rely on this being available before start(), and why!
-      //TODO - remove setDependencies method at this point
-      createRootNode();
-   }
-
-   public void setDependencies(Configuration configuration, NodeFactory nodeFactory)
-   {
-      this.configuration = configuration;
-      this.nodeFactory = nodeFactory;
-   }
-
-   @Start(priority = 12)
-   public void createRootNode()
-   {
-      if (trace) log.trace("Starting data container");
-      // create a new root temporarily.
-      NodeSPI tempRoot = nodeFactory.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.
-
-      Class currentRootType = root == null ? null : ((NodeInvocationDelegate) root).getDelegationTarget().getClass();
-      Class tempRootType = ((NodeInvocationDelegate) tempRoot).getDelegationTarget().getClass();
-
-      if (!tempRootType.equals(currentRootType))
-      {
-         if (trace) log.trace("Setting root node to an instance of " + tempRootType);
-         setRoot(tempRoot);
-      }
-   }
-
-   @Stop(priority = 100)
-   public void stop()
-   {
-      // empty in-memory state
-      root.clearDataDirect();
-      root.removeChildrenDirect();
-   }
-
-   /**
-    * Retrieves the root node.
-    *
-    * @return the root node
-    */
-   public NodeSPI getRoot()
-   {
-      return root;
-   }
-
-   /**
-    * Sets the root node reference to the node passed in.
-    *
-    * @param root node
-    */
-   public void setRoot(NodeSPI root)
-   {
-      if (root == null || !root.getFqn().isRoot())
-         throw new CacheException("Attempting to set an invalid node [" + root + "] as a root node!");
-      this.root = root;
-   }
-
-   /**
-    * Adds the specified Fqn to the list of Fqns to be considered "internal".
-    *
-    * @param fqn fqn to add to list
-    */
-   public void registerInternalFqn(Fqn fqn)
-   {
-      internalFqns.add(fqn);
-   }
-
-   /**
-    * Finds a node given a fully qualified name, directly off the interceptor chain.  In the event of an exception,
-    * returns null.  Does not include invalid or deleted nodes.
-    *
-    * @param fqn Fully qualified name for the corresponding node.
-    * @return Node referenced by the given Fqn, or null if the node cannot be found or if there is an exception.
-    */
-   public NodeSPI peek(Fqn fqn)
-   {
-      try
-      {
-         return peekVersioned(fqn, null);
-      }
-      catch (CacheException e)
-      {
-         log.warn("Unexpected error", e);
-         return null;
-      }
-   }
-
-   /**
-    * Finds a node given a fully qualified name and DataVersion.  Does not include invalid or deleted nodes.  If the data
-    * version passed in is null, then data version checking is skipped.  Data version checking is also skipped if optimistic
-    * locking is not used.
-    *
-    * @param fqn     fqn to find
-    * @param version version of the node to find
-    * @return a node, if found, or null if not.
-    */
-   public NodeSPI peekVersioned(Fqn fqn, DataVersion version)
-   {
-      return peekVersioned(fqn, version, false);
-   }
-
-   /**
-    * Similar to {@link #peekVersioned(Fqn, org.jboss.cache.optimistic.DataVersion)} except that it throws a {@link org.jboss.cache.NodeNotExistsException}
-    * if the node cannot be found.
-    *
-    * @param gtx            global transaction
-    * @param fqn            fqn to find
-    * @param includeInvalid if true, invalid nodes are considered as well.
-    * @return the node
-    */
-   public NodeSPI peekStrict(GlobalTransaction gtx, Fqn fqn, boolean includeInvalid)
-   {
-      NodeSPI n = peekVersioned(fqn, null, includeInvalid);
-      if (n == null)
-      {
-         StringBuilder builder = new StringBuilder();
-         builder.append("Node ").append(fqn).append(" not found (gtx=").append(gtx).append(")");
-         String errStr = builder.toString();
-         if (trace) log.trace(errStr);
-         throw new NodeNotExistsException(errStr);
-      }
-      return n;
-   }
-
-   /**
-    * Searches for a specific node, with a specific data version and, optionally, invalid nodes as well, but not
-    * deleted nodes.  If the data version passed in is null, then data version checking is skipped.  Data version
-    * checking is also skipped if optimistic locking is not used.
-    *
-    * @param fqn                 Fqn to find
-    * @param version             version of the node to find
-    * @param includeInvalidNodes if true, invalid nodes are considered
-    * @return the node, if found, or null otherwise.
-    */
-   public NodeSPI peekVersioned(Fqn fqn, DataVersion version, boolean includeInvalidNodes)
-   {
-      if (fqn == null) return null;
-
-      NodeSPI toReturn = peek(fqn, false, includeInvalidNodes);
-
-      if (toReturn != null && version != null && configuration.isNodeLockingOptimistic())
-      {
-         // we need to check the version of the data node...
-         DataVersion nodeVersion = toReturn.getVersion();
-         if (trace)
-         {
-            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;
-   }
-
-   /**
-    * Same as calling <tt>peek(fqn, includeDeletedNodes, false)</tt>.
-    *
-    * @param fqn                 Fqn to find
-    * @param includeDeletedNodes if true, deleted nodes are considered
-    * @return the node, if found, or null otherwise.
-    */
-   public NodeSPI peek(Fqn<?> fqn, boolean includeDeletedNodes)
-   {
-      return peek(fqn, includeDeletedNodes, false);
-   }
-
-   /**
-    * Peeks for a specified node.  This involves a direct walk of the tree, starting at the root, until the required node
-    * is found.  If the node is not found, a null is returned.
-    *
-    * @param fqn                 Fqn of the node to find
-    * @param includeDeletedNodes if true, deleted nodes are also considered
-    * @param includeInvalidNodes if true, invalid nodes are also considered
-    * @return the node, if found, or null otherwise.
-    */
-   public NodeSPI peek(Fqn<?> fqn, boolean includeDeletedNodes, boolean includeInvalidNodes)
-   {
-      if (fqn == null || fqn.size() == 0) return getRoot();
-      NodeSPI n = getRoot();
-      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;
-         }
-         else if (!includeInvalidNodes && !n.isValid())
-         {
-            return null;
-         }
-      }
-      return n;
-   }
-
-   /**
-    * Tests if an Fqn exists and is valid and not deleted.
-    *
-    * @param fqn the fqn representing the node to test
-    * @return true if the node exists, false otherwise.
-    */
-   public boolean exists(Fqn fqn)
-   {
-      return peek(fqn, false, false) != null;
-   }
-
-   /**
-    * Returns true if the Fqn exists, is valid and is not deleted, and the node has children.
-    *
-    * @param fqn the fqn to test
-    * @return true if the Fqn exists, is valid and is not deleted, and the node has children.
-    */
-   public boolean hasChildren(Fqn fqn)
-   {
-      if (fqn == null) return false;
-
-      NodeSPI n = peek(fqn);
-      return n != null && n.hasChildrenDirect();
-   }
-
-   /**
-    * Prepares a list of {@link NodeData} objects for a specified node and all its children.
-    *
-    * @param list List of NodeData objects, which will be added to.
-    * @param node node to recursively add to the list
-    * @return the same list passed in
-    */
-   public List<NodeData> buildNodeData(List<NodeData> list, NodeSPI node)
-   {
-      NodeData data = new NodeData(BuddyFqnTransformer.getActualFqn(node.getFqn()), node.getDataDirect());
-      list.add(data);
-      for (Object childNode : node.getChildrenDirect())
-      {
-         buildNodeData(list, (NodeSPI) childNode);
-      }
-      return list;
-   }
-
-   /**
-    * Generates a list of nodes for eviction.  This filters out nodes that cannot be evicted, such as those which are
-    * marked as resident.  See {@link NodeSPI#setResident(boolean)}.
-    *
-    * @param fqn       the node to consider for eviction
-    * @param recursive if recursive, child nodes are also considered
-    * @return a list of Fqns that can be considered for eviction
-    */
-   public List<Fqn> getNodesForEviction(Fqn fqn, boolean recursive)
-   {
-      List<Fqn> result = new ArrayList<Fqn>();
-      NodeSPI node = peek(fqn, false);
-      if (recursive)
-      {
-         recursiveAddEvictionNodes(node, result);
-      }
-      else
-      {
-         if (node == null)
-         {
-            result.add(fqn);
-            return result;
-         }
-         if (fqn.isRoot())
-         {
-            for (Object childName : node.getChildrenNamesDirect())
-            {
-               if (!node.isResident()) result.add(Fqn.fromRelativeElements(fqn, childName));
-            }
-         }
-         else if (!node.isResident())
-         {
-            result.add(fqn);
-         }
-      }
-      return result;
-   }
-
-   private void recursiveAddEvictionNodes(NodeSPI node, List<Fqn> result)
-   {
-      for (NodeSPI child : (Set<NodeSPI>) node.getChildrenDirect())
-      {
-         recursiveAddEvictionNodes(child, result);
-      }
-      Fqn fqn = node.getFqn();
-      if (node != null && !fqn.isRoot() && !node.isResident())
-      {
-         result.add(fqn);
-      }
-   }
-
-   @Override
-   public String toString()
-   {
-      return toString(false);
-   }
-
-   /**
-    * 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);
-   }
-
-   /**
-    * Returns a debug string with optional details of contents.
-    */
-   @SuppressWarnings("deprecation")
-   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 (Object n : root.getChildrenDirect())
-         {
-            ((NodeSPI) n).print(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 n)
-   {
-      int num = 0;
-      if (n != null)
-      {
-         if (n.getLock().isLocked())
-         {
-            num++;
-         }
-         for (Object cn : n.getChildrenDirect(true))
-         {
-            num += numLocks((NodeSPI) 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 n)
-   {
-      int count = 1;// for n
-      if (n != null)
-      {
-         for (Object child : n.getChildrenDirect())
-         {
-            count += numNodes((NodeSPI) child);
-         }
-      }
-      return count;
-   }
-
-   /**
-    * 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 (Object n : root.getChildrenDirect())
-      {
-         ((NodeSPI) n).getLock().printLockInfo(sb, indent);
-         sb.append("\n");
-      }
-      return sb.toString();
-   }
-
-   /**
-    * Returns an <em>approximation</em> of the total number of attributes in
-    * this sub cache.
-    *
-    * @see #getNumberOfAttributes
-    */
-   public int getNumberOfAttributes(Fqn fqn)
-   {
-      return numAttributes(peek(fqn));
-   }
-
-   private int numAttributes(NodeSPI n)
-   {
-      int count = 0;
-      for (Object child : n.getChildrenDirect())
-      {
-         count += numAttributes((NodeSPI) child);
-      }
-      count += n.getDataDirect().size();
-      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);
-   }
-
-   /**
-    * Removes the actual node from the tree data structure.
-    *
-    * @param f               the Fqn of the node to remove
-    * @param skipMarkerCheck if true, skips checking the boolean {@link org.jboss.cache.NodeSPI#isDeleted()} flag and deletes the node anyway.
-    * @return Returns true if the node was found and removed, false if not.
-    */
-   public boolean removeFromDataStructure(Fqn f, boolean skipMarkerCheck)
-   {
-      NodeSPI n = peek(f, true);
-      if (n == null)
-      {
-         return false;
-      }
-
-      if (trace) 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);
-
-            // mark the node to be removed (and all children) as invalid so anyone holding a direct reference to it will
-            // be aware that it is no longer valid.
-            n.setValid(false, true);
-            n.setValid(true, false);
-
-            // but now remove all children, since the call has been to remove("/")
-            n.removeChildrenDirect();
-            return true;
-         }
-         else
-         {
-            // mark the node to be removed (and all children) as invalid so anyone holding a direct reference to it will
-            // be aware that it is no longer valid.
-            n.setValid(false, true);
-            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;
-      }
-   }
-
-   public void evict(Fqn fqn, boolean recursive)
-   {
-      List<Fqn> toEvict = getNodesForEviction(fqn, recursive);
-      for (Fqn aFqn : toEvict)
-      {
-         evict(aFqn);
-      }
-   }
-
-   /**
-    * @return true if the FQN is leaf and was removed; false if is an intermediate FQN and only contained data
-    *         is droped.
-    */
-   public boolean evict(Fqn fqn)
-   {
-      if (peek(fqn, false, true) == null) return true;
-      if (hasChildren(fqn))
-      {
-         if (trace)
-            log.trace("removing DATA as node has children: evict(" + fqn + ")");
-         removeData(fqn);
-         return false;
-      }
-      else
-      {
-         if (trace) log.trace("removing NODE as it is a leaf: evict(" + fqn + ")");
-         removeNode(fqn);
-         return true;
-      }
-   }
-
-   private void removeNode(Fqn fqn)
-   {
-      NodeSPI targetNode = peekVersioned(fqn, null, true);
-      if (targetNode == null) return;
-      NodeSPI parentNode = targetNode.getParent();
-      targetNode.setValid(false, false);
-      if (parentNode != null)
-      {
-         parentNode.removeChildDirect(fqn.getLastElement());
-         parentNode.setChildrenLoaded(false);
-      }
-   }
-
-   protected void removeData(Fqn fqn)
-   {
-      NodeSPI n = peekVersioned(fqn, null);
-      if (n == null)
-      {
-         log.warn("node " + fqn + " not found");
-         return;
-      }
-      n.clearDataDirect();
-      n.setDataLoaded(false);
-   }
-
-   /**
-    * Traverses the tree to the given Fqn, creating nodes if needed.  Returns a list of nodes created, as well as a reference to the last node.
-    * <p/>
-    * E.g.,
-    * <code>
-    * Object[] results = createNode(myFqn);
-    * results[0] // this is a List&lt;NodeSPI&gt; of nodes <i>created</i> in getting to the target node.
-    * results[1] // is a NodeSPI reference to the target node, regardless of whether it was <i>created</i> or just <i>found</i>.
-    * </code>
-    *
-    * @param fqn fqn to find
-    * @return see above.
-    */
-   public Object[] createNodes(Fqn fqn)
-   {
-      List<NodeSPI> result = new ArrayList<NodeSPI>(fqn.size());
-      Fqn tmpFqn = Fqn.ROOT;
-
-      int size = fqn.size();
-
-      // root node
-      NodeSPI n = root;
-      for (int i = 0; i < size; i++)
-      {
-         Object childName = fqn.get(i);
-         tmpFqn = Fqn.fromRelativeElements(tmpFqn, childName);
-
-         NodeSPI childNode;
-         Map children = n.getChildrenMapDirect();
-         childNode = children == null ? null : (NodeSPI) children.get(childName);
-
-         if (childNode == null)
-         {
-            childNode = n.addChildDirect(Fqn.fromElements(childName));
-            result.add(childNode);
-         }
-
-         n = childNode;
-      }
-      return new Object[]{result, n};
-   }
-}

Added: core/trunk/src/main/java/org/jboss/cache/DataContainer.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/DataContainer.java	                        (rev 0)
+++ core/trunk/src/main/java/org/jboss/cache/DataContainer.java	2008-05-15 12:44:49 UTC (rev 5850)
@@ -0,0 +1,201 @@
+package org.jboss.cache;
+
+import org.jboss.cache.optimistic.DataVersion;
+import org.jboss.cache.transaction.GlobalTransaction;
+import org.jboss.cache.marshall.NodeData;
+
+import java.util.List;
+import java.util.Set;
+
+/**
+ * This class defines the functionality needed for node manipulation.
+ *
+ * @author Mircea.Markus at jboss.com
+ * @see org.jboss.cache.DataConatainerImpl
+ * @since 2.2
+ */
+public interface DataContainer
+{
+   /**
+    * Retrieves the root node.
+    *
+    * @return the root node
+    */
+   NodeSPI getRoot();
+
+   /**
+    * Adds the specified Fqn to the list of Fqns to be considered "internal".
+    *
+    * @param fqn fqn to add to list
+    */
+   void registerInternalFqn(Fqn fqn);
+
+   /**
+    * Finds a node given a fully qualified name, directly off the interceptor chain.  In the event of an exception,
+    * returns null.  Does not include invalid or deleted nodes.
+    *
+    * @param fqn Fully qualified name for the corresponding node.
+    * @return Node referenced by the given Fqn, or null if the node cannot be found or if there is an exception.
+    */
+   NodeSPI peek(Fqn fqn);
+
+   /**
+    * Finds a node given a fully qualified name and DataVersion.  Does not include invalid or deleted nodes.  If the data
+    * version passed in is null, then data version checking is skipped.  Data version checking is also skipped if optimistic
+    * locking is not used.
+    *
+    * @param fqn     fqn to find
+    * @param version version of the node to find
+    * @return a node, if found, or null if not.
+    */
+   NodeSPI peekVersioned(Fqn fqn, DataVersion version);
+
+   /**
+    * Similar to {@link #peekVersioned(Fqn, org.jboss.cache.optimistic.DataVersion)} except that it throws a {@link org.jboss.cache.NodeNotExistsException}
+    * if the node cannot be found.
+    *
+    * @param gtx            global transaction
+    * @param fqn            fqn to find
+    * @param includeInvalid if true, invalid nodes are considered as well.
+    * @return the node
+    */
+   NodeSPI peekStrict(GlobalTransaction gtx, Fqn fqn, boolean includeInvalid);
+
+   /**
+    * Searches for a specific node, with a specific data version and, optionally, invalid nodes as well, but not
+    * deleted nodes.  If the data version passed in is null, then data version checking is skipped.  Data version
+    * checking is also skipped if optimistic locking is not used.
+    *
+    * @param fqn                 Fqn to find
+    * @param version             version of the node to find
+    * @param includeInvalidNodes if true, invalid nodes are considered
+    * @return the node, if found, or null otherwise.
+    */
+   NodeSPI peekVersioned(Fqn fqn, DataVersion version, boolean includeInvalidNodes);
+
+   /**
+    * Same as calling <tt>peek(fqn, includeDeletedNodes, false)</tt>.
+    *
+    * @param fqn                 Fqn to find
+    * @param includeDeletedNodes if true, deleted nodes are considered
+    * @return the node, if found, or null otherwise.
+    */
+   NodeSPI peek(Fqn<?> fqn, boolean includeDeletedNodes);
+
+   /**
+    * Peeks for a specified node.  This involves a direct walk of the tree, starting at the root, until the required node
+    * is found.  If the node is not found, a null is returned.
+    *
+    * @param fqn                 Fqn of the node to find
+    * @param includeDeletedNodes if true, deleted nodes are also considered
+    * @param includeInvalidNodes if true, invalid nodes are also considered
+    * @return the node, if found, or null otherwise.
+    */
+   NodeSPI peek(Fqn<?> fqn, boolean includeDeletedNodes, boolean includeInvalidNodes);
+
+   /**
+    * Tests if an Fqn exists and is valid and not deleted.
+    *
+    * @param fqn the fqn representing the node to test
+    * @return true if the node exists, false otherwise.
+    */
+   boolean exists(Fqn fqn);
+
+   /**
+    * Returns true if the Fqn exists, is valid and is not deleted, and the node has children.
+    *
+    * @param fqn the fqn to test
+    * @return true if the Fqn exists, is valid and is not deleted, and the node has children.
+    */
+   boolean hasChildren(Fqn fqn);
+
+   /**
+    * Prepares a list of {@link NodeData} objects for a specified node and all its children.
+    *
+    * @param list List of NodeData objects, which will be added to.
+    * @param node node to recursively add to the list
+    * @return the same list passed in
+    */
+   List<NodeData> buildNodeData(List<NodeData> list, NodeSPI node);
+
+   /**
+    * Generates a list of nodes for eviction.  This filters out nodes that cannot be evicted, such as those which are
+    * marked as resident.  See {@link NodeSPI#setResident(boolean)}.
+    *
+    * @param fqn       the node to consider for eviction
+    * @param recursive if recursive, child nodes are also considered
+    * @return a list of Fqns that can be considered for eviction
+    */
+   List<Fqn> getNodesForEviction(Fqn fqn, boolean recursive);
+
+   /**
+    * Returns a Set<Fqn> of Fqns of the topmost node of internal regions that
+    * should not included in standard state transfers. Will include
+    * {@link org.jboss.cache.buddyreplication.BuddyManager#BUDDY_BACKUP_SUBTREE} if buddy replication is
+    * enabled.
+    *
+    * @return an unmodifiable Set<Fqn>.  Will not return <code>null</code>.
+    */
+   Set<Fqn> getInternalFqns();
+
+   /**
+    * Returns the number of read or write locks held across the entire cache.
+    */
+   int getNumberOfLocksHeld();
+
+   /**
+    * 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
+    */
+   int getNumberOfNodes();
+
+   /**
+    * Returns an <em>approximation</em> of the total number of attributes in
+    * this sub cache.
+    */
+   int getNumberOfAttributes(Fqn fqn);
+
+   /**
+    * Removes the actual node from the tree data structure.
+    *
+    * @param f               the Fqn of the node to remove
+    * @param skipMarkerCheck if true, skips checking the boolean {@link org.jboss.cache.NodeSPI#isDeleted()} flag and deletes the node anyway.
+    * @return Returns true if the node was found and removed, false if not.
+    */
+   boolean removeFromDataStructure(Fqn f, boolean skipMarkerCheck);
+
+   /**
+    * Evicts the given node. If recursive is set to true then all child nodes are recusively evicted.
+    */
+   void evict(Fqn fqn, boolean recursive);
+
+   /**
+    * <pre>
+    * Following scenarios define how eviction works.
+    * 1. If the given node is a leaf then it is entirely removed from the data structure. The node is marked as invalid.</li>
+    * 2. If the given node is a leaf then only the data map is cleared.
+    * 3. If the given node is the root node then the cildren nodes are evicted. For each child node 1. or 2. applies
+    * </pre>
+    *
+    * @return true if the FQN is leaf and was removed; false if is an intermediate FQN and only contained data
+    *         is droped.
+    */
+   boolean evict(Fqn fqn);
+
+   /**
+    * Traverses the tree to the given Fqn, creating nodes if needed.  Returns a list of nodes created, as well as a reference to the last node.
+    * <p/>
+    * E.g.,
+    * <code>
+    * Object[] results = createNode(myFqn);
+    * results[0] // this is a List&lt;NodeSPI&gt; of nodes <i>created</i> in getting to the target node.
+    * results[1] // is a NodeSPI reference to the target node, regardless of whether it was <i>created</i> or just <i>found</i>.
+    * </code>
+    *
+    * @param fqn fqn to find
+    * @return see above.
+    */
+   Object[] createNodes(Fqn fqn);
+}

Copied: core/trunk/src/main/java/org/jboss/cache/DataContainerImpl.java (from rev 5848, core/trunk/src/main/java/org/jboss/cache/DataContainer.java)
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/DataContainerImpl.java	                        (rev 0)
+++ core/trunk/src/main/java/org/jboss/cache/DataContainerImpl.java	2008-05-15 12:44:49 UTC (rev 5850)
@@ -0,0 +1,530 @@
+package org.jboss.cache;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.jboss.cache.buddyreplication.BuddyFqnTransformer;
+import org.jboss.cache.config.Configuration;
+import org.jboss.cache.factories.annotations.Inject;
+import org.jboss.cache.factories.annotations.NonVolatile;
+import org.jboss.cache.factories.annotations.Start;
+import org.jboss.cache.factories.annotations.Stop;
+import org.jboss.cache.invocation.NodeInvocationDelegate;
+import org.jboss.cache.marshall.NodeData;
+import org.jboss.cache.optimistic.DataVersion;
+import org.jboss.cache.transaction.GlobalTransaction;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * A container for the root node in the cache, which also provides helpers for efficiently accessing nodes, walking trees, etc.
+ *
+ * @author Mircea.Markus at jboss.com
+ * @since 2.2
+ */
+ at NonVolatile
+public class DataContainerImpl implements DataContainer
+{
+   private static final Log log = LogFactory.getLog(DataContainerImpl.class);
+   private static boolean trace = log.isTraceEnabled();
+
+   private Configuration configuration;
+
+   /**
+    * Root node.
+    */
+   private NodeSPI root;
+
+   /**
+    * Set<Fqn> of Fqns of the topmost node of internal regions that should
+    * not included in standard state transfers.
+    */
+   private final Set<Fqn> internalFqns = new HashSet<Fqn>();
+   private NodeFactory nodeFactory;
+
+   @Inject
+   public void injectDependencies(Configuration configuration, NodeFactory nodeFactory)
+   {
+      setDependencies(configuration, nodeFactory);
+
+      // We need to create a root node even at this stage since certain components rely on this being available before
+      // start() is called.
+      // TODO: Investigate which components rely on this being available before start(), and why!
+      //TODO - remove setDependencies method at this point
+      createRootNode();
+   }
+
+   public void setDependencies(Configuration configuration, NodeFactory nodeFactory)
+   {
+      this.configuration = configuration;
+      this.nodeFactory = nodeFactory;
+   }
+
+   @Start(priority = 12)
+   public void createRootNode()
+   {
+      if (trace) log.trace("Starting data container");
+      // create a new root temporarily.
+      NodeSPI tempRoot = nodeFactory.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.
+
+      Class currentRootType = root == null ? null : ((NodeInvocationDelegate) root).getDelegationTarget().getClass();
+      Class tempRootType = ((NodeInvocationDelegate) tempRoot).getDelegationTarget().getClass();
+
+      if (!tempRootType.equals(currentRootType))
+      {
+         if (trace) log.trace("Setting root node to an instance of " + tempRootType);
+         setRoot(tempRoot);
+      }
+   }
+
+   @Stop(priority = 100)
+   public void stop()
+   {
+      // empty in-memory state
+      root.clearDataDirect();
+      root.removeChildrenDirect();
+   }
+
+   public NodeSPI getRoot()
+   {
+      return root;
+   }
+
+   /**
+    * Sets the root node reference to the node passed in.
+    *
+    * @param root node
+    */
+   public void setRoot(NodeSPI root)
+   {
+      if (root == null || !root.getFqn().isRoot())
+         throw new CacheException("Attempting to set an invalid node [" + root + "] as a root node!");
+      this.root = root;
+   }
+
+   public void registerInternalFqn(Fqn fqn)
+   {
+      internalFqns.add(fqn);
+   }
+
+   /**
+    * Finds a node given a fully qualified name, directly off the interceptor chain.  In the event of an exception,
+    * returns null.  Does not include invalid or deleted nodes.
+    *
+    * @param fqn Fully qualified name for the corresponding node.
+    * @return Node referenced by the given Fqn, or null if the node cannot be found or if there is an exception.
+    */
+   public NodeSPI peek(Fqn fqn)
+   {
+      try
+      {
+         return peekVersioned(fqn, null);
+      }
+      catch (CacheException e)
+      {
+         log.warn("Unexpected error", e);
+         return null;
+      }
+   }
+
+   public NodeSPI peekVersioned(Fqn fqn, DataVersion version)
+   {
+      return peekVersioned(fqn, version, false);
+   }
+
+   public NodeSPI peekStrict(GlobalTransaction gtx, Fqn fqn, boolean includeInvalid)
+   {
+      NodeSPI n = peekVersioned(fqn, null, includeInvalid);
+      if (n == null)
+      {
+         StringBuilder builder = new StringBuilder();
+         builder.append("Node ").append(fqn).append(" not found (gtx=").append(gtx).append(")");
+         String errStr = builder.toString();
+         if (trace) log.trace(errStr);
+         throw new NodeNotExistsException(errStr);
+      }
+      return n;
+   }
+
+   public NodeSPI peekVersioned(Fqn fqn, DataVersion version, boolean includeInvalidNodes)
+   {
+      if (fqn == null) return null;
+
+      NodeSPI toReturn = peek(fqn, false, includeInvalidNodes);
+
+      if (toReturn != null && version != null && configuration.isNodeLockingOptimistic())
+      {
+         // we need to check the version of the data node...
+         DataVersion nodeVersion = toReturn.getVersion();
+         if (trace)
+         {
+            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 NodeSPI peek(Fqn<?> fqn, boolean includeDeletedNodes)
+   {
+      return peek(fqn, includeDeletedNodes, false);
+   }
+
+   public NodeSPI peek(Fqn<?> fqn, boolean includeDeletedNodes, boolean includeInvalidNodes)
+   {
+      if (fqn == null || fqn.size() == 0) return getRoot();
+      NodeSPI n = getRoot();
+      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;
+         }
+         else if (!includeInvalidNodes && !n.isValid())
+         {
+            return null;
+         }
+      }
+      return n;
+   }
+
+   public boolean exists(Fqn fqn)
+   {
+      return peek(fqn, false, false) != null;
+   }
+
+   public boolean hasChildren(Fqn fqn)
+   {
+      if (fqn == null) return false;
+
+      NodeSPI n = peek(fqn);
+      return n != null && n.hasChildrenDirect();
+   }
+
+   public List<NodeData> buildNodeData(List<NodeData> list, NodeSPI node)
+   {
+      NodeData data = new NodeData(BuddyFqnTransformer.getActualFqn(node.getFqn()), node.getDataDirect());
+      list.add(data);
+      for (Object childNode : node.getChildrenDirect())
+      {
+         buildNodeData(list, (NodeSPI) childNode);
+      }
+      return list;
+   }
+
+   public List<Fqn> getNodesForEviction(Fqn fqn, boolean recursive)
+   {
+      List<Fqn> result = new ArrayList<Fqn>();
+      NodeSPI node = peek(fqn, false);
+      if (recursive)
+      {
+         recursiveAddEvictionNodes(node, result);
+      }
+      else
+      {
+         if (node == null)
+         {
+            result.add(fqn);
+            return result;
+         }
+         if (fqn.isRoot())
+         {
+            for (Object childName : node.getChildrenNamesDirect())
+            {
+               if (!node.isResident()) result.add(Fqn.fromRelativeElements(fqn, childName));
+            }
+         }
+         else if (!node.isResident())
+         {
+            result.add(fqn);
+         }
+      }
+      return result;
+   }
+
+   private void recursiveAddEvictionNodes(NodeSPI node, List<Fqn> result)
+   {
+      for (NodeSPI child : (Set<NodeSPI>) node.getChildrenDirect())
+      {
+         recursiveAddEvictionNodes(child, result);
+      }
+      Fqn fqn = node.getFqn();
+      if (node != null && !fqn.isRoot() && !node.isResident())
+      {
+         result.add(fqn);
+      }
+   }
+
+   @Override
+   public String toString()
+   {
+      return toString(false);
+   }
+
+   public Set<Fqn> getInternalFqns()
+   {
+      return Collections.unmodifiableSet(internalFqns);
+   }
+
+   /**
+    * Returns a debug string with optional details of contents.
+    */
+   @SuppressWarnings("deprecation")
+   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 (Object n : root.getChildrenDirect())
+         {
+            ((NodeSPI) n).print(sb, indent);
+            sb.append("\n");
+         }
+      }
+      return sb.toString();
+   }
+
+   public int getNumberOfLocksHeld()
+   {
+      return numLocks(root);
+   }
+
+   private int numLocks(NodeSPI n)
+   {
+      int num = 0;
+      if (n != null)
+      {
+         if (n.getLock().isLocked())
+         {
+            num++;
+         }
+         for (Object cn : n.getChildrenDirect(true))
+         {
+            num += numLocks((NodeSPI) cn);
+         }
+      }
+      return num;
+   }
+
+   public int getNumberOfNodes()
+   {
+      return numNodes(root) - 1;
+   }
+
+   private int numNodes(NodeSPI n)
+   {
+      int count = 1;// for n
+      if (n != null)
+      {
+         for (Object child : n.getChildrenDirect())
+         {
+            count += numNodes((NodeSPI) child);
+         }
+      }
+      return count;
+   }
+
+   /**
+    * 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 (Object n : root.getChildrenDirect())
+      {
+         ((NodeSPI) n).getLock().printLockInfo(sb, indent);
+         sb.append("\n");
+      }
+      return sb.toString();
+   }
+
+   public int getNumberOfAttributes(Fqn fqn)
+   {
+      return numAttributes(peek(fqn));
+   }
+
+   private int numAttributes(NodeSPI n)
+   {
+      int count = 0;
+      for (Object child : n.getChildrenDirect())
+      {
+         count += numAttributes((NodeSPI) child);
+      }
+      count += n.getDataDirect().size();
+      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);
+   }
+
+   public boolean removeFromDataStructure(Fqn f, boolean skipMarkerCheck)
+   {
+      NodeSPI n = peek(f, true);
+      if (n == null)
+      {
+         return false;
+      }
+
+      if (trace) 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);
+
+            // mark the node to be removed (and all children) as invalid so anyone holding a direct reference to it will
+            // be aware that it is no longer valid.
+            n.setValid(false, true);
+            n.setValid(true, false);
+
+            // but now remove all children, since the call has been to remove("/")
+            n.removeChildrenDirect();
+            return true;
+         }
+         else
+         {
+            // mark the node to be removed (and all children) as invalid so anyone holding a direct reference to it will
+            // be aware that it is no longer valid.
+            n.setValid(false, true);
+            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;
+      }
+   }
+
+   public void evict(Fqn fqn, boolean recursive)
+   {
+      List<Fqn> toEvict = getNodesForEviction(fqn, recursive);
+      for (Fqn aFqn : toEvict)
+      {
+         evict(aFqn);
+      }
+   }
+
+   public boolean evict(Fqn fqn)
+   {
+      if (peek(fqn, false, true) == null) return true;
+      if (hasChildren(fqn))
+      {
+         if (trace)
+            log.trace("removing DATA as node has children: evict(" + fqn + ")");
+         removeData(fqn);
+         return false;
+      }
+      else
+      {
+         if (trace) log.trace("removing NODE as it is a leaf: evict(" + fqn + ")");
+         removeNode(fqn);
+         return true;
+      }
+   }
+
+   private void removeNode(Fqn fqn)
+   {
+      NodeSPI targetNode = peekVersioned(fqn, null, true);
+      if (targetNode == null) return;
+      NodeSPI parentNode = targetNode.getParent();
+      targetNode.setValid(false, false);
+      if (parentNode != null)
+      {
+         parentNode.removeChildDirect(fqn.getLastElement());
+         parentNode.setChildrenLoaded(false);
+      }
+   }
+
+   protected void removeData(Fqn fqn)
+   {
+      NodeSPI n = peekVersioned(fqn, null);
+      if (n == null)
+      {
+         log.warn("node " + fqn + " not found");
+         return;
+      }
+      n.clearDataDirect();
+      n.setDataLoaded(false);
+   }
+
+   public Object[] createNodes(Fqn fqn)
+   {
+      List<NodeSPI> result = new ArrayList<NodeSPI>(fqn.size());
+      Fqn tmpFqn = Fqn.ROOT;
+
+      int size = fqn.size();
+
+      // root node
+      NodeSPI n = root;
+      for (int i = 0; i < size; i++)
+      {
+         Object childName = fqn.get(i);
+         tmpFqn = Fqn.fromRelativeElements(tmpFqn, childName);
+
+         NodeSPI childNode;
+         Map children = n.getChildrenMapDirect();
+         childNode = children == null ? null : (NodeSPI) children.get(childName);
+
+         if (childNode == null)
+         {
+            childNode = n.addChildDirect(Fqn.fromElements(childName));
+            result.add(childNode);
+         }
+
+         n = childNode;
+      }
+      return new Object[]{result, n};
+   }
+}

Modified: core/trunk/src/main/java/org/jboss/cache/RPCManagerImpl.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/RPCManagerImpl.java	2008-05-14 17:05:33 UTC (rev 5849)
+++ core/trunk/src/main/java/org/jboss/cache/RPCManagerImpl.java	2008-05-15 12:44:49 UTC (rev 5850)
@@ -23,7 +23,7 @@
 import org.jboss.cache.marshall.CommandAwareRpcDispatcher;
 import org.jboss.cache.marshall.InactiveRegionAwareRpcDispatcher;
 import org.jboss.cache.marshall.Marshaller;
-import org.jboss.cache.notifications.Notifier;
+import org.jboss.cache.notifications.NotifierImpl;
 import org.jboss.cache.remoting.jgroups.ChannelMessageListener;
 import org.jboss.cache.statetransfer.StateTransferManager;
 import org.jboss.cache.transaction.GlobalTransaction;
@@ -82,7 +82,7 @@
     */
    private ChannelMessageListener messageListener;
    private Configuration configuration;
-   private Notifier notifier;
+   private NotifierImpl notifier;
    private CacheSPI spi;
    private InvocationContextContainer invocationContextContainer;
    private final boolean trace = log.isTraceEnabled();
@@ -96,7 +96,7 @@
    private ComponentRegistry componentRegistry;
 
    @Inject
-   private void setupDependencies(ChannelMessageListener messageListener, Configuration configuration, Notifier notifier,
+   private void setupDependencies(ChannelMessageListener messageListener, Configuration configuration, NotifierImpl notifier,
                                   CacheSPI spi, Marshaller marshaller, TransactionTable txTable,
                                   TransactionManager txManager, InvocationContextContainer container, InterceptorChain interceptorChain,
                                   ComponentRegistry componentRegistry)

Modified: core/trunk/src/main/java/org/jboss/cache/buddyreplication/BuddyManager.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/buddyreplication/BuddyManager.java	2008-05-14 17:05:33 UTC (rev 5849)
+++ core/trunk/src/main/java/org/jboss/cache/buddyreplication/BuddyManager.java	2008-05-15 12:44:49 UTC (rev 5850)
@@ -8,14 +8,8 @@
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
-import org.jboss.cache.CacheException;
-import org.jboss.cache.CacheSPI;
-import org.jboss.cache.DataContainer;
-import org.jboss.cache.Fqn;
-import org.jboss.cache.Node;
-import org.jboss.cache.RPCManager;
-import org.jboss.cache.Region;
-import org.jboss.cache.RegionManager;
+import org.jboss.cache.DataContainerImpl;
+import org.jboss.cache.*;
 import org.jboss.cache.commands.ReplicableCommand;
 import org.jboss.cache.commands.VisitableCommand;
 import org.jboss.cache.commands.remote.AnnounceBuddyPoolNameCommand;
@@ -31,7 +25,7 @@
 import org.jboss.cache.factories.annotations.Start;
 import org.jboss.cache.factories.annotations.Stop;
 import org.jboss.cache.lock.TimeoutException;
-import org.jboss.cache.notifications.Notifier;
+import org.jboss.cache.notifications.NotifierImpl;
 import org.jboss.cache.notifications.annotation.CacheListener;
 import org.jboss.cache.notifications.annotation.ViewChanged;
 import org.jboss.cache.notifications.event.ViewChangedEvent;
@@ -78,7 +72,7 @@
    private CacheSPI<?, ?> cache;
    private Configuration configuration;
    private RegionManager regionManager;
-   private Notifier notifier;
+   private NotifierImpl notifier;
    private StateTransferManager stateTransferManager;
    private RPCManager rpcManager;
    /**
@@ -141,7 +135,7 @@
    private ViewChangeListener viewChangeListener; // the view-change viewChangeListener
 
    private boolean receivedBuddyInfo;
-   private DataContainer dataContainer;
+   private DataContainerImpl dataContainer;
 
    public BuddyManager()
    {
@@ -179,8 +173,8 @@
 
    @Inject
    public void injectDependencies(CacheSPI cache, Configuration configuration, RegionManager regionManager,
-                                  StateTransferManager stateTransferManager, RPCManager rpcManager, Notifier notifier,
-                                  CommandsFactory factory, DataContainer dataContainer)
+                                  StateTransferManager stateTransferManager, RPCManager rpcManager, NotifierImpl notifier,
+                                  CommandsFactory factory, DataContainerImpl dataContainer)
    {
       this.cache = cache;
       this.configuration = configuration;

Modified: core/trunk/src/main/java/org/jboss/cache/buddyreplication/GravitateResult.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/buddyreplication/GravitateResult.java	2008-05-14 17:05:33 UTC (rev 5849)
+++ core/trunk/src/main/java/org/jboss/cache/buddyreplication/GravitateResult.java	2008-05-15 12:44:49 UTC (rev 5850)
@@ -80,4 +80,28 @@
             " nodeData=" + nodeData +
             " fqn=" + buddyBackupFqn;
    }
+
+   public boolean equals(Object o)
+   {
+      if (this == o) return true;
+      if (o == null || getClass() != o.getClass()) return false;
+
+      GravitateResult that = (GravitateResult) o;
+
+      if (dataFound != that.dataFound) return false;
+      if (buddyBackupFqn != null ? !buddyBackupFqn.equals(that.buddyBackupFqn) : that.buddyBackupFqn != null)
+         return false;
+      if (nodeData != null ? !nodeData.equals(that.nodeData) : that.nodeData != null) return false;
+
+      return true;
+   }
+
+   public int hashCode()
+   {
+      int result;
+      result = (dataFound ? 1 : 0);
+      result = 31 * result + (nodeData != null ? nodeData.hashCode() : 0);
+      result = 31 * result + (buddyBackupFqn != null ? buddyBackupFqn.hashCode() : 0);
+      return result;
+   }
 }

Modified: core/trunk/src/main/java/org/jboss/cache/commands/read/ExistsCommand.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/commands/read/ExistsCommand.java	2008-05-14 17:05:33 UTC (rev 5849)
+++ core/trunk/src/main/java/org/jboss/cache/commands/read/ExistsCommand.java	2008-05-15 12:44:49 UTC (rev 5850)
@@ -35,14 +35,13 @@
 
    /**
     * Checks whether a node represented by a given Fqn exists.
+    * Deleted and invalid nodes are not considered.
     *
-    * @param ctx invocation context
     * @return true if the node exists, false otherwise.
     */
    public Object perform(InvocationContext ctx)
    {
-      Node n = dataContainer.peek(fqn, false);
-      return n != null;
+      return dataContainer.exists(fqn);
    }
 
    public Object acceptVisitor(InvocationContext ctx, Visitor visitor) throws Throwable

Modified: core/trunk/src/main/java/org/jboss/cache/commands/read/GetChildrenNamesCommand.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/commands/read/GetChildrenNamesCommand.java	2008-05-14 17:05:33 UTC (rev 5849)
+++ core/trunk/src/main/java/org/jboss/cache/commands/read/GetChildrenNamesCommand.java	2008-05-15 12:44:49 UTC (rev 5850)
@@ -43,9 +43,9 @@
    {
       NodeSPI n = dataContainer.peek(fqn);
       if (n == null) return null;
-      Set childNames = new HashSet();
       Map childrenMap = n.getChildrenMapDirect();
       if (childrenMap == null || childrenMap.isEmpty()) return Collections.emptySet();
+      Set childNames = new HashSet();
       Collection s = childrenMap.values();
       // prune deleted children - JBCACHE-1136
       for (Object c : s)

Modified: core/trunk/src/main/java/org/jboss/cache/commands/read/GetDataMapCommand.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/commands/read/GetDataMapCommand.java	2008-05-14 17:05:33 UTC (rev 5849)
+++ core/trunk/src/main/java/org/jboss/cache/commands/read/GetDataMapCommand.java	2008-05-15 12:44:49 UTC (rev 5850)
@@ -31,7 +31,6 @@
    /**
     * Retrieves an unmodifiable map of data contained in a node referenced by the specified Fqn.
     *
-    * @param ctx invocation context
     * @return an unmodifiable Map<K, V> of data contained in a node for a given Fqn, or null if the Fqn refers to a node that does not exist.
     */
    public Object perform(InvocationContext ctx)

Modified: core/trunk/src/main/java/org/jboss/cache/commands/read/GetKeyValueCommand.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/commands/read/GetKeyValueCommand.java	2008-05-14 17:05:33 UTC (rev 5849)
+++ core/trunk/src/main/java/org/jboss/cache/commands/read/GetKeyValueCommand.java	2008-05-15 12:44:49 UTC (rev 5850)
@@ -2,10 +2,7 @@
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
-import org.jboss.cache.DataContainer;
-import org.jboss.cache.Fqn;
-import org.jboss.cache.InvocationContext;
-import org.jboss.cache.NodeSPI;
+import org.jboss.cache.*;
 import org.jboss.cache.commands.Visitor;
 import org.jboss.cache.notifications.Notifier;
 
@@ -48,25 +45,25 @@
    /**
     * Retrieves the value stored under a specified key in a node referenced by the specified Fqn.
     *
-    * @param ctx invocation context
     * @return an Object of type V, stored under a specific key in a node for a given Fqn, or null if the Fqn refers to a node that does not exist.
     */
    public Object perform(InvocationContext ctx)
    {
       if (trace)
       {
-         log.trace(new StringBuffer("_get(").append("\"").append(fqn).append("\", \"").append(key).append("\", \"").
+         log.trace(new StringBuffer("get(").append("\"").append(fqn).append("\", \"").append(key).append("\", \"").
                append(sendNodeEvent).append("\")"));
       }
-      if (sendNodeEvent) notifier.notifyNodeVisited(fqn, true, ctx);
       NodeSPI n = dataContainer.peek(fqn);
       if (n == null)
       {
          log.trace("node not found");
          return null;
       }
+      if (sendNodeEvent) notifier.notifyNodeVisited(fqn, true, ctx);
+      Object result = n.getDirect(key);
       if (sendNodeEvent) notifier.notifyNodeVisited(fqn, false, ctx);
-      return n.getDirect(key);
+      return result;
    }
 
 

Modified: core/trunk/src/main/java/org/jboss/cache/commands/read/GetKeysCommand.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/commands/read/GetKeysCommand.java	2008-05-14 17:05:33 UTC (rev 5849)
+++ core/trunk/src/main/java/org/jboss/cache/commands/read/GetKeysCommand.java	2008-05-15 12:44:49 UTC (rev 5850)
@@ -41,8 +41,7 @@
    {
       NodeSPI n = dataContainer.peek(fqn);
       if (n == null) return null;
-      Set keys = n.getKeysDirect();
-      return new HashSet(keys);
+      return n.getKeysDirect();
    }
 
    public Object acceptVisitor(InvocationContext ctx, Visitor visitor) throws Throwable

Modified: core/trunk/src/main/java/org/jboss/cache/commands/read/GravitateDataCommand.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/commands/read/GravitateDataCommand.java	2008-05-14 17:05:33 UTC (rev 5849)
+++ core/trunk/src/main/java/org/jboss/cache/commands/read/GravitateDataCommand.java	2008-05-15 12:44:49 UTC (rev 5850)
@@ -2,18 +2,13 @@
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
-import org.jboss.cache.CacheSPI;
-import org.jboss.cache.DataContainer;
-import org.jboss.cache.Fqn;
-import org.jboss.cache.InvocationContext;
-import org.jboss.cache.Node;
-import org.jboss.cache.NodeSPI;
-import org.jboss.cache.RPCManager;
+import org.jboss.cache.*;
 import org.jboss.cache.buddyreplication.BuddyFqnTransformer;
 import org.jboss.cache.buddyreplication.BuddyManager;
 import org.jboss.cache.buddyreplication.GravitateResult;
 import org.jboss.cache.commands.Visitor;
 import org.jboss.cache.marshall.NodeData;
+import org.jgroups.Address;
 
 import java.util.LinkedList;
 import java.util.List;
@@ -34,29 +29,30 @@
    public static final int METHOD_ID = 35;
 
    /* dependencies */
-   private RPCManager rpcManager;
    private CacheSPI spi;
 
    /* parametres */
    private boolean searchSubtrees;
+   private Address localAddress;
 
    private static final Log log = LogFactory.getLog(GravitateDataCommand.class);
    private static boolean trace = log.isTraceEnabled();
 
-   public GravitateDataCommand(Fqn fqn, boolean searchSubtrees)
+   public GravitateDataCommand(Fqn fqn, boolean searchSubtrees, Address localAddress)
    {
       this.fqn = fqn;
       this.searchSubtrees = searchSubtrees;
+      this.localAddress = localAddress;
    }
 
-   public GravitateDataCommand()
+   public GravitateDataCommand(Address localAddress)
    {
+      this.localAddress = localAddress;
    }
 
-   public void initialize(DataContainer dataContainer, RPCManager manager, CacheSPI spi)
+   public void initialize(DataContainer dataContainer, CacheSPI spi)
    {
       this.dataContainer = dataContainer;
-      this.rpcManager = manager;
       this.spi = spi;
    }
 
@@ -77,6 +73,7 @@
          ctx.setOriginLocal(false);
          // use a get() call into the cache to make sure cache loading takes place.
          // no need to cache the original skipDataGravitation setting here - it will always be false of we got here!!
+         //todo 2.2  use dataContainer for peek and load the data in the CLInterceptor rather than using the SPI for than!!!
          ctx.getOptionOverrides().setSkipDataGravitation(true);
          Node actualNode = spi.getNode(fqn);
          ctx.getOptionOverrides().setSkipDataGravitation(false);
@@ -91,14 +88,14 @@
             if (backupSubtree != null)
             {
                // need to loop through backupSubtree's children
-               Set childNames = backupSubtree.getChildrenNamesDirect();
-               if (childNames != null)
+               Set allGroupNames = backupSubtree.getChildrenNamesDirect();
+               if (allGroupNames != null)
                {
-                  for (Object childName : childNames)
+                  for (Object groupName : allGroupNames)
                   {
-                     // childName is the name of a buddy group since all child names in this
+                     // groupName is the name of a buddy group since all child names in this
                      // collection are direct children of BUDDY_BACKUP_SUBTREE_FQN
-                     Fqn backupRoot = Fqn.fromRelativeElements(BuddyManager.BUDDY_BACKUP_SUBTREE_FQN, childName);
+                     Fqn backupRoot = Fqn.fromRelativeElements(BuddyManager.BUDDY_BACKUP_SUBTREE_FQN, groupName);
                      if (BuddyFqnTransformer.isDeadBackupRoot(backupRoot))
                      {
                         Set<Integer> deadChildNames = new TreeSet<Integer>(spi.getChildrenNames(backupRoot));
@@ -150,7 +147,7 @@
 
          if (backupNodeFqn == null && searchSubtrees)
          {
-            backupNodeFqn = BuddyFqnTransformer.getBackupFqn(BuddyFqnTransformer.getGroupNameFromAddress(rpcManager.getLocalAddress()), fqn);
+            backupNodeFqn = BuddyFqnTransformer.getBackupFqn(BuddyFqnTransformer.getGroupNameFromAddress(localAddress), fqn);
          }
 
          List<NodeData> list = dataContainer.buildNodeData(new LinkedList<NodeData>(), (NodeSPI) actualNode);
@@ -226,4 +223,9 @@
             ", searchSubtrees=" + searchSubtrees +
             '}';
    }
+
+   void setSearchSubtrees(boolean searchSubtrees)
+   {
+      this.searchSubtrees = searchSubtrees;
+   }
 }

Modified: core/trunk/src/main/java/org/jboss/cache/commands/remote/ClusteredGetCommand.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/commands/remote/ClusteredGetCommand.java	2008-05-14 17:05:33 UTC (rev 5849)
+++ core/trunk/src/main/java/org/jboss/cache/commands/remote/ClusteredGetCommand.java	2008-05-15 12:44:49 UTC (rev 5850)
@@ -2,7 +2,7 @@
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
-import org.jboss.cache.DataContainer;
+import org.jboss.cache.DataContainerImpl;
 import org.jboss.cache.InvocationContext;
 import org.jboss.cache.commands.DataCommand;
 import org.jboss.cache.commands.ReplicableCommand;
@@ -30,7 +30,7 @@
 
    private DataCommand dataCommand;
    private boolean searchBackupSubtrees;
-   private DataContainer dataContainer;
+   private DataContainerImpl dataContainer;
    private InterceptorChain interceptorChain;
 
    private static final Log log = LogFactory.getLog(ClusteredGetCommand.class);
@@ -46,7 +46,7 @@
    {
    }
 
-   public void initialize(DataContainer dataContainer, InterceptorChain interceptorChain)
+   public void initialize(DataContainerImpl dataContainer, InterceptorChain interceptorChain)
    {
       this.dataContainer = dataContainer;
       this.interceptorChain = interceptorChain;

Modified: core/trunk/src/main/java/org/jboss/cache/commands/remote/DataGravitationCleanupCommand.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/commands/remote/DataGravitationCleanupCommand.java	2008-05-14 17:05:33 UTC (rev 5849)
+++ core/trunk/src/main/java/org/jboss/cache/commands/remote/DataGravitationCleanupCommand.java	2008-05-15 12:44:49 UTC (rev 5850)
@@ -2,7 +2,7 @@
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
-import org.jboss.cache.DataContainer;
+import org.jboss.cache.DataContainerImpl;
 import org.jboss.cache.Fqn;
 import org.jboss.cache.InvocationContext;
 import org.jboss.cache.NodeSPI;
@@ -38,7 +38,7 @@
    private TransactionTable transactionTable;
    private InterceptorChain invoker;
    private CommandsFactory commandsFactory;
-   private DataContainer dataContainer;
+   private DataContainerImpl dataContainer;
 
    /* parameters */
    private GlobalTransaction globalTransaction;
@@ -57,7 +57,7 @@
    }
 
    public void initialize(BuddyManager buddyManager, InterceptorChain invoker, TransactionTable transactionTable,
-                          CommandsFactory commandsFactory, DataContainer dataContainer)
+                          CommandsFactory commandsFactory, DataContainerImpl dataContainer)
    {
       this.buddyManager = buddyManager;
       this.invoker = invoker;

Modified: core/trunk/src/main/java/org/jboss/cache/commands/write/AbstractVersionedDataCommand.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/commands/write/AbstractVersionedDataCommand.java	2008-05-14 17:05:33 UTC (rev 5849)
+++ core/trunk/src/main/java/org/jboss/cache/commands/write/AbstractVersionedDataCommand.java	2008-05-15 12:44:49 UTC (rev 5850)
@@ -1,7 +1,7 @@
 package org.jboss.cache.commands.write;
 
 import org.jboss.cache.Fqn;
-import org.jboss.cache.DataContainer;
+import org.jboss.cache.DataContainerImpl;
 import org.jboss.cache.commands.VersionedDataCommand;
 import org.jboss.cache.commands.read.AbstractDataCommand;
 import org.jboss.cache.notifications.Notifier;
@@ -21,7 +21,7 @@
    protected DataVersion dataVersion;
    protected GlobalTransaction globalTransaction;
 
-   public void initialize(Notifier notifier, DataContainer dataContainer)
+   public void initialize(Notifier notifier, DataContainerImpl dataContainer)
    {
       this.notifier = notifier;
       this.dataContainer = dataContainer;

Modified: core/trunk/src/main/java/org/jboss/cache/commands/write/MoveCommand.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/commands/write/MoveCommand.java	2008-05-14 17:05:33 UTC (rev 5849)
+++ core/trunk/src/main/java/org/jboss/cache/commands/write/MoveCommand.java	2008-05-15 12:44:49 UTC (rev 5850)
@@ -2,7 +2,7 @@
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
-import org.jboss.cache.DataContainer;
+import org.jboss.cache.DataContainerImpl;
 import org.jboss.cache.Fqn;
 import org.jboss.cache.InvocationContext;
 import org.jboss.cache.NodeNotExistsException;
@@ -37,7 +37,7 @@
    {
    }
 
-   public void initialize(Notifier notifier, DataContainer dataContainer)
+   public void initialize(Notifier notifier, DataContainerImpl dataContainer)
    {
       this.notifier = notifier;
       this.dataContainer = dataContainer;

Modified: core/trunk/src/main/java/org/jboss/cache/factories/CommandsFactory.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/factories/CommandsFactory.java	2008-05-14 17:05:33 UTC (rev 5849)
+++ core/trunk/src/main/java/org/jboss/cache/factories/CommandsFactory.java	2008-05-15 12:44:49 UTC (rev 5850)
@@ -2,7 +2,7 @@
 
 import org.jboss.cache.CacheException;
 import org.jboss.cache.CacheSPI;
-import org.jboss.cache.DataContainer;
+import org.jboss.cache.DataContainerImpl;
 import org.jboss.cache.Fqn;
 import org.jboss.cache.RPCManager;
 import org.jboss.cache.buddyreplication.BuddyGroup;
@@ -40,7 +40,7 @@
 import org.jboss.cache.factories.annotations.Inject;
 import org.jboss.cache.factories.annotations.NonVolatile;
 import org.jboss.cache.interceptors.InterceptorChain;
-import org.jboss.cache.notifications.Notifier;
+import org.jboss.cache.notifications.NotifierImpl;
 import org.jboss.cache.transaction.GlobalTransaction;
 import org.jboss.cache.transaction.TransactionTable;
 import org.jgroups.Address;
@@ -66,8 +66,8 @@
 public class CommandsFactory
 {
    private RPCManager rpcManager;
-   private DataContainer dataContainer;
-   private Notifier notifier;
+   private DataContainerImpl dataContainer;
+   private NotifierImpl notifier;
    private InterceptorChain invoker;
    private BuddyManager buddyManager;
    private TransactionTable transactionTable;
@@ -80,7 +80,7 @@
    }
 
    @Inject
-   public void initialize(RPCManager rpc, DataContainer dataContainer, Notifier notifier, BuddyManager buddyManager,
+   public void initialize(RPCManager rpc, DataContainerImpl dataContainer, NotifierImpl notifier, BuddyManager buddyManager,
                           InterceptorChain invoker, TransactionTable transactionTable, CacheSPI cacheSpi,
                           Configuration configuration, TransactionManager txManager)
    {
@@ -147,8 +147,8 @@
 
    public GravitateDataCommand buildGravitateDataCommand(Fqn fqn, Boolean searchSubtrees)
    {
-      GravitateDataCommand command = new GravitateDataCommand(fqn, searchSubtrees);
-      command.initialize(dataContainer, rpcManager, cacheSpi);
+      GravitateDataCommand command = new GravitateDataCommand(fqn, searchSubtrees, rpcManager.getLocalAddress());
+      command.initialize(dataContainer, cacheSpi);
       return command;
    }
 
@@ -239,8 +239,8 @@
 
    public GravitateDataCommand buildGravitateDataCacheCommand(Fqn fqn, boolean searchSubtrees)
    {
-      GravitateDataCommand command = new GravitateDataCommand(fqn, searchSubtrees);
-      command.initialize(dataContainer, rpcManager, cacheSpi);
+      GravitateDataCommand command = new GravitateDataCommand(fqn, searchSubtrees, rpcManager.getLocalAddress());
+      command.initialize(dataContainer, cacheSpi);
       return command;
    }
 
@@ -485,8 +485,8 @@
          }
          case GravitateDataCommand.METHOD_ID:
          {
-            GravitateDataCommand returnValue = new GravitateDataCommand();
-            returnValue.initialize(dataContainer, rpcManager, cacheSpi);
+            GravitateDataCommand returnValue = new GravitateDataCommand(rpcManager.getLocalAddress());
+            returnValue.initialize(dataContainer, cacheSpi);
             command = returnValue;
             break;
          }

Modified: core/trunk/src/main/java/org/jboss/cache/factories/EmptyConstructorFactory.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/factories/EmptyConstructorFactory.java	2008-05-14 17:05:33 UTC (rev 5849)
+++ core/trunk/src/main/java/org/jboss/cache/factories/EmptyConstructorFactory.java	2008-05-15 12:44:49 UTC (rev 5850)
@@ -1,6 +1,6 @@
 package org.jboss.cache.factories;
 
-import org.jboss.cache.DataContainer;
+import org.jboss.cache.DataContainerImpl;
 import org.jboss.cache.RegionManager;
 import org.jboss.cache.config.ConfigurationException;
 import org.jboss.cache.factories.annotations.DefaultFactoryFor;
@@ -11,7 +11,7 @@
 import org.jboss.cache.lock.LockStrategyFactory;
 import org.jboss.cache.marshall.Marshaller;
 import org.jboss.cache.marshall.VersionAwareMarshaller;
-import org.jboss.cache.notifications.Notifier;
+import org.jboss.cache.notifications.NotifierImpl;
 import org.jboss.cache.remoting.jgroups.ChannelMessageListener;
 import org.jboss.cache.statetransfer.StateTransferManager;
 import org.jboss.cache.transaction.TransactionTable;
@@ -22,10 +22,10 @@
  * @author Manik Surtani (<a href="mailto:manik at jboss.org">manik at jboss.org</a>)
  * @since 2.1.0
  */
- at DefaultFactoryFor(classes = {StateTransferManager.class, RegionManager.class, Notifier.class,
+ at DefaultFactoryFor(classes = {StateTransferManager.class, RegionManager.class, NotifierImpl.class,
       ChannelMessageListener.class, CacheLoaderManager.class, Marshaller.class,
       InvocationContextContainer.class, CacheInvocationDelegate.class,
-      TransactionTable.class, DataContainer.class, CommandsFactory.class, LockManager.class,
+      TransactionTable.class, DataContainerImpl.class, CommandsFactory.class, LockManager.class,
       LockStrategyFactory.class})
 public class EmptyConstructorFactory extends ComponentFactory
 {

Modified: core/trunk/src/main/java/org/jboss/cache/interceptors/CacheLoaderInterceptor.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/interceptors/CacheLoaderInterceptor.java	2008-05-14 17:05:33 UTC (rev 5849)
+++ core/trunk/src/main/java/org/jboss/cache/interceptors/CacheLoaderInterceptor.java	2008-05-15 12:44:49 UTC (rev 5850)
@@ -1,7 +1,7 @@
 package org.jboss.cache.interceptors;
 
 import org.jboss.cache.CacheException;
-import org.jboss.cache.DataContainer;
+import org.jboss.cache.DataContainerImpl;
 import org.jboss.cache.Fqn;
 import org.jboss.cache.InvocationContext;
 import org.jboss.cache.NodeSPI;
@@ -27,7 +27,7 @@
 import org.jboss.cache.loader.CacheLoaderManager;
 import org.jboss.cache.lock.LockManager;
 import org.jboss.cache.lock.NodeLock;
-import org.jboss.cache.notifications.Notifier;
+import org.jboss.cache.notifications.NotifierImpl;
 import org.jboss.cache.transaction.TransactionEntry;
 import org.jboss.cache.transaction.TransactionTable;
 
@@ -53,8 +53,8 @@
 
    protected TransactionTable txTable = null;
    protected CacheLoader loader;
-   protected DataContainer dataContainer;
-   protected Notifier notifier;
+   protected DataContainerImpl dataContainer;
+   protected NotifierImpl notifier;
 
    protected boolean isActivation = false;
    protected boolean usingOptimisticInvalidation = false;
@@ -69,7 +69,7 @@
 
    @Inject
    protected void injectDependencies(TransactionTable txTable, CacheLoaderManager clm, Configuration configuration,
-                                     DataContainer dataContainer, LockManager lockManager, Notifier notifier)
+                                     DataContainerImpl dataContainer, LockManager lockManager, NotifierImpl notifier)
    {
       this.txTable = txTable;
       this.clm = clm;

Modified: core/trunk/src/main/java/org/jboss/cache/interceptors/CacheMgmtInterceptor.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/interceptors/CacheMgmtInterceptor.java	2008-05-14 17:05:33 UTC (rev 5849)
+++ core/trunk/src/main/java/org/jboss/cache/interceptors/CacheMgmtInterceptor.java	2008-05-15 12:44:49 UTC (rev 5850)
@@ -21,7 +21,7 @@
  */
 package org.jboss.cache.interceptors;
 
-import org.jboss.cache.DataContainer;
+import org.jboss.cache.DataContainerImpl;
 import org.jboss.cache.InvocationContext;
 import org.jboss.cache.commands.read.GetKeyValueCommand;
 import org.jboss.cache.commands.write.EvictCommand;
@@ -51,10 +51,10 @@
    private long m_start = System.currentTimeMillis();
    private long m_reset = m_start;
 
-   private DataContainer dataContainer;
+   private DataContainerImpl dataContainer;
 
    @Inject
-   public void setDependencies(DataContainer dataContainer)
+   public void setDependencies(DataContainerImpl dataContainer)
    {
       this.dataContainer = dataContainer;
    }

Modified: core/trunk/src/main/java/org/jboss/cache/interceptors/CacheStoreInterceptor.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/interceptors/CacheStoreInterceptor.java	2008-05-14 17:05:33 UTC (rev 5849)
+++ core/trunk/src/main/java/org/jboss/cache/interceptors/CacheStoreInterceptor.java	2008-05-15 12:44:49 UTC (rev 5850)
@@ -1,11 +1,7 @@
 package org.jboss.cache.interceptors;
 
 import org.apache.commons.logging.LogFactory;
-import org.jboss.cache.DataContainer;
-import org.jboss.cache.Fqn;
-import org.jboss.cache.InvocationContext;
-import org.jboss.cache.Modification;
-import org.jboss.cache.NodeSPI;
+import org.jboss.cache.*;
 import org.jboss.cache.commands.AbstractVisitor;
 import org.jboss.cache.commands.ReversibleCommand;
 import org.jboss.cache.commands.VisitableCommand;
@@ -13,12 +9,7 @@
 import org.jboss.cache.commands.tx.OptimisticPrepareCommand;
 import org.jboss.cache.commands.tx.PrepareCommand;
 import org.jboss.cache.commands.tx.RollbackCommand;
-import org.jboss.cache.commands.write.MoveCommand;
-import org.jboss.cache.commands.write.PutDataMapCommand;
-import org.jboss.cache.commands.write.PutKeyValueCommand;
-import org.jboss.cache.commands.write.RemoveDataCommand;
-import org.jboss.cache.commands.write.RemoveKeyCommand;
-import org.jboss.cache.commands.write.RemoveNodeCommand;
+import org.jboss.cache.commands.write.*;
 import org.jboss.cache.config.CacheLoaderConfig;
 import org.jboss.cache.factories.annotations.Inject;
 import org.jboss.cache.factories.annotations.Start;
@@ -30,12 +21,7 @@
 
 import javax.transaction.SystemException;
 import javax.transaction.TransactionManager;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
+import java.util.*;
 import java.util.concurrent.ConcurrentHashMap;
 
 /**
@@ -53,7 +39,7 @@
    private Map<GlobalTransaction, Set<Fqn>> preparingTxs = new ConcurrentHashMap<GlobalTransaction, Set<Fqn>>();
    private long cacheStores = 0;
    private CacheLoader loader;
-   private DataContainer dataContainer;
+   private DataContainerImpl dataContainer;
    private CacheLoaderManager loaderManager;
 
    public CacheStoreInterceptor()
@@ -63,7 +49,7 @@
    }
 
    @Inject
-   protected void init(DataContainer dataContainer, CacheLoaderManager loaderManager, TransactionManager txManager, CacheLoaderConfig clConfig)
+   protected void init(DataContainerImpl dataContainer, CacheLoaderManager loaderManager, TransactionManager txManager, CacheLoaderConfig clConfig)
    {
       // never inject a CacheLoader at this stage - only a CacheLoaderManager, since the CacheLoaderManager only creates a CacheLoader instance when it @Starts.
       this.loaderManager = loaderManager;

Modified: core/trunk/src/main/java/org/jboss/cache/interceptors/DataGravitatorInterceptor.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/interceptors/DataGravitatorInterceptor.java	2008-05-14 17:05:33 UTC (rev 5849)
+++ core/trunk/src/main/java/org/jboss/cache/interceptors/DataGravitatorInterceptor.java	2008-05-15 12:44:49 UTC (rev 5850)
@@ -6,11 +6,8 @@
  */
 package org.jboss.cache.interceptors;
 
-import org.jboss.cache.CacheException;
-import org.jboss.cache.CacheSPI;
-import org.jboss.cache.DataContainer;
-import org.jboss.cache.Fqn;
-import org.jboss.cache.InvocationContext;
+import org.jboss.cache.DataContainerImpl;
+import org.jboss.cache.*;
 import org.jboss.cache.buddyreplication.BuddyFqnTransformer;
 import org.jboss.cache.buddyreplication.BuddyManager;
 import org.jboss.cache.buddyreplication.GravitateResult;
@@ -69,12 +66,12 @@
     * cleanup commands corresponding to all gravitate calls made during the course of the transaction in question.
     */
    private Map<GlobalTransaction, List<ReplicableCommand>> cleanupCommands = new ConcurrentHashMap<GlobalTransaction, List<ReplicableCommand>>();
-   private DataContainer dataContainer;
+   private DataContainerImpl dataContainer;
    private CommandsFactory commandsFactory;
    private CacheSPI cacheSPI;
 
    @Inject
-   public void injectComponents(BuddyManager buddyManager, DataContainer dataContainer, CommandsFactory commandsFactory, CacheSPI cacheSPI)
+   public void injectComponents(BuddyManager buddyManager, DataContainerImpl dataContainer, CommandsFactory commandsFactory, CacheSPI cacheSPI)
    {
       this.buddyManager = buddyManager;
       this.dataContainer = dataContainer;

Modified: core/trunk/src/main/java/org/jboss/cache/interceptors/EvictionInterceptor.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/interceptors/EvictionInterceptor.java	2008-05-14 17:05:33 UTC (rev 5849)
+++ core/trunk/src/main/java/org/jboss/cache/interceptors/EvictionInterceptor.java	2008-05-15 12:44:49 UTC (rev 5850)
@@ -7,12 +7,8 @@
  */
 package org.jboss.cache.interceptors;
 
-import org.jboss.cache.DataContainer;
-import org.jboss.cache.Fqn;
-import org.jboss.cache.InvocationContext;
-import org.jboss.cache.NodeSPI;
-import org.jboss.cache.Region;
-import org.jboss.cache.RegionManager;
+import org.jboss.cache.DataContainerImpl;
+import org.jboss.cache.*;
 import org.jboss.cache.commands.read.GetDataMapCommand;
 import org.jboss.cache.commands.read.GetKeyValueCommand;
 import org.jboss.cache.commands.read.GetNodeCommand;
@@ -40,10 +36,10 @@
 {
    protected RegionManager regionManager;
 
-   private DataContainer dataContainer;
+   private DataContainerImpl dataContainer;
 
    @Inject
-   public void initialize(DataContainer dataContainer)
+   public void initialize(DataContainerImpl dataContainer)
    {
       this.dataContainer = dataContainer;
    }

Modified: core/trunk/src/main/java/org/jboss/cache/interceptors/NotificationInterceptor.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/interceptors/NotificationInterceptor.java	2008-05-14 17:05:33 UTC (rev 5849)
+++ core/trunk/src/main/java/org/jboss/cache/interceptors/NotificationInterceptor.java	2008-05-15 12:44:49 UTC (rev 5850)
@@ -5,7 +5,7 @@
 import org.jboss.cache.commands.tx.CommitCommand;
 import org.jboss.cache.commands.tx.RollbackCommand;
 import org.jboss.cache.factories.annotations.Inject;
-import org.jboss.cache.notifications.Notifier;
+import org.jboss.cache.notifications.NotifierImpl;
 
 /**
  * The interceptor in charge of firing off notifications to cache listeners
@@ -15,11 +15,11 @@
  */
 public class NotificationInterceptor extends BaseTransactionalContextInterceptor
 {
-   private Notifier notifier;
+   private NotifierImpl notifier;
    private CacheSPI cacheSPI;
 
    @Inject
-   public void injectDependencies(Notifier notifier, CacheSPI cacheSPI)
+   public void injectDependencies(NotifierImpl notifier, CacheSPI cacheSPI)
    {
       this.notifier = notifier;
       this.cacheSPI = cacheSPI;

Modified: core/trunk/src/main/java/org/jboss/cache/interceptors/OptimisticCreateIfNotExistsInterceptor.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/interceptors/OptimisticCreateIfNotExistsInterceptor.java	2008-05-14 17:05:33 UTC (rev 5849)
+++ core/trunk/src/main/java/org/jboss/cache/interceptors/OptimisticCreateIfNotExistsInterceptor.java	2008-05-15 12:44:49 UTC (rev 5850)
@@ -6,13 +6,8 @@
  */
 package org.jboss.cache.interceptors;
 
-import org.jboss.cache.CacheException;
-import org.jboss.cache.CacheSPI;
-import org.jboss.cache.DataContainer;
-import org.jboss.cache.Fqn;
-import org.jboss.cache.InvocationContext;
-import org.jboss.cache.NodeFactory;
-import org.jboss.cache.NodeSPI;
+import org.jboss.cache.DataContainerImpl;
+import org.jboss.cache.*;
 import org.jboss.cache.commands.write.MoveCommand;
 import org.jboss.cache.commands.write.PutDataMapCommand;
 import org.jboss.cache.commands.write.PutKeyValueCommand;
@@ -45,14 +40,14 @@
     */
    private NodeFactory nodeFactory;
 
-   private DataContainer dataContainer;
+   private DataContainerImpl dataContainer;
 
    private CacheSPI cache;
 
    private long lockAcquisitionTimeout;
 
    @Inject
-   private void injectDependencies(NodeFactory nodeFactory, DataContainer dataContainer, CacheSPI cacheSPI)
+   private void injectDependencies(NodeFactory nodeFactory, DataContainerImpl dataContainer, CacheSPI cacheSPI)
    {
       this.nodeFactory = nodeFactory;
       this.dataContainer = dataContainer;

Modified: core/trunk/src/main/java/org/jboss/cache/interceptors/OptimisticNodeInterceptor.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/interceptors/OptimisticNodeInterceptor.java	2008-05-14 17:05:33 UTC (rev 5849)
+++ core/trunk/src/main/java/org/jboss/cache/interceptors/OptimisticNodeInterceptor.java	2008-05-15 12:44:49 UTC (rev 5850)
@@ -7,13 +7,8 @@
 package org.jboss.cache.interceptors;
 
 import org.apache.commons.logging.LogFactory;
-import org.jboss.cache.CacheException;
-import org.jboss.cache.DataContainer;
-import org.jboss.cache.Fqn;
-import org.jboss.cache.InvocationContext;
-import org.jboss.cache.NodeFactory;
-import org.jboss.cache.NodeNotExistsException;
-import org.jboss.cache.NodeSPI;
+import org.jboss.cache.DataContainerImpl;
+import org.jboss.cache.*;
 import org.jboss.cache.commands.ReversibleCommand;
 import org.jboss.cache.commands.read.GetChildrenNamesCommand;
 import org.jboss.cache.commands.read.GetDataMapCommand;
@@ -29,7 +24,7 @@
 import org.jboss.cache.config.Option;
 import org.jboss.cache.factories.annotations.Inject;
 import org.jboss.cache.factories.annotations.Start;
-import org.jboss.cache.notifications.Notifier;
+import org.jboss.cache.notifications.NotifierImpl;
 import static org.jboss.cache.notifications.event.NodeModifiedEvent.ModificationType.*;
 import org.jboss.cache.optimistic.DataVersion;
 import org.jboss.cache.optimistic.DefaultDataVersion;
@@ -55,12 +50,12 @@
     * Needed for the creation of workspace nodes based on underlying nodes in the cache.
     */
    private NodeFactory nodeFactory;
-   private Notifier notifier;
-   private DataContainer dataContainer;
+   private NotifierImpl notifier;
+   private DataContainerImpl dataContainer;
    private long lockAcquisitionTimeout;
 
    @Inject
-   protected void injectDependencies(Notifier notifier, NodeFactory nodeFactory, DataContainer dataContainer)
+   protected void injectDependencies(NotifierImpl notifier, NodeFactory nodeFactory, DataContainerImpl dataContainer)
    {
       this.notifier = notifier;
       this.nodeFactory = nodeFactory;

Modified: core/trunk/src/main/java/org/jboss/cache/interceptors/OptimisticValidatorInterceptor.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/interceptors/OptimisticValidatorInterceptor.java	2008-05-14 17:05:33 UTC (rev 5849)
+++ core/trunk/src/main/java/org/jboss/cache/interceptors/OptimisticValidatorInterceptor.java	2008-05-15 12:44:49 UTC (rev 5850)
@@ -6,11 +6,8 @@
  */
 package org.jboss.cache.interceptors;
 
-import org.jboss.cache.CacheException;
-import org.jboss.cache.DataContainer;
-import org.jboss.cache.Fqn;
-import org.jboss.cache.InvocationContext;
-import org.jboss.cache.NodeSPI;
+import org.jboss.cache.DataContainerImpl;
+import org.jboss.cache.*;
 import org.jboss.cache.commands.tx.CommitCommand;
 import org.jboss.cache.commands.tx.OptimisticPrepareCommand;
 import org.jboss.cache.commands.tx.RollbackCommand;
@@ -50,10 +47,10 @@
 {
    private boolean useTombstones;
 
-   private DataContainer dataContainer;
+   private DataContainerImpl dataContainer;
 
    @Inject
-   public void initialize(DataContainer dataContainer)
+   public void initialize(DataContainerImpl dataContainer)
    {
       this.dataContainer = dataContainer;
    }

Modified: core/trunk/src/main/java/org/jboss/cache/interceptors/PassivationInterceptor.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/interceptors/PassivationInterceptor.java	2008-05-14 17:05:33 UTC (rev 5849)
+++ core/trunk/src/main/java/org/jboss/cache/interceptors/PassivationInterceptor.java	2008-05-15 12:44:49 UTC (rev 5850)
@@ -1,6 +1,6 @@
 package org.jboss.cache.interceptors;
 
-import org.jboss.cache.DataContainer;
+import org.jboss.cache.DataContainerImpl;
 import org.jboss.cache.Fqn;
 import org.jboss.cache.InvocationContext;
 import org.jboss.cache.NodeSPI;
@@ -9,7 +9,7 @@
 import org.jboss.cache.interceptors.base.CommandInterceptor;
 import org.jboss.cache.loader.CacheLoader;
 import org.jboss.cache.loader.CacheLoaderManager;
-import org.jboss.cache.notifications.Notifier;
+import org.jboss.cache.notifications.NotifierImpl;
 
 import java.util.Collections;
 import java.util.HashMap;
@@ -30,11 +30,11 @@
    private final AtomicLong passivations = new AtomicLong(0);
 
    protected CacheLoader loader;
-   private Notifier notifier;
-   private DataContainer dataContainer;
+   private NotifierImpl notifier;
+   private DataContainerImpl dataContainer;
 
    @Inject
-   public void setDependencies(Notifier notifier, DataContainer dataContainer, CacheLoaderManager loaderManager)
+   public void setDependencies(NotifierImpl notifier, DataContainerImpl dataContainer, CacheLoaderManager loaderManager)
    {
       this.notifier = notifier;
       this.dataContainer = dataContainer;

Modified: core/trunk/src/main/java/org/jboss/cache/interceptors/PessimisticLockInterceptor.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/interceptors/PessimisticLockInterceptor.java	2008-05-14 17:05:33 UTC (rev 5849)
+++ core/trunk/src/main/java/org/jboss/cache/interceptors/PessimisticLockInterceptor.java	2008-05-15 12:44:49 UTC (rev 5850)
@@ -6,7 +6,7 @@
  */
 package org.jboss.cache.interceptors;
 
-import org.jboss.cache.DataContainer;
+import org.jboss.cache.DataContainerImpl;
 import org.jboss.cache.Fqn;
 import org.jboss.cache.InvocationContext;
 import org.jboss.cache.NodeSPI;
@@ -59,12 +59,12 @@
 public class PessimisticLockInterceptor extends PostProcessingCommandInterceptor
 {
    private TransactionTable txTable;
-   private DataContainer dataContainer;
+   private DataContainerImpl dataContainer;
    private LockManager lockManager;
    private long lockAcquisitionTimeout;
 
    @Inject
-   public void injectDependencies(DataContainer dataContainer, TransactionTable txTable, LockManager lockManager)
+   public void injectDependencies(DataContainerImpl dataContainer, TransactionTable txTable, LockManager lockManager)
    {
       this.dataContainer = dataContainer;
       this.txTable = txTable;

Modified: core/trunk/src/main/java/org/jboss/cache/interceptors/TxInterceptor.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/interceptors/TxInterceptor.java	2008-05-14 17:05:33 UTC (rev 5849)
+++ core/trunk/src/main/java/org/jboss/cache/interceptors/TxInterceptor.java	2008-05-15 12:44:49 UTC (rev 5850)
@@ -30,7 +30,7 @@
 import org.jboss.cache.factories.ComponentRegistry;
 import org.jboss.cache.factories.annotations.Inject;
 import org.jboss.cache.invocation.InvocationContextContainer;
-import org.jboss.cache.notifications.Notifier;
+import org.jboss.cache.notifications.NotifierImpl;
 import org.jboss.cache.transaction.GlobalTransaction;
 import org.jboss.cache.transaction.TransactionEntry;
 import org.jboss.cache.transaction.TransactionTable;
@@ -62,7 +62,7 @@
 {
    protected CommandsFactory commandsFactory;
    protected RPCManager rpcManager;
-   private Notifier notifier;
+   private NotifierImpl notifier;
    private InvocationContextContainer invocationContextContainer;
    private ComponentRegistry componentRegistry;
 
@@ -78,7 +78,7 @@
 
    @Inject
    public void intialize(RPCManager rpcManager,
-                         Notifier notifier, InvocationContextContainer icc,
+                         NotifierImpl notifier, InvocationContextContainer icc,
                          CommandsFactory factory, ComponentRegistry componentRegistry)
    {
       this.commandsFactory = factory;

Modified: core/trunk/src/main/java/org/jboss/cache/invocation/CacheInvocationDelegate.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/invocation/CacheInvocationDelegate.java	2008-05-14 17:05:33 UTC (rev 5849)
+++ core/trunk/src/main/java/org/jboss/cache/invocation/CacheInvocationDelegate.java	2008-05-15 12:44:49 UTC (rev 5850)
@@ -23,7 +23,7 @@
 import org.jboss.cache.interceptors.base.CommandInterceptor;
 import org.jboss.cache.loader.CacheLoaderManager;
 import org.jboss.cache.marshall.Marshaller;
-import org.jboss.cache.notifications.Notifier;
+import org.jboss.cache.notifications.NotifierImpl;
 import org.jboss.cache.statetransfer.StateTransferManager;
 import org.jboss.cache.transaction.GlobalTransaction;
 import org.jboss.cache.transaction.TransactionTable;
@@ -51,21 +51,21 @@
    // this stuff is needed since the SPI has methods to retrieve these.
    private StateTransferManager stateTransferManager;
    private CacheLoaderManager cacheLoaderManager;
-   private Notifier notifier;
+   private NotifierImpl notifier;
    private TransactionManager transactionManager;
    private BuddyManager buddyManager;
    private TransactionTable transactionTable;
    private RPCManager rpcManager;
    private RegionManager regionManager;
    private Marshaller marshaller;
-   private DataContainer dataContainer;
+   private DataContainerImpl dataContainer;
    private CommandsFactory commandsFactory;
 
    @Inject
-   public void initialize(StateTransferManager stateTransferManager, CacheLoaderManager cacheLoaderManager, Notifier notifier,
+   public void initialize(StateTransferManager stateTransferManager, CacheLoaderManager cacheLoaderManager, NotifierImpl notifier,
                           TransactionManager transactionManager, BuddyManager buddyManager, TransactionTable transactionTable,
                           RPCManager rpcManager, RegionManager regionManager, Marshaller marshaller,
-                          CommandsFactory commandsFactory, DataContainer dataContainer)
+                          CommandsFactory commandsFactory, DataContainerImpl dataContainer)
    {
       this.stateTransferManager = stateTransferManager;
       this.cacheLoaderManager = cacheLoaderManager;
@@ -214,7 +214,7 @@
       return peek(fqn, false, false) != null;
    }
 
-   public Notifier getNotifier()
+   public NotifierImpl getNotifier()
    {
       return notifier;
    }
@@ -574,7 +574,7 @@
       return getChildrenNames(Fqn.fromString(fqn));
    }
 
-   public DataContainer getDataContainer()
+   public DataContainerImpl getDataContainer()
    {
       return dataContainer;
    }

Modified: core/trunk/src/main/java/org/jboss/cache/lock/LockManager.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/lock/LockManager.java	2008-05-14 17:05:33 UTC (rev 5849)
+++ core/trunk/src/main/java/org/jboss/cache/lock/LockManager.java	2008-05-15 12:44:49 UTC (rev 5850)
@@ -2,7 +2,7 @@
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
-import org.jboss.cache.DataContainer;
+import org.jboss.cache.DataContainerImpl;
 import org.jboss.cache.Fqn;
 import org.jboss.cache.InvocationContext;
 import org.jboss.cache.NodeSPI;
@@ -31,13 +31,13 @@
 
    private Configuration configuration;
    private long lockAcquisitionTimeout;
-   private DataContainer dataContainer;
+   private DataContainerImpl dataContainer;
    private NodeSPI rootNode;
    private TransactionTable txTable;
    private CommandsFactory commandsFactory;
 
    @Inject
-   public void inject(Configuration configuration, DataContainer dataContainer, TransactionTable txTable,
+   public void inject(Configuration configuration, DataContainerImpl dataContainer, TransactionTable txTable,
                       CommandsFactory commandsFactory)
    {
       this.configuration = configuration;

Deleted: core/trunk/src/main/java/org/jboss/cache/notifications/Notifier.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/notifications/Notifier.java	2008-05-14 17:05:33 UTC (rev 5849)
+++ core/trunk/src/main/java/org/jboss/cache/notifications/Notifier.java	2008-05-15 12:44:49 UTC (rev 5850)
@@ -1,733 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source
- *
- * Distributable under LGPL license.
- * See terms of license at gnu.org.
- */
-package org.jboss.cache.notifications;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.jboss.cache.Cache;
-import org.jboss.cache.CacheException;
-import org.jboss.cache.CacheSPI;
-import org.jboss.cache.Fqn;
-import org.jboss.cache.InvocationContext;
-import org.jboss.cache.buddyreplication.BuddyGroup;
-import org.jboss.cache.config.Configuration;
-import org.jboss.cache.factories.annotations.Destroy;
-import org.jboss.cache.factories.annotations.Inject;
-import org.jboss.cache.factories.annotations.NonVolatile;
-import org.jboss.cache.factories.annotations.Start;
-import org.jboss.cache.factories.annotations.Stop;
-import org.jboss.cache.marshall.MarshalledValueMap;
-import org.jboss.cache.notifications.annotation.*;
-import org.jboss.cache.notifications.event.*;
-import static org.jboss.cache.notifications.event.Event.Type.*;
-import org.jboss.cache.util.MapCopy;
-import org.jgroups.View;
-
-import javax.transaction.Transaction;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.CopyOnWriteArrayList;
-
-/**
- * Helper class that handles all notifications to registered listeners.
- *
- * @author <a href="mailto:manik at jboss.org">Manik Surtani (manik at jboss.org)</a>
- */
- at NonVolatile
-public class Notifier
-{
-   private static final Log log = LogFactory.getLog(Notifier.class);
-
-   private static final Class emptyMap = Collections.emptyMap().getClass();
-
-   private static final Class singletonMap = Collections.singletonMap(null, null).getClass();
-   private static final Class[] allowedMethodAnnotations =
-         {
-               CacheStarted.class, CacheStopped.class, CacheBlocked.class, CacheUnblocked.class, NodeCreated.class, NodeRemoved.class, NodeVisited.class, NodeModified.class, NodeMoved.class,
-               NodeActivated.class, NodePassivated.class, NodeLoaded.class, NodeEvicted.class, TransactionRegistered.class, TransactionCompleted.class, ViewChanged.class, BuddyGroupChanged.class
-         };
-   private static final Class[] parameterTypes =
-         {
-               CacheStartedEvent.class, CacheStoppedEvent.class, CacheBlockedEvent.class, CacheUnblockedEvent.class, NodeCreatedEvent.class, NodeRemovedEvent.class, NodeVisitedEvent.class, NodeModifiedEvent.class, NodeMovedEvent.class,
-               NodeActivatedEvent.class, NodePassivatedEvent.class, NodeLoadedEvent.class, NodeEvictedEvent.class, TransactionRegisteredEvent.class, TransactionCompletedEvent.class, ViewChangedEvent.class, BuddyGroupChangedEvent.class
-         };
-
-
-   final Map<Class, List<ListenerInvocation>> listenerInvocations = new ConcurrentHashMap<Class, List<ListenerInvocation>>();
-   private Cache cache;
-   private boolean useMarshalledValueMaps;
-   private Configuration config;
-
-   public Notifier()
-   {
-   }
-
-   public Notifier(Cache cache)
-   {
-      this.cache = cache;
-   }
-
-   @Inject
-   private void injectDependencies(CacheSPI cache, Configuration config)
-   {
-      this.cache = cache;
-      this.config = config;
-   }
-
-   @Destroy
-   protected void destroy()
-   {
-      listenerInvocations.clear();
-   }
-
-   @Start
-   protected void start()
-   {
-      useMarshalledValueMaps = config.isUseLazyDeserialization();
-   }
-
-   /**
-    * Loops through all valid methods on the object passed in, and caches the relevant methods as {@link org.jboss.cache.notifications.Notifier.ListenerInvocation}
-    * for invocation by reflection.
-    *
-    * @param listener object to be considered as a listener.
-    */
-   private void validateAndAddListenerInvocation(Object listener)
-   {
-      testListenerClassValidity(listener.getClass());
-
-      boolean foundMethods = false;
-      // now try all methods on the listener for anything that we like.  Note that only PUBLIC methods are scanned.
-      for (Method m : listener.getClass().getMethods())
-      {
-         // loop through all valid method annotations
-         for (int i = 0; i < allowedMethodAnnotations.length; i++)
-         {
-            if (m.isAnnotationPresent(allowedMethodAnnotations[i]))
-            {
-               testListenerMethodValidity(m, parameterTypes[i], allowedMethodAnnotations[i].getName());
-               addListenerInvocation(allowedMethodAnnotations[i], new ListenerInvocation(listener, m));
-               foundMethods = true;
-            }
-         }
-      }
-
-      if (!foundMethods && log.isWarnEnabled())
-         log.warn("Attempted to register listener of class " + listener.getClass() + ", but no valid, public methods annotated with method-level event annotations found! Ignoring listener.");
-   }
-
-   private static void testListenerClassValidity(Class<?> listenerClass)
-   {
-      if (!listenerClass.isAnnotationPresent(CacheListener.class))
-         throw new IncorrectCacheListenerException("Cache listener class MUST be annotated with org.jboss.cache.notifications.annotation.CacheListener");
-      if (!Modifier.isPublic(listenerClass.getModifiers()))
-         throw new IncorrectCacheListenerException("Cache listener class MUST be public!");
-   }
-
-   private static void testListenerMethodValidity(Method m, Class allowedParameter, String annotationName)
-   {
-      if (m.getParameterTypes().length != 1 || !m.getParameterTypes()[0].isAssignableFrom(allowedParameter))
-         throw new IncorrectCacheListenerException("Methods annotated with " + annotationName + " must accept exactly one parameter, of assignable from type " + allowedParameter.getName());
-      if (!m.getReturnType().equals(void.class))
-         throw new IncorrectCacheListenerException("Methods annotated with " + annotationName + " should have a return type of void.");
-   }
-
-   private void addListenerInvocation(Class annotation, ListenerInvocation li)
-   {
-      synchronized (listenerInvocations)
-      {
-         List<ListenerInvocation> l = listenerInvocations.get(annotation);
-         if (l == null)
-         {
-            l = new CopyOnWriteArrayList<ListenerInvocation>();
-            listenerInvocations.put(annotation, l);
-         }
-         l.add(li);
-      }
-   }
-
-   /**
-    * Adds a cache listener to the list of cache listeners registered.
-    *
-    * @param listener
-    */
-   public void addCacheListener(Object listener)
-   {
-      validateAndAddListenerInvocation(listener);
-   }
-
-   /**
-    * Removes a cache listener from the list of cache listeners registered.
-    *
-    * @param listener
-    */
-   public void removeCacheListener(Object listener)
-   {
-      synchronized (listenerInvocations)
-      {
-         for (Class annotation : allowedMethodAnnotations) removeListenerInvocation(annotation, listener);
-      }
-   }
-
-   private void removeListenerInvocation(Class annotation, Object listener)
-   {
-      if (listener == null) return;
-
-      List<ListenerInvocation> l = listenerInvocations.get(annotation);
-      Set<Object> markedForRemoval = new HashSet<Object>();
-      if (l != null)
-      {
-         for (ListenerInvocation li : l)
-         {
-            if (listener.equals(li.target)) markedForRemoval.add(li);
-         }
-
-         l.removeAll(markedForRemoval);
-
-         if (l.isEmpty()) listenerInvocations.remove(annotation);
-      }
-   }
-
-   /**
-    * Removes all listeners from the notifier, including the evictionPolicyListener.
-    */
-   @Stop(priority = 99)
-   public void removeAllCacheListeners()
-   {
-      synchronized (listenerInvocations)
-      {
-         listenerInvocations.clear();
-      }
-   }
-
-   /**
-    * @return Retrieves an (unmodifiable) set of cache listeners registered.
-    */
-   public Set<Object> getCacheListeners()
-   {
-      Set<Object> s = new HashSet<Object>();
-      synchronized (listenerInvocations)
-      {
-         for (Class annotation : allowedMethodAnnotations)
-         {
-            List<ListenerInvocation> l = listenerInvocations.get(annotation);
-            if (l != null)
-            {
-               for (ListenerInvocation li : l) s.add(li.target);
-            }
-         }
-      }
-      return Collections.unmodifiableSet(s);
-   }
-
-   /**
-    * Notifies all registered listeners of a nodeCreated event.
-    *
-    * @param fqn
-    * @param pre
-    * @param ctx context of invocation
-    */
-   public void notifyNodeCreated(Fqn fqn, boolean pre, InvocationContext ctx)
-   {
-      List<ListenerInvocation> listeners = listenerInvocations.get(NodeCreated.class);
-
-      if (listeners != null && !listeners.isEmpty())
-      {
-         boolean originLocal = ctx.isOriginLocal();
-         Transaction tx = ctx.getTransaction();
-         InvocationContext backup = resetInvocationContext(ctx);
-         EventImpl e = new EventImpl();
-         e.setCache(cache);
-         e.setOriginLocal(originLocal);
-         e.setPre(pre);
-         e.setFqn(fqn);
-         e.setTransaction(tx);
-         e.setType(NODE_CREATED);
-         for (ListenerInvocation listener : listeners) listener.invoke(e);
-         restoreInvocationContext(backup);
-      }
-   }
-
-   /**
-    * Notifies all registered listeners of a nodeModified event.
-    *
-    * @param fqn
-    * @param pre
-    * @param modificationType
-    * @param data
-    * @param ctx              context of invocation
-    */
-   public void notifyNodeModified(Fqn fqn, boolean pre, NodeModifiedEvent.ModificationType modificationType, Map data, InvocationContext ctx)
-   {
-      List<ListenerInvocation> listeners = listenerInvocations.get(NodeModified.class);
-
-      if (listeners != null && !listeners.isEmpty())
-      {
-         boolean originLocal = ctx.isOriginLocal();
-         Map dataCopy = copy(data, useMarshalledValueMaps);
-         Transaction tx = ctx.getTransaction();
-         InvocationContext backup = resetInvocationContext(ctx);
-         EventImpl e = new EventImpl();
-         e.setCache(cache);
-         e.setOriginLocal(originLocal);
-         e.setPre(pre);
-         e.setFqn(fqn);
-         e.setTransaction(tx);
-         e.setModificationType(modificationType);
-         e.setData(dataCopy);
-         e.setType(NODE_MODIFIED);
-         for (ListenerInvocation listener : listeners) listener.invoke(e);
-         restoreInvocationContext(backup);
-      }
-   }
-
-   /**
-    * Notifies all registered listeners of a nodeRemoved event.
-    *
-    * @param fqn
-    * @param pre
-    * @param data
-    * @param ctx  context of invocation
-    */
-   public void notifyNodeRemoved(Fqn fqn, boolean pre, Map data, InvocationContext ctx)
-   {
-      List<ListenerInvocation> listeners = listenerInvocations.get(NodeRemoved.class);
-
-      if (listeners != null && !listeners.isEmpty())
-      {
-         boolean originLocal = ctx.isOriginLocal();
-         Map dataCopy = copy(data, useMarshalledValueMaps);
-         Transaction tx = ctx.getTransaction();
-         InvocationContext backup = resetInvocationContext(ctx);
-         EventImpl e = new EventImpl();
-         e.setCache(cache);
-         e.setOriginLocal(originLocal);
-         e.setPre(pre);
-         e.setFqn(fqn);
-         e.setTransaction(tx);
-         e.setData(dataCopy);
-         e.setType(NODE_REMOVED);
-         for (ListenerInvocation listener : listeners) listener.invoke(e);
-         restoreInvocationContext(backup);
-      }
-   }
-
-   /**
-    * Notifies all registered listeners of a nodeVisited event.
-    *
-    * @param fqn
-    * @param pre
-    * @param ctx context of invocation
-    */
-   public void notifyNodeVisited(Fqn fqn, boolean pre, InvocationContext ctx)
-   {
-      List<ListenerInvocation> listeners = listenerInvocations.get(NodeVisited.class);
-
-      if (listeners != null && !listeners.isEmpty())
-      {
-         Transaction tx = ctx.getTransaction();
-         InvocationContext backup = resetInvocationContext(ctx);
-         EventImpl e = new EventImpl();
-         e.setCache(cache);
-         e.setPre(pre);
-         e.setFqn(fqn);
-         e.setTransaction(tx);
-         e.setType(NODE_VISITED);
-         for (ListenerInvocation listener : listeners) listener.invoke(e);
-         restoreInvocationContext(backup);
-      }
-   }
-
-   public void notifyNodeMoved(Fqn originalFqn, Fqn newFqn, boolean pre, InvocationContext ctx)
-   {
-      List<ListenerInvocation> listeners = listenerInvocations.get(NodeMoved.class);
-
-      if (listeners != null && !listeners.isEmpty())
-      {
-         boolean originLocal = ctx.isOriginLocal();
-         Transaction tx = ctx.getTransaction();
-         InvocationContext backup = resetInvocationContext(ctx);
-         EventImpl e = new EventImpl();
-         e.setCache(cache);
-         e.setOriginLocal(originLocal);
-         e.setPre(pre);
-         e.setFqn(originalFqn);
-         e.setTargetFqn(newFqn);
-         e.setTransaction(tx);
-         e.setType(NODE_MOVED);
-         for (ListenerInvocation listener : listeners) listener.invoke(e);
-         restoreInvocationContext(backup);
-      }
-   }
-
-
-   /**
-    * Notifies all registered listeners of a nodeEvicted event.
-    *
-    * @param fqn
-    * @param pre
-    * @param ctx context of invocation
-    */
-   public void notifyNodeEvicted(final Fqn fqn, final boolean pre, InvocationContext ctx)
-   {
-      List<ListenerInvocation> listeners = listenerInvocations.get(NodeEvicted.class);
-
-      if (listeners != null && !listeners.isEmpty())
-      {
-         final boolean originLocal = ctx.isOriginLocal();
-         Transaction tx = ctx.getTransaction();
-         InvocationContext backup = resetInvocationContext(ctx);
-         EventImpl e = new EventImpl();
-         e.setCache(cache);
-         e.setOriginLocal(originLocal);
-         e.setPre(pre);
-         e.setFqn(fqn);
-         e.setTransaction(tx);
-         e.setType(NODE_EVICTED);
-         for (ListenerInvocation listener : listeners) listener.invoke(e);
-         restoreInvocationContext(backup);
-      }
-   }
-
-   /**
-    * Notifies all registered listeners of a nodeLoaded event.
-    *
-    * @param fqn
-    * @param pre
-    * @param data
-    * @param ctx  context of invocation
-    */
-   public void notifyNodeLoaded(Fqn fqn, boolean pre, Map data, InvocationContext ctx)
-   {
-      List<ListenerInvocation> listeners = listenerInvocations.get(NodeLoaded.class);
-
-      if (listeners != null && !listeners.isEmpty())
-      {
-         boolean originLocal = ctx.isOriginLocal();
-         Map dataCopy = copy(data, useMarshalledValueMaps);
-         Transaction tx = ctx.getTransaction();
-         InvocationContext backup = resetInvocationContext(ctx);
-         EventImpl e = new EventImpl();
-         e.setCache(cache);
-         e.setOriginLocal(originLocal);
-         e.setPre(pre);
-         e.setFqn(fqn);
-         e.setTransaction(tx);
-         e.setData(dataCopy);
-         e.setType(NODE_LOADED);
-         for (ListenerInvocation listener : listeners) listener.invoke(e);
-         restoreInvocationContext(backup);
-      }
-   }
-
-   /**
-    * Notifies all registered listeners of a nodeActivated event.
-    *
-    * @param fqn
-    * @param pre
-    * @param data
-    * @param ctx  context of invocation
-    */
-   public void notifyNodeActivated(Fqn fqn, boolean pre, Map data, InvocationContext ctx)
-   {
-      List<ListenerInvocation> listeners = listenerInvocations.get(NodeActivated.class);
-
-      if (listeners != null && !listeners.isEmpty())
-      {
-         boolean originLocal = ctx.isOriginLocal();
-         Map dataCopy = copy(data, useMarshalledValueMaps);
-         Transaction tx = ctx.getTransaction();
-         InvocationContext backup = resetInvocationContext(ctx);
-         EventImpl e = new EventImpl();
-         e.setCache(cache);
-         e.setOriginLocal(originLocal);
-         e.setPre(pre);
-         e.setFqn(fqn);
-         e.setTransaction(tx);
-         e.setData(dataCopy);
-         e.setType(NODE_ACTIVATED);
-         for (ListenerInvocation listener : listeners) listener.invoke(e);
-         restoreInvocationContext(backup);
-      }
-   }
-
-   /**
-    * Notifies all registered listeners of a nodePassivated event.
-    *
-    * @param fqn
-    * @param pre
-    * @param data
-    * @param ctx  context of invocation
-    */
-   public void notifyNodePassivated(Fqn fqn, boolean pre, Map data, InvocationContext ctx)
-   {
-      List<ListenerInvocation> listeners = listenerInvocations.get(NodePassivated.class);
-
-      if (listeners != null && !listeners.isEmpty())
-      {
-         Map dataCopy = copy(data, useMarshalledValueMaps);
-         Transaction tx = ctx.getTransaction();
-         InvocationContext backup = resetInvocationContext(ctx);
-         EventImpl e = new EventImpl();
-         e.setCache(cache);
-         e.setPre(pre);
-         e.setFqn(fqn);
-         e.setTransaction(tx);
-         e.setData(dataCopy);
-         e.setType(NODE_PASSIVATED);
-         for (ListenerInvocation listener : listeners) listener.invoke(e);
-         restoreInvocationContext(backup);
-      }
-   }
-
-   /**
-    * Notifies all registered listeners of a cacheStarted event.
-    */
-   @Start(priority = 99)
-   public void notifyCacheStarted()
-   {
-      List<ListenerInvocation> listeners = listenerInvocations.get(CacheStarted.class);
-
-      if (listeners != null && !listeners.isEmpty())
-      {
-         EventImpl e = new EventImpl();
-         e.setCache(cache);
-         e.setType(CACHE_STARTED);
-         for (ListenerInvocation listener : listeners) listener.invoke(e);
-      }
-   }
-
-   /**
-    * Notifies all registered listeners of a cacheStopped event.
-    */
-   @Stop(priority = 98)
-   public void notifyCacheStopped()
-   {
-      List<ListenerInvocation> listeners = listenerInvocations.get(CacheStopped.class);
-
-      if (listeners != null && !listeners.isEmpty())
-      {
-         EventImpl e = new EventImpl();
-         e.setCache(cache);
-         e.setType(CACHE_STOPPED);
-         for (ListenerInvocation listener : listeners) listener.invoke(e);
-      }
-   }
-
-   /**
-    * Notifies all registered listeners of a viewChange event.  Note that viewChange notifications are ALWAYS sent
-    * immediately.
-    *
-    * @param new_view
-    * @param ctx      context of invocation
-    */
-   public void notifyViewChange(final View new_view, InvocationContext ctx)
-   {
-      List<ListenerInvocation> listeners = listenerInvocations.get(ViewChanged.class);
-
-      if (listeners != null && !listeners.isEmpty())
-      {
-         InvocationContext backup = resetInvocationContext(ctx);
-         EventImpl e = new EventImpl();
-         e.setCache(cache);
-         e.setNewView(new_view);
-         e.setType(VIEW_CHANGED);
-         for (ListenerInvocation listener : listeners) listener.invoke(e);
-         restoreInvocationContext(backup);
-      }
-   }
-
-   /**
-    * Notifies all registered listeners of a buddy group change event.  Note that buddy group change notifications are ALWAYS sent
-    * immediately.
-    *
-    * @param buddyGroup buddy group to set
-    * @param pre        if true, this has occured before the buddy group message is broadcast to the cluster
-    */
-   public void notifyBuddyGroupChange(final BuddyGroup buddyGroup, boolean pre)
-   {
-      List<ListenerInvocation> listeners = listenerInvocations.get(BuddyGroupChanged.class);
-
-      if (listeners != null && !listeners.isEmpty())
-      {
-         EventImpl e = new EventImpl();
-         e.setCache(cache);
-         e.setBuddyGroup(buddyGroup);
-         e.setPre(pre);
-         e.setType(BUDDY_GROUP_CHANGED);
-         for (ListenerInvocation listener : listeners) listener.invoke(e);
-      }
-   }
-
-   /**
-    * Notifies all registered listeners of a transaction completion event.
-    *
-    * @param transaction the transaction that has just completed
-    * @param successful  if true, the transaction committed.  If false, this is a rollback event
-    */
-   public void notifyTransactionCompleted(Transaction transaction, boolean successful, InvocationContext ctx)
-   {
-      List<ListenerInvocation> listeners = listenerInvocations.get(TransactionCompleted.class);
-
-      if (listeners != null && !listeners.isEmpty())
-      {
-         Transaction tx = ctx.getTransaction();
-         boolean isOriginLocal = ctx.isOriginLocal();
-         InvocationContext backup = resetInvocationContext(ctx);
-         EventImpl e = new EventImpl();
-         e.setCache(cache);
-         e.setOriginLocal(isOriginLocal);
-         e.setTransaction(tx);
-         e.setSuccessful(successful);
-         e.setType(TRANSACTION_COMPLETED);
-         for (ListenerInvocation listener : listeners) listener.invoke(e);
-         restoreInvocationContext(backup);
-      }
-   }
-
-   /**
-    * Notifies all registered listeners of a transaction registration event.
-    *
-    * @param transaction the transaction that has just completed
-    */
-   public void notifyTransactionRegistered(Transaction transaction, InvocationContext ctx)
-   {
-      List<ListenerInvocation> listeners = listenerInvocations.get(TransactionRegistered.class);
-
-      if (listeners != null && !listeners.isEmpty())
-      {
-         Transaction tx = ctx.getTransaction();
-         boolean isOriginLocal = ctx.isOriginLocal();
-         InvocationContext backup = resetInvocationContext(ctx);
-         EventImpl e = new EventImpl();
-         e.setCache(cache);
-         e.setOriginLocal(isOriginLocal);
-         e.setTransaction(tx);
-         e.setType(TRANSACTION_REGISTERED);
-         for (ListenerInvocation listener : listeners) listener.invoke(e);
-         restoreInvocationContext(backup);
-      }
-   }
-
-   public void notifyCacheBlocked(CacheSPI cache, boolean pre)
-   {
-      List<ListenerInvocation> listeners = listenerInvocations.get(CacheBlocked.class);
-
-      if (listeners != null && !listeners.isEmpty())
-      {
-         EventImpl e = new EventImpl();
-         e.setCache(cache);
-         e.setPre(pre);
-         e.setType(CACHE_BLOCKED);
-         for (ListenerInvocation listener : listeners) listener.invoke(e);
-      }
-   }
-
-   public void notifyCacheUnblocked(CacheSPI cache, boolean pre)
-   {
-      List<ListenerInvocation> listeners = listenerInvocations.get(CacheUnblocked.class);
-
-      if (listeners != null && !listeners.isEmpty())
-      {
-         EventImpl e = new EventImpl();
-         e.setCache(cache);
-         e.setPre(pre);
-         e.setType(CACHE_UNBLOCKED);
-         for (ListenerInvocation listener : listeners) listener.invoke(e);
-      }
-   }
-
-   private static Map copy(Map data, boolean useMarshalledValueMaps)
-   {
-      if (data == null) return null;
-      if (data.isEmpty()) return Collections.emptyMap();
-      if (safe(data)) return useMarshalledValueMaps ? new MarshalledValueMap(data) : data;
-      Map defensivelyCopiedData = new MapCopy(data);
-      return useMarshalledValueMaps ? new MarshalledValueMap(defensivelyCopiedData) : defensivelyCopiedData;
-   }
-
-   private void restoreInvocationContext(InvocationContext backup)
-   {
-      cache.setInvocationContext(backup);
-   }
-
-   /**
-    * Resets the current (passed-in) invocation, and returns a temp InvocationContext containing its state so it can
-    * be restored later using {@link #restoreInvocationContext(org.jboss.cache.InvocationContext)}
-    *
-    * @param ctx the current context to be reset
-    * @return a clone of ctx, before it was reset
-    */
-   private InvocationContext resetInvocationContext(InvocationContext ctx)
-   {
-      // wipe current context.
-      cache.setInvocationContext(null);
-      return ctx;
-   }
-
-   /**
-    * A map is deemed 'safe' to be passed as-is to a listener, if either of the following are true:
-    * <ul>
-    * <li>It is null</li>
-    * <li>It is an instance of {@link org.jboss.cache.util.MapCopy}, which is immutable</li>
-    * <li>It is an instance of {@link java.util.Collections#emptyMap()}, which is also immutable</li>
-    * <li>It is an instance of {@link java.util.Collections#singletonMap(Object,Object)}, which is also immutable</li>
-    * </ul>
-    *
-    * @param map
-    * @return
-    */
-   private static boolean safe(Map map)
-   {
-      return map == null || map instanceof MapCopy || map.getClass().equals(emptyMap) || map.getClass().equals(singletonMap);
-   }
-
-   /**
-    * Class that encapsulates a valid invocation for a given registered listener - containing a reference to the
-    * method to be invoked as well as the target object.
-    */
-   class ListenerInvocation
-   {
-      private final Object target;
-      private final Method method;
-
-      public ListenerInvocation(Object target, Method method)
-      {
-         this.target = target;
-         this.method = method;
-      }
-
-      public void invoke(Event e)
-      {
-         try
-         {
-            method.invoke(target, e);
-         }
-         catch (InvocationTargetException e1)
-         {
-            Throwable cause = e1.getCause();
-            if (cause != null)
-               throw new CacheException("Caught exception invoking method " + method + " on listener instance " + target, cause);
-            else
-               throw new CacheException("Caught exception invoking method " + method + " on listener instance " + target, e1);
-         }
-         catch (IllegalAccessException e1)
-         {
-            log.warn("Unable to invoke method " + method + " on Object instance " + target + " - removing this target object from list of listeners!", e1);
-            removeCacheListener(this.target);
-         }
-      }
-   }
-
-}

Added: core/trunk/src/main/java/org/jboss/cache/notifications/Notifier.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/notifications/Notifier.java	                        (rev 0)
+++ core/trunk/src/main/java/org/jboss/cache/notifications/Notifier.java	2008-05-15 12:44:49 UTC (rev 5850)
@@ -0,0 +1,99 @@
+package org.jboss.cache.notifications;
+
+import org.jboss.cache.Fqn;
+import org.jboss.cache.InvocationContext;
+import org.jboss.cache.CacheSPI;
+import org.jboss.cache.buddyreplication.BuddyGroup;
+import org.jboss.cache.factories.annotations.Start;
+import org.jboss.cache.factories.annotations.Stop;
+import org.jboss.cache.notifications.event.NodeModifiedEvent;
+import org.jgroups.View;
+
+import javax.transaction.Transaction;
+import java.util.Map;
+
+/**
+ * @author Mircea.Markus at jboss.com
+ * @since 2.2
+ */
+public interface Notifier
+{
+   /**
+    * Notifies all registered listeners of a nodeCreated event.
+    */
+   void notifyNodeCreated(Fqn fqn, boolean pre, InvocationContext ctx);
+
+   /**
+    * Notifies all registered listeners of a nodeModified event.
+    */
+   void notifyNodeModified(Fqn fqn, boolean pre, NodeModifiedEvent.ModificationType modificationType, Map data, InvocationContext ctx);
+
+   /**
+    * Notifies all registered listeners of a nodeRemoved event.
+    */
+   void notifyNodeRemoved(Fqn fqn, boolean pre, Map data, InvocationContext ctx);
+
+   /**
+    * Notifies all registered listeners of a nodeVisited event.
+    */
+   void notifyNodeVisited(Fqn fqn, boolean pre, InvocationContext ctx);
+
+   /**
+    * Notifies all registered listeners of a nodeMoved event.
+    */
+   void notifyNodeMoved(Fqn originalFqn, Fqn newFqn, boolean pre, InvocationContext ctx);
+
+   /**
+    * Notifies all registered listeners of a nodeEvicted event.
+    */
+   void notifyNodeEvicted(Fqn fqn, boolean pre, InvocationContext ctx);
+
+   /**
+    * Notifies all registered listeners of a nodeLoaded event.
+    */
+   void notifyNodeLoaded(Fqn fqn, boolean pre, Map data, InvocationContext ctx);
+
+   /**
+    * Notifies all registered listeners of a nodeActivated event.
+    */
+   void notifyNodeActivated(Fqn fqn, boolean pre, Map data, InvocationContext ctx);
+
+   /**
+    * Notifies all registered listeners of a nodePassivated event.
+    */
+   void notifyNodePassivated(Fqn fqn, boolean pre, Map data, InvocationContext ctx);
+
+   /**
+    * Notifies all registered listeners of a viewChange event.  Note that viewChange notifications are ALWAYS sent
+    * immediately.
+    */
+   void notifyViewChange(View new_view, InvocationContext ctx);
+
+   /**
+    * Notifies all registered listeners of a buddy group change event.  Note that buddy group change notifications are ALWAYS sent
+    * immediately.
+    *
+    * @param buddyGroup buddy group to set
+    * @param pre        if true, this has occured before the buddy group message is broadcast to the cluster
+    */
+   void notifyBuddyGroupChange(BuddyGroup buddyGroup, boolean pre);
+
+   /**
+    * Notifies all registered listeners of a transaction completion event.
+    *
+    * @param transaction the transaction that has just completed
+    * @param successful  if true, the transaction committed.  If false, this is a rollback event
+    */
+   void notifyTransactionCompleted(Transaction transaction, boolean successful, InvocationContext ctx);
+
+   /**
+    * Notifies all registered listeners of a transaction registration event.
+    *
+    * @param transaction the transaction that has just completed
+    */
+   void notifyTransactionRegistered(Transaction transaction, InvocationContext ctx);
+
+   void notifyCacheBlocked(CacheSPI cache, boolean pre);
+
+   void notifyCacheUnblocked(CacheSPI cache, boolean pre);
+}

Copied: core/trunk/src/main/java/org/jboss/cache/notifications/NotifierImpl.java (from rev 5840, core/trunk/src/main/java/org/jboss/cache/notifications/Notifier.java)
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/notifications/NotifierImpl.java	                        (rev 0)
+++ core/trunk/src/main/java/org/jboss/cache/notifications/NotifierImpl.java	2008-05-15 12:44:49 UTC (rev 5850)
@@ -0,0 +1,633 @@
+/*
+ * JBoss, Home of Professional Open Source
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package org.jboss.cache.notifications;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.jboss.cache.*;
+import org.jboss.cache.buddyreplication.BuddyGroup;
+import org.jboss.cache.config.Configuration;
+import org.jboss.cache.factories.annotations.*;
+import org.jboss.cache.marshall.MarshalledValueMap;
+import org.jboss.cache.notifications.annotation.*;
+import org.jboss.cache.notifications.event.*;
+import static org.jboss.cache.notifications.event.Event.Type.*;
+import org.jboss.cache.util.MapCopy;
+import org.jgroups.View;
+
+import javax.transaction.Transaction;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+/**
+ * Helper class that handles all notifications to registered listeners.
+ *
+ * @author <a href="mailto:manik at jboss.org">Manik Surtani (manik at jboss.org)</a>
+ */
+ at NonVolatile
+public class NotifierImpl implements Notifier
+{
+   private static final Log log = LogFactory.getLog(NotifierImpl.class);
+
+   private static final Class emptyMap = Collections.emptyMap().getClass();
+
+   private static final Class singletonMap = Collections.singletonMap(null, null).getClass();
+   private static final Class[] allowedMethodAnnotations =
+         {
+               CacheStarted.class, CacheStopped.class, CacheBlocked.class, CacheUnblocked.class, NodeCreated.class, NodeRemoved.class, NodeVisited.class, NodeModified.class, NodeMoved.class,
+               NodeActivated.class, NodePassivated.class, NodeLoaded.class, NodeEvicted.class, TransactionRegistered.class, TransactionCompleted.class, ViewChanged.class, BuddyGroupChanged.class
+         };
+   private static final Class[] parameterTypes =
+         {
+               CacheStartedEvent.class, CacheStoppedEvent.class, CacheBlockedEvent.class, CacheUnblockedEvent.class, NodeCreatedEvent.class, NodeRemovedEvent.class, NodeVisitedEvent.class, NodeModifiedEvent.class, NodeMovedEvent.class,
+               NodeActivatedEvent.class, NodePassivatedEvent.class, NodeLoadedEvent.class, NodeEvictedEvent.class, TransactionRegisteredEvent.class, TransactionCompletedEvent.class, ViewChangedEvent.class, BuddyGroupChangedEvent.class
+         };
+
+
+   final Map<Class, List<ListenerInvocation>> listenerInvocations = new ConcurrentHashMap<Class, List<ListenerInvocation>>();
+   private Cache cache;
+   private boolean useMarshalledValueMaps;
+   private Configuration config;
+
+   public NotifierImpl()
+   {
+   }
+
+   public NotifierImpl(Cache cache)
+   {
+      this.cache = cache;
+   }
+
+   @Inject
+   private void injectDependencies(CacheSPI cache, Configuration config)
+   {
+      this.cache = cache;
+      this.config = config;
+   }
+
+   @Destroy
+   protected void destroy()
+   {
+      listenerInvocations.clear();
+   }
+
+   @Start
+   protected void start()
+   {
+      useMarshalledValueMaps = config.isUseLazyDeserialization();
+   }
+
+   /**
+    * Loops through all valid methods on the object passed in, and caches the relevant methods as {@link NotifierImpl.ListenerInvocation}
+    * for invocation by reflection.
+    *
+    * @param listener object to be considered as a listener.
+    */
+   private void validateAndAddListenerInvocation(Object listener)
+   {
+      testListenerClassValidity(listener.getClass());
+
+      boolean foundMethods = false;
+      // now try all methods on the listener for anything that we like.  Note that only PUBLIC methods are scanned.
+      for (Method m : listener.getClass().getMethods())
+      {
+         // loop through all valid method annotations
+         for (int i = 0; i < allowedMethodAnnotations.length; i++)
+         {
+            if (m.isAnnotationPresent(allowedMethodAnnotations[i]))
+            {
+               testListenerMethodValidity(m, parameterTypes[i], allowedMethodAnnotations[i].getName());
+               addListenerInvocation(allowedMethodAnnotations[i], new ListenerInvocation(listener, m));
+               foundMethods = true;
+            }
+         }
+      }
+
+      if (!foundMethods && log.isWarnEnabled())
+         log.warn("Attempted to register listener of class " + listener.getClass() + ", but no valid, public methods annotated with method-level event annotations found! Ignoring listener.");
+   }
+
+   private static void testListenerClassValidity(Class<?> listenerClass)
+   {
+      if (!listenerClass.isAnnotationPresent(CacheListener.class))
+         throw new IncorrectCacheListenerException("Cache listener class MUST be annotated with org.jboss.cache.notifications.annotation.CacheListener");
+      if (!Modifier.isPublic(listenerClass.getModifiers()))
+         throw new IncorrectCacheListenerException("Cache listener class MUST be public!");
+   }
+
+   private static void testListenerMethodValidity(Method m, Class allowedParameter, String annotationName)
+   {
+      if (m.getParameterTypes().length != 1 || !m.getParameterTypes()[0].isAssignableFrom(allowedParameter))
+         throw new IncorrectCacheListenerException("Methods annotated with " + annotationName + " must accept exactly one parameter, of assignable from type " + allowedParameter.getName());
+      if (!m.getReturnType().equals(void.class))
+         throw new IncorrectCacheListenerException("Methods annotated with " + annotationName + " should have a return type of void.");
+   }
+
+   private void addListenerInvocation(Class annotation, ListenerInvocation li)
+   {
+      synchronized (listenerInvocations)
+      {
+         List<ListenerInvocation> l = listenerInvocations.get(annotation);
+         if (l == null)
+         {
+            l = new CopyOnWriteArrayList<ListenerInvocation>();
+            listenerInvocations.put(annotation, l);
+         }
+         l.add(li);
+      }
+   }
+
+   /**
+    * Adds a cache listener to the list of cache listeners registered.
+    *
+    * @param listener
+    */
+   public void addCacheListener(Object listener)
+   {
+      validateAndAddListenerInvocation(listener);
+   }
+
+   /**
+    * Removes a cache listener from the list of cache listeners registered.
+    *
+    * @param listener
+    */
+   public void removeCacheListener(Object listener)
+   {
+      synchronized (listenerInvocations)
+      {
+         for (Class annotation : allowedMethodAnnotations) removeListenerInvocation(annotation, listener);
+      }
+   }
+
+   private void removeListenerInvocation(Class annotation, Object listener)
+   {
+      if (listener == null) return;
+
+      List<ListenerInvocation> l = listenerInvocations.get(annotation);
+      Set<Object> markedForRemoval = new HashSet<Object>();
+      if (l != null)
+      {
+         for (ListenerInvocation li : l)
+         {
+            if (listener.equals(li.target)) markedForRemoval.add(li);
+         }
+
+         l.removeAll(markedForRemoval);
+
+         if (l.isEmpty()) listenerInvocations.remove(annotation);
+      }
+   }
+
+   /**
+    * Removes all listeners from the notifier, including the evictionPolicyListener.
+    */
+   @Stop(priority = 99)
+   public void removeAllCacheListeners()
+   {
+      synchronized (listenerInvocations)
+      {
+         listenerInvocations.clear();
+      }
+   }
+
+   /**
+    * @return Retrieves an (unmodifiable) set of cache listeners registered.
+    */
+   public Set<Object> getCacheListeners()
+   {
+      Set<Object> s = new HashSet<Object>();
+      synchronized (listenerInvocations)
+      {
+         for (Class annotation : allowedMethodAnnotations)
+         {
+            List<ListenerInvocation> l = listenerInvocations.get(annotation);
+            if (l != null)
+            {
+               for (ListenerInvocation li : l) s.add(li.target);
+            }
+         }
+      }
+      return Collections.unmodifiableSet(s);
+   }
+
+   public void notifyNodeCreated(Fqn fqn, boolean pre, InvocationContext ctx)
+   {
+      List<ListenerInvocation> listeners = listenerInvocations.get(NodeCreated.class);
+
+      if (listeners != null && !listeners.isEmpty())
+      {
+         boolean originLocal = ctx.isOriginLocal();
+         Transaction tx = ctx.getTransaction();
+         InvocationContext backup = resetInvocationContext(ctx);
+         EventImpl e = new EventImpl();
+         e.setCache(cache);
+         e.setOriginLocal(originLocal);
+         e.setPre(pre);
+         e.setFqn(fqn);
+         e.setTransaction(tx);
+         e.setType(NODE_CREATED);
+         for (ListenerInvocation listener : listeners) listener.invoke(e);
+         restoreInvocationContext(backup);
+      }
+   }
+
+   public void notifyNodeModified(Fqn fqn, boolean pre, NodeModifiedEvent.ModificationType modificationType, Map data, InvocationContext ctx)
+   {
+      List<ListenerInvocation> listeners = listenerInvocations.get(NodeModified.class);
+
+      if (listeners != null && !listeners.isEmpty())
+      {
+         boolean originLocal = ctx.isOriginLocal();
+         Map dataCopy = copy(data, useMarshalledValueMaps);
+         Transaction tx = ctx.getTransaction();
+         InvocationContext backup = resetInvocationContext(ctx);
+         EventImpl e = new EventImpl();
+         e.setCache(cache);
+         e.setOriginLocal(originLocal);
+         e.setPre(pre);
+         e.setFqn(fqn);
+         e.setTransaction(tx);
+         e.setModificationType(modificationType);
+         e.setData(dataCopy);
+         e.setType(NODE_MODIFIED);
+         for (ListenerInvocation listener : listeners) listener.invoke(e);
+         restoreInvocationContext(backup);
+      }
+   }
+
+   public void notifyNodeRemoved(Fqn fqn, boolean pre, Map data, InvocationContext ctx)
+   {
+      List<ListenerInvocation> listeners = listenerInvocations.get(NodeRemoved.class);
+
+      if (listeners != null && !listeners.isEmpty())
+      {
+         boolean originLocal = ctx.isOriginLocal();
+         Map dataCopy = copy(data, useMarshalledValueMaps);
+         Transaction tx = ctx.getTransaction();
+         InvocationContext backup = resetInvocationContext(ctx);
+         EventImpl e = new EventImpl();
+         e.setCache(cache);
+         e.setOriginLocal(originLocal);
+         e.setPre(pre);
+         e.setFqn(fqn);
+         e.setTransaction(tx);
+         e.setData(dataCopy);
+         e.setType(NODE_REMOVED);
+         for (ListenerInvocation listener : listeners) listener.invoke(e);
+         restoreInvocationContext(backup);
+      }
+   }
+
+   public void notifyNodeVisited(Fqn fqn, boolean pre, InvocationContext ctx)
+   {
+      List<ListenerInvocation> listeners = listenerInvocations.get(NodeVisited.class);
+
+      if (listeners != null && !listeners.isEmpty())
+      {
+         Transaction tx = ctx.getTransaction();
+         InvocationContext backup = resetInvocationContext(ctx);
+         EventImpl e = new EventImpl();
+         e.setCache(cache);
+         e.setPre(pre);
+         e.setFqn(fqn);
+         e.setTransaction(tx);
+         e.setType(NODE_VISITED);
+         for (ListenerInvocation listener : listeners) listener.invoke(e);
+         restoreInvocationContext(backup);
+      }
+   }
+
+   public void notifyNodeMoved(Fqn originalFqn, Fqn newFqn, boolean pre, InvocationContext ctx)
+   {
+      List<ListenerInvocation> listeners = listenerInvocations.get(NodeMoved.class);
+
+      if (listeners != null && !listeners.isEmpty())
+      {
+         boolean originLocal = ctx.isOriginLocal();
+         Transaction tx = ctx.getTransaction();
+         InvocationContext backup = resetInvocationContext(ctx);
+         EventImpl e = new EventImpl();
+         e.setCache(cache);
+         e.setOriginLocal(originLocal);
+         e.setPre(pre);
+         e.setFqn(originalFqn);
+         e.setTargetFqn(newFqn);
+         e.setTransaction(tx);
+         e.setType(NODE_MOVED);
+         for (ListenerInvocation listener : listeners) listener.invoke(e);
+         restoreInvocationContext(backup);
+      }
+   }
+
+   public void notifyNodeEvicted(final Fqn fqn, final boolean pre, InvocationContext ctx)
+   {
+      List<ListenerInvocation> listeners = listenerInvocations.get(NodeEvicted.class);
+
+      if (listeners != null && !listeners.isEmpty())
+      {
+         final boolean originLocal = ctx.isOriginLocal();
+         Transaction tx = ctx.getTransaction();
+         InvocationContext backup = resetInvocationContext(ctx);
+         EventImpl e = new EventImpl();
+         e.setCache(cache);
+         e.setOriginLocal(originLocal);
+         e.setPre(pre);
+         e.setFqn(fqn);
+         e.setTransaction(tx);
+         e.setType(NODE_EVICTED);
+         for (ListenerInvocation listener : listeners) listener.invoke(e);
+         restoreInvocationContext(backup);
+      }
+   }
+
+   public void notifyNodeLoaded(Fqn fqn, boolean pre, Map data, InvocationContext ctx)
+   {
+      List<ListenerInvocation> listeners = listenerInvocations.get(NodeLoaded.class);
+
+      if (listeners != null && !listeners.isEmpty())
+      {
+         boolean originLocal = ctx.isOriginLocal();
+         Map dataCopy = copy(data, useMarshalledValueMaps);
+         Transaction tx = ctx.getTransaction();
+         InvocationContext backup = resetInvocationContext(ctx);
+         EventImpl e = new EventImpl();
+         e.setCache(cache);
+         e.setOriginLocal(originLocal);
+         e.setPre(pre);
+         e.setFqn(fqn);
+         e.setTransaction(tx);
+         e.setData(dataCopy);
+         e.setType(NODE_LOADED);
+         for (ListenerInvocation listener : listeners) listener.invoke(e);
+         restoreInvocationContext(backup);
+      }
+   }
+
+   public void notifyNodeActivated(Fqn fqn, boolean pre, Map data, InvocationContext ctx)
+   {
+      List<ListenerInvocation> listeners = listenerInvocations.get(NodeActivated.class);
+
+      if (listeners != null && !listeners.isEmpty())
+      {
+         boolean originLocal = ctx.isOriginLocal();
+         Map dataCopy = copy(data, useMarshalledValueMaps);
+         Transaction tx = ctx.getTransaction();
+         InvocationContext backup = resetInvocationContext(ctx);
+         EventImpl e = new EventImpl();
+         e.setCache(cache);
+         e.setOriginLocal(originLocal);
+         e.setPre(pre);
+         e.setFqn(fqn);
+         e.setTransaction(tx);
+         e.setData(dataCopy);
+         e.setType(NODE_ACTIVATED);
+         for (ListenerInvocation listener : listeners) listener.invoke(e);
+         restoreInvocationContext(backup);
+      }
+   }
+
+   public void notifyNodePassivated(Fqn fqn, boolean pre, Map data, InvocationContext ctx)
+   {
+      List<ListenerInvocation> listeners = listenerInvocations.get(NodePassivated.class);
+
+      if (listeners != null && !listeners.isEmpty())
+      {
+         Map dataCopy = copy(data, useMarshalledValueMaps);
+         Transaction tx = ctx.getTransaction();
+         InvocationContext backup = resetInvocationContext(ctx);
+         EventImpl e = new EventImpl();
+         e.setCache(cache);
+         e.setPre(pre);
+         e.setFqn(fqn);
+         e.setTransaction(tx);
+         e.setData(dataCopy);
+         e.setType(NODE_PASSIVATED);
+         for (ListenerInvocation listener : listeners) listener.invoke(e);
+         restoreInvocationContext(backup);
+      }
+   }
+
+   /**
+    * Notifies all registered listeners of a cacheStarted event.
+    */
+   @Start(priority = 99)
+   public void notifyCacheStarted()
+   {
+      List<ListenerInvocation> listeners = listenerInvocations.get(CacheStarted.class);
+
+      if (listeners != null && !listeners.isEmpty())
+      {
+         EventImpl e = new EventImpl();
+         e.setCache(cache);
+         e.setType(CACHE_STARTED);
+         for (ListenerInvocation listener : listeners) listener.invoke(e);
+      }
+   }
+
+   /**
+    * Notifies all registered listeners of a cacheStopped event.
+    */
+   @Stop(priority = 98)
+   public void notifyCacheStopped()
+   {
+      List<ListenerInvocation> listeners = listenerInvocations.get(CacheStopped.class);
+
+      if (listeners != null && !listeners.isEmpty())
+      {
+         EventImpl e = new EventImpl();
+         e.setCache(cache);
+         e.setType(CACHE_STOPPED);
+         for (ListenerInvocation listener : listeners) listener.invoke(e);
+      }
+   }
+
+   public void notifyViewChange(final View new_view, InvocationContext ctx)
+   {
+      List<ListenerInvocation> listeners = listenerInvocations.get(ViewChanged.class);
+
+      if (listeners != null && !listeners.isEmpty())
+      {
+         InvocationContext backup = resetInvocationContext(ctx);
+         EventImpl e = new EventImpl();
+         e.setCache(cache);
+         e.setNewView(new_view);
+         e.setType(VIEW_CHANGED);
+         for (ListenerInvocation listener : listeners) listener.invoke(e);
+         restoreInvocationContext(backup);
+      }
+   }
+
+   public void notifyBuddyGroupChange(final BuddyGroup buddyGroup, boolean pre)
+   {
+      List<ListenerInvocation> listeners = listenerInvocations.get(BuddyGroupChanged.class);
+
+      if (listeners != null && !listeners.isEmpty())
+      {
+         EventImpl e = new EventImpl();
+         e.setCache(cache);
+         e.setBuddyGroup(buddyGroup);
+         e.setPre(pre);
+         e.setType(BUDDY_GROUP_CHANGED);
+         for (ListenerInvocation listener : listeners) listener.invoke(e);
+      }
+   }
+
+   public void notifyTransactionCompleted(Transaction transaction, boolean successful, InvocationContext ctx)
+   {
+      List<ListenerInvocation> listeners = listenerInvocations.get(TransactionCompleted.class);
+
+      if (listeners != null && !listeners.isEmpty())
+      {
+         Transaction tx = ctx.getTransaction();
+         boolean isOriginLocal = ctx.isOriginLocal();
+         InvocationContext backup = resetInvocationContext(ctx);
+         EventImpl e = new EventImpl();
+         e.setCache(cache);
+         e.setOriginLocal(isOriginLocal);
+         e.setTransaction(tx);
+         e.setSuccessful(successful);
+         e.setType(TRANSACTION_COMPLETED);
+         for (ListenerInvocation listener : listeners) listener.invoke(e);
+         restoreInvocationContext(backup);
+      }
+   }
+
+   public void notifyTransactionRegistered(Transaction transaction, InvocationContext ctx)
+   {
+      List<ListenerInvocation> listeners = listenerInvocations.get(TransactionRegistered.class);
+
+      if (listeners != null && !listeners.isEmpty())
+      {
+         Transaction tx = ctx.getTransaction();
+         boolean isOriginLocal = ctx.isOriginLocal();
+         InvocationContext backup = resetInvocationContext(ctx);
+         EventImpl e = new EventImpl();
+         e.setCache(cache);
+         e.setOriginLocal(isOriginLocal);
+         e.setTransaction(tx);
+         e.setType(TRANSACTION_REGISTERED);
+         for (ListenerInvocation listener : listeners) listener.invoke(e);
+         restoreInvocationContext(backup);
+      }
+   }
+
+   public void notifyCacheBlocked(CacheSPI cache, boolean pre)
+   {
+      List<ListenerInvocation> listeners = listenerInvocations.get(CacheBlocked.class);
+
+      if (listeners != null && !listeners.isEmpty())
+      {
+         EventImpl e = new EventImpl();
+         e.setCache(cache);
+         e.setPre(pre);
+         e.setType(CACHE_BLOCKED);
+         for (ListenerInvocation listener : listeners) listener.invoke(e);
+      }
+   }
+
+   public void notifyCacheUnblocked(CacheSPI cache, boolean pre)
+   {
+      List<ListenerInvocation> listeners = listenerInvocations.get(CacheUnblocked.class);
+
+      if (listeners != null && !listeners.isEmpty())
+      {
+         EventImpl e = new EventImpl();
+         e.setCache(cache);
+         e.setPre(pre);
+         e.setType(CACHE_UNBLOCKED);
+         for (ListenerInvocation listener : listeners) listener.invoke(e);
+      }
+   }
+
+   private static Map copy(Map data, boolean useMarshalledValueMaps)
+   {
+      if (data == null) return null;
+      if (data.isEmpty()) return Collections.emptyMap();
+      if (safe(data)) return useMarshalledValueMaps ? new MarshalledValueMap(data) : data;
+      Map defensivelyCopiedData = new MapCopy(data);
+      return useMarshalledValueMaps ? new MarshalledValueMap(defensivelyCopiedData) : defensivelyCopiedData;
+   }
+
+   private void restoreInvocationContext(InvocationContext backup)
+   {
+      cache.setInvocationContext(backup);
+   }
+
+   /**
+    * Resets the current (passed-in) invocation, and returns a temp InvocationContext containing its state so it can
+    * be restored later using {@link #restoreInvocationContext(org.jboss.cache.InvocationContext)}
+    *
+    * @param ctx the current context to be reset
+    * @return a clone of ctx, before it was reset
+    */
+   private InvocationContext resetInvocationContext(InvocationContext ctx)
+   {
+      // wipe current context.
+      cache.setInvocationContext(null);
+      return ctx;
+   }
+
+   /**
+    * A map is deemed 'safe' to be passed as-is to a listener, if either of the following are true:
+    * <ul>
+    * <li>It is null</li>
+    * <li>It is an instance of {@link org.jboss.cache.util.MapCopy}, which is immutable</li>
+    * <li>It is an instance of {@link java.util.Collections#emptyMap()}, which is also immutable</li>
+    * <li>It is an instance of {@link java.util.Collections#singletonMap(Object,Object)}, which is also immutable</li>
+    * </ul>
+    *
+    * @param map
+    * @return
+    */
+   private static boolean safe(Map map)
+   {
+      return map == null || map instanceof MapCopy || map.getClass().equals(emptyMap) || map.getClass().equals(singletonMap);
+   }
+
+   /**
+    * Class that encapsulates a valid invocation for a given registered listener - containing a reference to the
+    * method to be invoked as well as the target object.
+    */
+   class ListenerInvocation
+   {
+      private final Object target;
+      private final Method method;
+
+      public ListenerInvocation(Object target, Method method)
+      {
+         this.target = target;
+         this.method = method;
+      }
+
+      public void invoke(Event e)
+      {
+         try
+         {
+            method.invoke(target, e);
+         }
+         catch (InvocationTargetException e1)
+         {
+            Throwable cause = e1.getCause();
+            if (cause != null)
+               throw new CacheException("Caught exception invoking method " + method + " on listener instance " + target, cause);
+            else
+               throw new CacheException("Caught exception invoking method " + method + " on listener instance " + target, e1);
+         }
+         catch (IllegalAccessException e1)
+         {
+            log.warn("Unable to invoke method " + method + " on Object instance " + target + " - removing this target object from list of listeners!", e1);
+            removeCacheListener(this.target);
+         }
+      }
+   }
+
+}


Property changes on: core/trunk/src/main/java/org/jboss/cache/notifications/NotifierImpl.java
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision
Name: svn:eol-style
   + native

Modified: core/trunk/src/main/java/org/jboss/cache/util/CachePrinter.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/util/CachePrinter.java	2008-05-14 17:05:33 UTC (rev 5849)
+++ core/trunk/src/main/java/org/jboss/cache/util/CachePrinter.java	2008-05-15 12:44:49 UTC (rev 5850)
@@ -2,7 +2,7 @@
 
 import org.jboss.cache.Cache;
 import org.jboss.cache.CacheSPI;
-import org.jboss.cache.DataContainer;
+import org.jboss.cache.DataContainerImpl;
 import org.jboss.cache.interceptors.base.CommandInterceptor;
 import org.jboss.cache.invocation.CacheInvocationDelegate;
 
@@ -23,7 +23,7 @@
    public static String printCacheDetails(Cache c)
    {
       // internal cast
-      DataContainer ci = ((CacheInvocationDelegate) c).getDataContainer();
+      DataContainerImpl ci = ((CacheInvocationDelegate) c).getDataContainer();
       return ci.printDetails();
    }
 
@@ -36,7 +36,7 @@
    public static String printCacheLockingInfo(Cache c)
    {
       // internal cast
-      DataContainer cd = ((CacheInvocationDelegate) c).getDataContainer();
+      DataContainerImpl cd = ((CacheInvocationDelegate) c).getDataContainer();
       return cd.printLockInfo();
    }
 

Modified: core/trunk/src/test/java/org/jboss/cache/DataContainerTest.java
===================================================================
--- core/trunk/src/test/java/org/jboss/cache/DataContainerTest.java	2008-05-14 17:05:33 UTC (rev 5849)
+++ core/trunk/src/test/java/org/jboss/cache/DataContainerTest.java	2008-05-15 12:44:49 UTC (rev 5850)
@@ -2,7 +2,7 @@
 
 import org.jboss.cache.config.Configuration;
 import org.jboss.cache.marshall.NodeData;
-import org.jboss.cache.mock.NodeSpiMock;
+import org.jboss.cache.mock.MockNodesFixture;
 import org.jboss.cache.optimistic.DataVersion;
 import org.jboss.cache.optimistic.DefaultDataVersion;
 import org.testng.annotations.BeforeMethod;
@@ -20,100 +20,74 @@
 @Test(groups = "unit")
 public class DataContainerTest
 {
-   private DataContainer container;
+   private DataContainerImpl container;
+   private MockNodesFixture nodes;
 
-   //node structure on which all tests are being run.
-   private NodeSpiMock root;
-   private Fqn a = Fqn.fromString("/a");
-   private NodeSpiMock aNode;
-   private Fqn ab = Fqn.fromString("/a/b");
-   private NodeSpiMock abNode;
-   private Fqn abc = Fqn.fromString("/a/b/c");
-   private NodeSpiMock abcNode;
-   private Fqn ad = Fqn.fromString("/a/d");
-   private NodeSpiMock adNode;
-   private Fqn ade = Fqn.fromString("/a/d/e");
-   private NodeSpiMock adeNode;
-   private Fqn adf = Fqn.fromString("/a/d/f");
-   private NodeSpiMock adfNode;
-   private Fqn adfh = Fqn.fromString("/a/d/f/h");
-   private NodeSpiMock adfhNode;
-   private Fqn adfg = Fqn.fromString("/a/d/f/g");
-   private NodeSpiMock adfgNode;
-   private Fqn notExistent = Fqn.fromString("aaa" + System.currentTimeMillis());
    //end of node structure.
 
    @BeforeMethod
    public void setUp()
    {
-      root = new NodeSpiMock(Fqn.ROOT);
-      container = new DataContainer();
-      container.setRoot(root);
-      aNode = (NodeSpiMock) root.addChild(a);
-      abNode = (NodeSpiMock) root.addChild(ab);
-      abcNode = (NodeSpiMock) root.addChild(abc);
-      adNode = (NodeSpiMock) root.addChild(ad);
-      adeNode = (NodeSpiMock) root.addChild(ade);
-      adfNode = (NodeSpiMock) root.addChild(adf);
-      adfhNode = (NodeSpiMock) root.addChild(adfh);
-      adfgNode = (NodeSpiMock) root.addChild(adfg);
+      nodes = new MockNodesFixture();
+      container = new DataContainerImpl();
+      container.setRoot(nodes.root);
    }
 
    /**
-    * tests {@link org.jboss.cache.DataContainer#peek(Fqn, boolean, boolean)} method
+    * tests {@link DataContainerImpl#peek(Fqn, boolean, boolean)} method
     */
    public void testPeekNodesSimple()
    {
-      assert root == container.peek(Fqn.ROOT, true, true);
-      assert adfgNode == container.peek(adfg, false, false);
-      assert adfgNode == container.peek(adfg, false, true);
-      assert adfgNode == container.peek(adfg, true, true);
+      assert nodes.root == container.peek(Fqn.ROOT, true, true);
+      assert nodes.adfgNode == container.peek(nodes.adfg, false, false);
+      assert nodes.adfgNode == container.peek(nodes.adfg, false, true);
+      assert nodes.adfgNode == container.peek(nodes.adfg, true, true);
    }
 
    /**
-    * tests {@link org.jboss.cache.DataContainer#peek(Fqn, boolean, boolean)} for invalid nodes.
+    * tests {@link DataContainerImpl#peek(Fqn, boolean, boolean)} for invalid nodes.
     */
    public void testPeekInvalidNodes()
    {
-      adfgNode.setValid(false, false);
-      assert null == container.peek(adfg, true, false);
-      assert adfgNode == container.peek(adfg, true, true);
+      nodes.adfgNode.setValid(false, false);
+      assert null == container.peek(nodes.adfg, true, false);
+      assert nodes.adfgNode == container.peek(nodes.adfg, true, true);
    }
 
    /**
-    * tests {@link org.jboss.cache.DataContainer#peek(Fqn, boolean, boolean)} method for deleted nodes.
+    * tests {@link DataContainerImpl#peek(Fqn, boolean, boolean)} method for deleted nodes.
     */
    public void testPeekDeletedNodes()
    {
-      adfgNode.markAsDeleted(true);
-      assert null == container.peek(adfg, false, false);
-      assert adfgNode == container.peek(adfg, true, false);
+      nodes.adfgNode.markAsDeleted(true);
+      assert null == container.peek(nodes.adfg, false, false);
+      assert nodes.adfgNode == container.peek(nodes.adfg, true, false);
    }
 
    /**
-    * tests {@link org.jboss.cache.DataContainer#peekVersioned(Fqn, org.jboss.cache.optimistic.DataVersion, boolean)} method.
+    * tests {@link DataContainerImpl#peekVersioned(Fqn, org.jboss.cache.optimistic.DataVersion, boolean)} method.
     */
    public void testPeekVersioned()
    {
-      assert adfgNode == container.peekVersioned(adfg, null, true) : "if data version is null this returns same value as peek(boolean, boolean)";
+      assert nodes.adfgNode == container.peekVersioned(nodes.adfg, null, true) : "if data version is null this returns same value as peek(boolean, boolean)";
 
       //test pessimistic loking
       Configuration config = new Configuration();
       config.setNodeLockingOptimistic(false);
       DataVersion dataVersion = new DefaultDataVersion(2);
       container.setDependencies(config, null);
-      assert adfgNode == container.peekVersioned(adfg, dataVersion, true) : "if NOT opt locking same value as peek(boolean, boolean) expected";
+      assert nodes.adfgNode == container.peekVersioned(nodes.adfg, dataVersion, true) : "if NOT opt locking same value as peek(boolean, boolean) expected";
 
       //test optimistic locking with same version
       config.setNodeLockingOptimistic(true);
       DataVersion adfgDataVersion = new DefaultDataVersion(2);
-      adfgNode.setVersion(adfgDataVersion);
-      assert adfgNode == container.peekVersioned(adfg, adfgDataVersion, true) : "same version, expcting node to be returned";
+      nodes.adfgNode.setVersion(adfgDataVersion);
+      assert nodes.adfgNode == container.peekVersioned(nodes.adfg, adfgDataVersion, true) : "same version, expcting node to be returned";
 
       //test optimistic locking with a an older
       try
       {
-         container.peekVersioned(adfg, new DefaultDataVersion(1), true);
+         container.peekVersioned(nodes.adfg, new DefaultDataVersion(1), true);
          assert false : "exception expected as version changed.";
       } catch (CacheException e)
       {
@@ -122,15 +96,15 @@
    }
 
    /**
-    * tests {@link DataContainer#peekStrict(org.jboss.cache.transaction.GlobalTransaction, Fqn, boolean)}.
+    * tests {@link DataContainerImpl#peekStrict(org.jboss.cache.transaction.GlobalTransaction, Fqn, boolean)}.
     */
    public void testPeekStrict()
    {
-      assert adfgNode == container.peekStrict(null, adfg, true) : "if data version is null this returns same value as peek(boolean, boolean)";
+      assert nodes.adfgNode == container.peekStrict(null, nodes.adfg, true) : "if data version is null this returns same value as peek(boolean, boolean)";
 
       try
       {
-         container.peekStrict(null, notExistent, true);
+         container.peekStrict(null, nodes.notExistent, true);
          assert false : "excpetion expected as node does not exist";
       } catch (Exception e)
       {
@@ -139,67 +113,67 @@
    }
 
    /**
-    * tests {@link org.jboss.cache.DataContainer#exists(Fqn)}
+    * tests {@link DataContainerImpl#exists(Fqn)}
     */
    public void testsExists()
    {
-      assert container.exists(ab) : "ab exists";
-      abNode.markAsDeleted(true);
-      assert !container.exists(ab) : "ab marked as deleted";
-      assert container.exists(ad);
-      adNode.setValid(false, false);
-      assert !container.exists(ade) : "its parent was marked as invalid";
+      assert container.exists(nodes.ab) : "ab exists";
+      nodes.abNode.markAsDeleted(true);
+      assert !container.exists(nodes.ab) : "ab marked as deleted";
+      assert container.exists(nodes.ad);
+      nodes.adNode.setValid(false, false);
+      assert !container.exists(nodes.ade) : "its parent was marked as invalid";
    }
 
    /**
-    * tests {@link org.jboss.cache.DataContainer#hasChildren(Fqn)}
+    * tests {@link DataContainerImpl#hasChildren(Fqn)}
     */
    public void testHasChildren()
    {
-      assert container.hasChildren(ad) : " ade is a child of ad";
-      assert !container.hasChildren(notExistent) : " this one does not exist";
-      assert !container.hasChildren(adfg) : "this one exists but does not have children";
-      adNode.setValid(false, false);
-      assert !container.hasChildren(ad) : "ad exists and has children but is invalid";
+      assert container.hasChildren(nodes.ad) : " ade is a child of ad";
+      assert !container.hasChildren(nodes.notExistent) : " this one does not exist";
+      assert !container.hasChildren(nodes.adfg) : "this one exists but does not have children";
+      nodes.adNode.setValid(false, false);
+      assert !container.hasChildren(nodes.ad) : "ad exists and has children but is invalid";
    }
 
    /**
-    * test {@link DataContainer#buildNodeData(java.util.List, NodeSPI)}
+    * test {@link DataContainerImpl#buildNodeData(java.util.List, NodeSPI)}
     */
    public void testBuildNodeData()
    {
-      abNode.put("ab", "ab");
-      abcNode.put("abc", "abc");
+      nodes.abNode.put("ab", "ab");
+      nodes.abcNode.put("abc", "abc");
       List<NodeData> result = new ArrayList<NodeData>();
-      container.buildNodeData(result, abNode);
+      container.buildNodeData(result, nodes.abNode);
       assert result.size() == 2;
-      assert result.contains(new NodeData(ab, abNode.getData()));
-      assert result.contains(new NodeData(abc, abcNode.getData()));
+      assert result.contains(new NodeData(nodes.ab, nodes.abNode.getData()));
+      assert result.contains(new NodeData(nodes.abc, nodes.abcNode.getData()));
    }
 
    /**
-    * tests {@link org.jboss.cache.DataContainer#getNodesForEviction(Fqn, boolean)} in a nonrecursive scenario.
+    * tests {@link DataContainerImpl#getNodesForEviction(Fqn, boolean)} in a nonrecursive scenario.
     */
    public void testGetNodesForEvictionNonrecursive()
    {
       //check for root first
       List<Fqn> result = container.getNodesForEviction(Fqn.ROOT, false);
       assert result.size() == 1 : "for root the direct children are considered for eviction";
-      assert result.contains(a);
+      assert result.contains(nodes.a);
 
       //check normal
-      result = container.getNodesForEviction(ad, false);
+      result = container.getNodesForEviction(nodes.ad, false);
       assert result.size() == 1 : "one child expected";
-      assert result.contains(ad);
+      assert result.contains(nodes.ad);
 
       //check resident scenario
-      adNode.setResident(true);
-      result = container.getNodesForEviction(ad, false);
+      nodes.adNode.setResident(true);
+      result = container.getNodesForEviction(nodes.ad, false);
       assert result.size() == 0 : "no children expected";
    }
 
    /**
-    * tests {@link org.jboss.cache.DataContainer#getNodesForEviction(Fqn, boolean)} in a recursive scenario.
+    * tests {@link DataContainerImpl#getNodesForEviction(Fqn, boolean)} in a recursive scenario.
     */
    public void testGetNodesForEvictionRecursive()
    {
@@ -208,26 +182,26 @@
       assert result.size() == 8 : "all children are considered for eviction";
 
       //check normal
-      result = container.getNodesForEviction(ad, true);
+      result = container.getNodesForEviction(nodes.ad, true);
       assert result.size() == 5 : "five childrens expected";
-      assert result.contains(ad);
-      assert result.contains(ade);
-      assert result.contains(adf);
-      assert result.contains(adfh);
-      assert result.contains(adfg);
+      assert result.contains(nodes.ad);
+      assert result.contains(nodes.ade);
+      assert result.contains(nodes.adf);
+      assert result.contains(nodes.adfh);
+      assert result.contains(nodes.adfg);
 
       //check resident scenario
-      adNode.setResident(true);
-      result = container.getNodesForEviction(ad, true);
+      nodes.adNode.setResident(true);
+      result = container.getNodesForEviction(nodes.ad, true);
       assert result.size() == 4 : "only children expected";
-      assert result.contains(ade);
-      assert result.contains(adf);
-      assert result.contains(adfh);
-      assert result.contains(adfg);
+      assert result.contains(nodes.ade);
+      assert result.contains(nodes.adf);
+      assert result.contains(nodes.adfh);
+      assert result.contains(nodes.adfg);
    }
 
    /**
-    * tests {@link DataContainer#getNumberOfNodes()}
+    * tests {@link DataContainerImpl#getNumberOfNodes()}
     */
    public void testGetNumberOfNodes()
    {
@@ -235,87 +209,87 @@
    }
 
    /**
-    * tests {@link DataContainer#removeFromDataStructure(Fqn, boolean)} having skipMarkerCheck set to false.
+    * tests {@link DataContainerImpl#removeFromDataStructure(Fqn, boolean)} having skipMarkerCheck set to false.
     */
    public void removeFromDataStructureNoSkip1()
    {
       //check inexisten node
-      assert !container.removeFromDataStructure(notExistent, false);
+      assert !container.removeFromDataStructure(nodes.notExistent, false);
 
       //check root - all the subnodes should be deleted and marked as invalid, but the root itself
-      root.markAsDeleted(true);
+      nodes.root.markAsDeleted(true);
       assert container.removeFromDataStructure(Fqn.ROOT, false);
-      assert !aNode.isValid();
-      assert !abNode.isValid();
-      assert !abcNode.isValid();
-      assert !adNode.isValid();
-      assert !adeNode.isValid();
-      assert !adfNode.isValid();
-      assert !adfgNode.isValid();
-      assert !adfhNode.isValid();
-      assert root.isValid();
+      assert !nodes.aNode.isValid();
+      assert !nodes.abNode.isValid();
+      assert !nodes.abcNode.isValid();
+      assert !nodes.adNode.isValid();
+      assert !nodes.adeNode.isValid();
+      assert !nodes.adfNode.isValid();
+      assert !nodes.adfgNode.isValid();
+      assert !nodes.adfhNode.isValid();
+      assert nodes.root.isValid();
    }
 
    /**
-    * tests {@link DataContainer#removeFromDataStructure(Fqn, boolean)} having skipMarkerCheck set to false.
+    * tests {@link DataContainerImpl#removeFromDataStructure(Fqn, boolean)} having skipMarkerCheck set to false.
     */
    public void removeFromDataStructureNoSkip2()
    {
       //check root - all the subnodes should be deleted and marked as invalid, but the root itself
-      root.markAsDeleted(false);
+      nodes.root.markAsDeleted(false);
       assert !container.removeFromDataStructure(Fqn.ROOT, false);
 
       //check a normal node
-      adNode.markAsDeleted(true);
-      assert container.removeFromDataStructure(ad, false);
-      assert !adeNode.isValid();
-      assert !adfNode.isValid();
-      assert !adfhNode.isValid();
-      assert !adfhNode.isValid();
+      nodes.adNode.markAsDeleted(true);
+      assert container.removeFromDataStructure(nodes.ad, false);
+      assert !nodes.adeNode.isValid();
+      assert !nodes.adfNode.isValid();
+      assert !nodes.adfhNode.isValid();
+      assert !nodes.adfhNode.isValid();
    }
 
    /**
-    * tests {@link DataContainer#removeFromDataStructure(Fqn, boolean)} having skipMarkerCheck set to true.
+    * tests {@link DataContainerImpl#removeFromDataStructure(Fqn, boolean)} having skipMarkerCheck set to true.
     */
    public void removeFromDataStructureWithSkip()
    {
       //check inexisten node
-      assert !container.removeFromDataStructure(notExistent, false);
+      assert !container.removeFromDataStructure(nodes.notExistent, false);
 
       //check root - all the subnodes should be deleted and marked as invalid, but the root itself
       assert container.removeFromDataStructure(Fqn.ROOT, true);
-      assert !aNode.isValid();
-      assert !abNode.isValid();
-      assert !abcNode.isValid();
-      assert !adNode.isValid();
-      assert !adeNode.isValid();
-      assert !adfNode.isValid();
-      assert !adfgNode.isValid();
-      assert !adfhNode.isValid();
-      assert root.isValid();
+      assert !nodes.aNode.isValid();
+      assert !nodes.abNode.isValid();
+      assert !nodes.abcNode.isValid();
+      assert !nodes.adNode.isValid();
+      assert !nodes.adeNode.isValid();
+      assert !nodes.adfNode.isValid();
+      assert !nodes.adfgNode.isValid();
+      assert !nodes.adfhNode.isValid();
+      assert nodes.root.isValid();
    }
 
    /**
-    * tests {@link org.jboss.cache.DataContainer#evict(Fqn)}
+    * tests {@link DataContainerImpl#evict(Fqn)}
     */
    public void testEvict()
    {
       //tests eviction of leaf nodes
-      assert container.evict(abc);
-      assert !abcNode.isValid();
-      assert !abNode.hasChild("c");
+      assert container.evict(nodes.abc);
+      assert !nodes.abcNode.isValid();
+      assert !nodes.abNode.hasChild("c");
 
       //test eviction of intermediate nodes
-      adNode.put("key", "value");
-      assert !container.evict(ad);
-      assert adNode.isValid();
-      assert adNode.getData().isEmpty();
-      assert aNode.hasChild("d");
-      assert adNode.hasChild("e");
+      nodes.adNode.put("key", "value");
+      assert !container.evict(nodes.ad);
+      assert nodes.adNode.isValid();
+      assert nodes.adNode.getData().isEmpty();
+      assert nodes.aNode.hasChild("d");
+      assert nodes.adNode.hasChild("e");
    }
 
    /**
-    *  test {@link org.jboss.cache.DataContainer#createNodes(Fqn)}
+    *  test {@link DataContainerImpl#createNodes(Fqn)}
     */
    public void testCreateNodes()
    {

Added: core/trunk/src/test/java/org/jboss/cache/commands/read/AbstractDataCommandTest.java
===================================================================
--- core/trunk/src/test/java/org/jboss/cache/commands/read/AbstractDataCommandTest.java	                        (rev 0)
+++ core/trunk/src/test/java/org/jboss/cache/commands/read/AbstractDataCommandTest.java	2008-05-15 12:44:49 UTC (rev 5850)
@@ -0,0 +1,32 @@
+package org.jboss.cache.commands.read;
+
+import org.jboss.cache.Fqn;
+import org.jboss.cache.DataContainer;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+import static org.easymock.EasyMock.createMock;
+
+/**
+ * Class that has convinience fixture for all tests that operated on {@link AbstractDataCommand}
+ *
+ * @author Mircea.Markus at jboss.com
+ * @since 2.2
+ */
+public abstract class AbstractDataCommandTest
+{
+   protected Fqn testFqn = Fqn.fromString("/testfqn");
+   protected DataContainer containerMock;
+
+   @BeforeMethod
+   final public void setUp()
+   {
+      containerMock = createMock(DataContainer.class);
+      moreSetup();
+   }
+
+   /**
+    * called by setUp after initializing the testFqn and containeMock.
+    */
+   protected abstract void moreSetup();
+
+}

Added: core/trunk/src/test/java/org/jboss/cache/commands/read/ExistsCommandTest.java
===================================================================
--- core/trunk/src/test/java/org/jboss/cache/commands/read/ExistsCommandTest.java	                        (rev 0)
+++ core/trunk/src/test/java/org/jboss/cache/commands/read/ExistsCommandTest.java	2008-05-15 12:44:49 UTC (rev 5850)
@@ -0,0 +1,33 @@
+package org.jboss.cache.commands.read;
+
+import static org.easymock.EasyMock.*;
+import org.testng.annotations.Test;
+
+/**
+ * Tester class for {@link org.jboss.cache.commands.read.ExistsCommand}
+ * @author Mircea.Markus at jboss.com
+ * @since 2.2
+ */
+ at Test(groups="unit")
+public class ExistsCommandTest extends AbstractDataCommandTest
+{
+   private ExistsCommand command;
+
+   protected void moreSetup()
+   {
+      command = new ExistsCommand(testFqn);
+      command.initialize(containerMock);
+   }
+
+   public void testPerform()
+   {
+      expect(containerMock.exists(testFqn)).andReturn(Boolean.FALSE);
+      replay(containerMock);
+      assert Boolean.FALSE == command.perform(null);
+      reset(containerMock);
+      
+      expect(containerMock.exists(testFqn)).andReturn(Boolean.TRUE);
+      replay(containerMock);
+      assert Boolean.TRUE == command.perform(null);
+   }
+}

Added: core/trunk/src/test/java/org/jboss/cache/commands/read/GetChildrenNamesCommandTest.java
===================================================================
--- core/trunk/src/test/java/org/jboss/cache/commands/read/GetChildrenNamesCommandTest.java	                        (rev 0)
+++ core/trunk/src/test/java/org/jboss/cache/commands/read/GetChildrenNamesCommandTest.java	2008-05-15 12:44:49 UTC (rev 5850)
@@ -0,0 +1,66 @@
+package org.jboss.cache.commands.read;
+
+import static org.easymock.EasyMock.*;
+
+import org.testng.annotations.Test;
+import org.jboss.cache.mock.NodeSpiMock;
+import org.jboss.cache.mock.MockNodesFixture;
+
+import java.util.Set;
+
+/**
+ * Tester class for {@link  org.jboss.cache.commands.read.GetChildrenNamesCommand}.
+ *
+ * @author Mircea.Markus at jboss.com
+ * @since 2.2
+ */
+ at Test (groups="unit")
+public class GetChildrenNamesCommandTest extends AbstractDataCommandTest
+{
+   private GetChildrenNamesCommand command;
+   private MockNodesFixture nodes;
+
+   protected void moreSetup()
+   {
+      nodes = new MockNodesFixture();
+      command = new GetChildrenNamesCommand(testFqn);
+      command.initialize(containerMock);
+   }
+
+   public void testPerformNoChildren()
+   {
+      NodeSpiMock node = new NodeSpiMock(testFqn);
+      expect(containerMock.peek(testFqn)).andReturn(node);
+      replay(containerMock);
+      Set result = (Set) command.perform(null);
+      assert result.isEmpty() : "empty result expected";
+   }
+   
+   public void testPerformInexistingNode()
+   {
+      expect(containerMock.peek(testFqn)).andReturn(null);
+      replay(containerMock);
+      Set result = (Set) command.perform(null);
+      assert result == null : "empty result expected";
+   }
+
+   public void testNodeWithChildren()
+   {
+      expect(containerMock.peek(testFqn)).andReturn(nodes.adfNode);
+      replay(containerMock);
+      Set result = (Set) command.perform(null);
+      assert result.size() == 2;
+      assert result.contains("h");
+      assert result.contains("g");
+   }
+
+   public void testNodeInvalidChildren()
+   {
+      nodes.adfgNode.markAsDeleted(true);
+      expect(containerMock.peek(testFqn)).andReturn(nodes.adfNode);
+      replay(containerMock);
+      Set result = (Set) command.perform(null);
+      assert result.size() == 1;
+      assert result.contains("h");
+   }
+}

Added: core/trunk/src/test/java/org/jboss/cache/commands/read/GetDataMapCommandTest.java
===================================================================
--- core/trunk/src/test/java/org/jboss/cache/commands/read/GetDataMapCommandTest.java	                        (rev 0)
+++ core/trunk/src/test/java/org/jboss/cache/commands/read/GetDataMapCommandTest.java	2008-05-15 12:44:49 UTC (rev 5850)
@@ -0,0 +1,54 @@
+package org.jboss.cache.commands.read;
+
+import org.testng.annotations.Test;
+import static org.easymock.EasyMock.*;
+import org.jboss.cache.mock.NodeSpiMock;
+
+import java.util.Map;
+
+/**
+ * Tester class for {@link GetDataMapCommand}.
+ *
+ * @author Mircea.Markus at jboss.com
+ * @since 2.2
+ */
+ at Test(groups = "unit")
+public class GetDataMapCommandTest extends AbstractDataCommandTest
+{
+   GetDataMapCommand command;
+
+   protected void moreSetup()
+   {
+      command = new GetDataMapCommand(testFqn);
+      command.initialize(containerMock);
+   }
+
+   public void testForNonexistentNode()
+   {
+      expect(containerMock.peek(testFqn)).andReturn(null);
+      replay(containerMock);
+      assert null == command.perform(null);
+   }
+
+   public void testForExistingNode()
+   {
+      NodeSpiMock node = new NodeSpiMock(testFqn);
+      node.putDirect("k1","v1");
+      node.putDirect("k2","v2");
+      expect(containerMock.peek(testFqn)).andReturn(node);
+      replay(containerMock);
+      Map result = (Map) command.perform(null);
+      assert 2 == result.entrySet().size();
+      assert result.get("k1").equals("v1");
+      assert result.get("k2").equals("v2");
+
+      try
+      {
+         result.put("k3", "v3");
+         assert false : "map should be immutable";
+      } catch (RuntimeException ex)
+      {
+         //expected
+      }
+   }
+}

Added: core/trunk/src/test/java/org/jboss/cache/commands/read/GetKeyValueCommandTest.java
===================================================================
--- core/trunk/src/test/java/org/jboss/cache/commands/read/GetKeyValueCommandTest.java	                        (rev 0)
+++ core/trunk/src/test/java/org/jboss/cache/commands/read/GetKeyValueCommandTest.java	2008-05-15 12:44:49 UTC (rev 5850)
@@ -0,0 +1,82 @@
+package org.jboss.cache.commands.read;
+
+import org.testng.annotations.Test;
+import org.testng.annotations.BeforeMethod;
+import static org.easymock.EasyMock.*;
+import org.easymock.*;
+import org.jboss.cache.notifications.Notifier;
+import org.jboss.cache.DataContainer;
+import org.jboss.cache.Fqn;
+import org.jboss.cache.mock.NodeSpiMock;
+
+/**
+ * Tester class for {@link GetKeyValueCommand}.
+ *
+ * @author Mircea.Markus at jboss.com
+ * @since 2.2
+ */
+ at Test(groups = "unit")
+public class GetKeyValueCommandTest
+{
+   private IMocksControl control;
+   Notifier notifierMock;
+   DataContainer containerMock;
+   GetKeyValueCommand command;
+   Fqn fqn = Fqn.fromString("/dummy");
+   String key = "key";
+
+   @BeforeMethod
+   protected void setUup()
+   {
+      control = createStrictControl();
+      containerMock = control.createMock(DataContainer.class);
+      notifierMock = control.createMock(Notifier.class);
+      command = new GetKeyValueCommand(fqn, key, false);
+      command.initialize(containerMock, notifierMock);
+   }
+
+   public void testNonexistentNodeNoNotifications()
+   {
+      expect(containerMock.peek(fqn)).andReturn(null);
+      control.replay();
+      assert null == command.perform(null);
+   }
+
+   public void testExistentNodeNoNotifications()
+   {
+      NodeSpiMock node = new NodeSpiMock(fqn);
+      String value = "vvv";
+      node.put(key, value);
+      expect(containerMock.peek(fqn)).andReturn(node);
+      control.replay();
+      assert value.equals(command.perform(null));
+   }
+
+   /**
+    * Notification should only be triggered if the node exists.
+    */
+   public void testNonexistentNodeWithNotifications()
+   {
+      command.sendNodeEvent = true;
+      expect(containerMock.peek(fqn)).andReturn(null);
+      control.replay();
+      assert null == command.perform(null);
+   }
+
+   public void testExistentNodeWithNotifications()
+   {
+      command.sendNodeEvent = true;
+      NodeSpiMock node = new NodeSpiMock(fqn);
+      String value = "vvv";
+      node.put(key, value);
+      //not ordred because the peek hapens before notification - that is to make sure that no notification
+      // is sent for an nonexistent node.
+      control.checkOrder(false);
+      notifierMock.notifyNodeVisited(fqn, true, null);
+      expect(containerMock.peek(fqn)).andReturn(node);
+      notifierMock.notifyNodeVisited(fqn, false, null);
+      control.replay();
+      assert value.equals(command.perform(null));
+      control.verify();
+   }
+}

Added: core/trunk/src/test/java/org/jboss/cache/commands/read/GetKeysCommandTest.java
===================================================================
--- core/trunk/src/test/java/org/jboss/cache/commands/read/GetKeysCommandTest.java	                        (rev 0)
+++ core/trunk/src/test/java/org/jboss/cache/commands/read/GetKeysCommandTest.java	2008-05-15 12:44:49 UTC (rev 5850)
@@ -0,0 +1,48 @@
+package org.jboss.cache.commands.read;
+
+import org.testng.annotations.Test;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import org.jboss.cache.mock.NodeSpiMock;
+
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Tester class for {@link GetKeysCommand}.
+ *
+ * @author Mircea.Markus at jboss.com
+ * @since 2.2
+ */
+ at Test(groups = "unit")
+public class GetKeysCommandTest extends AbstractDataCommandTest
+{
+
+   GetKeysCommand command;
+
+   protected void moreSetup()
+   {
+      command = new GetKeysCommand(testFqn);
+      command.initialize(containerMock);
+   }
+
+   public void testForNonexistentNode()
+   {
+      expect(containerMock.peek(testFqn)).andReturn(null);
+      replay(containerMock);
+      assert null == command.perform(null);
+   }
+
+   public void testForExistingNode()
+   {
+      NodeSpiMock node = new NodeSpiMock(testFqn);
+      node.putDirect("k1", "v1");
+      node.putDirect("k2", "v2");
+      expect(containerMock.peek(testFqn)).andReturn(node);
+      replay(containerMock);
+      Set result = (Set) command.perform(null);
+      assert 2 == result.size();
+      assert result.contains("k1");
+      assert result.contains("k2");
+   }
+}

Added: core/trunk/src/test/java/org/jboss/cache/commands/read/GravitateDataCommandTest.java
===================================================================
--- core/trunk/src/test/java/org/jboss/cache/commands/read/GravitateDataCommandTest.java	                        (rev 0)
+++ core/trunk/src/test/java/org/jboss/cache/commands/read/GravitateDataCommandTest.java	2008-05-15 12:44:49 UTC (rev 5850)
@@ -0,0 +1,141 @@
+package org.jboss.cache.commands.read;
+
+import static org.easymock.EasyMock.*;
+import org.easymock.IMocksControl;
+import org.jboss.cache.*;
+import org.jboss.cache.buddyreplication.BuddyManager;
+import org.jboss.cache.buddyreplication.GravitateResult;
+import org.jboss.cache.buddyreplication.BuddyFqnTransformer;
+import org.jboss.cache.mock.MockNodesFixture;
+import org.jboss.cache.mock.NodeSpiMock;
+import org.jgroups.stack.IpAddress;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import java.util.ArrayList;
+import java.util.Collections;
+
+/**
+ * Tester class for {@link org.jboss.cache.commands.read.GravitateDataCommand}
+ *
+ * @author Mircea.Markus at jboss.com
+ * @since 2.2
+ */
+ at Test(groups="unit")
+public class GravitateDataCommandTest
+{
+   GravitateDataCommand command;
+   DataContainer containerMock;
+   CacheSPI spiMock;
+   IMocksControl control;
+   Fqn fqn = Fqn.fromString("/dummy");
+   InvocationContext ctx;
+
+   @BeforeMethod
+   public void setUp()
+   {
+      control = createStrictControl();
+      containerMock = control.createMock(DataContainer.class);
+      spiMock = control.createMock(CacheSPI.class);
+      command = new GravitateDataCommand(fqn, true, new IpAddress());
+      command.initialize(containerMock, spiMock);
+      ctx = new InvocationContext();
+   }
+
+   public void testNonexistentNode()
+   {
+      command.setSearchSubtrees(false);
+      expect(spiMock.getNode(fqn)).andReturn(null);
+      control.replay();
+      assert GravitateResult.noDataFound().equals(command.perform(ctx));
+   }
+
+   public void testExistentNodeInTheCache()
+   {
+      MockNodesFixture nodes = new MockNodesFixture();
+      command.setSearchSubtrees(false);
+
+      expect(spiMock.getNode(fqn)).andReturn(nodes.adfNode);
+      ArrayList arrayList = new ArrayList();
+      expect(containerMock.buildNodeData(Collections.EMPTY_LIST, nodes.adfNode)).andReturn(arrayList);
+      control.replay();
+      GravitateResult result = (GravitateResult) command.perform(ctx);
+      control.verify();
+
+      assert result != null;
+      assert result.getNodeData() == arrayList;
+   }
+
+   public void testNodeDoesExistsInBackupAndNoDead()
+   {
+      MockNodesFixture nodes = new MockNodesFixture();
+      expect(spiMock.getNode(fqn)).andReturn(null);
+      expect(containerMock.peek(BuddyManager.BUDDY_BACKUP_SUBTREE_FQN)).andReturn(nodes.abNode);
+
+      Fqn firstSearch = Fqn.fromString(BuddyManager.BUDDY_BACKUP_SUBTREE_FQN + "/c/dummy");
+      expect(spiMock.getNode(firstSearch)).andReturn(nodes.abcNode);
+
+      ArrayList listReference = new ArrayList();
+      expect(containerMock.buildNodeData(Collections.EMPTY_LIST, nodes.abcNode)).andReturn(listReference);
+
+      control.replay();
+      GravitateResult result = (GravitateResult) command.perform(ctx);
+      assert  result.getNodeData()== listReference;
+      control.verify();
+   }
+
+   public void testNodeDoesNotExistsInBackupAndNoDead()
+   {
+      MockNodesFixture nodes = new MockNodesFixture();
+      expect(spiMock.getNode(fqn)).andReturn(null);
+      expect(containerMock.peek(BuddyManager.BUDDY_BACKUP_SUBTREE_FQN)).andReturn(nodes.adfNode);
+
+      control.checkOrder(false);
+      Fqn firstSearch = Fqn.fromString(BuddyManager.BUDDY_BACKUP_SUBTREE_FQN + "/g/dummy");
+      expect(spiMock.getNode(firstSearch)).andReturn(null);
+      Fqn secondSearch = Fqn.fromString(BuddyManager.BUDDY_BACKUP_SUBTREE_FQN + "/h/dummy");
+      expect(spiMock.getNode(secondSearch)).andReturn(null);
+      control.checkOrder(true);
+
+      control.replay();
+      assert GravitateResult.noDataFound().equals(command.perform(ctx));
+      control.verify();
+   }
+
+   public void testDeadBeackup() throws Exception
+   {
+      NodeSpiMock root = new NodeSpiMock(Fqn.ROOT);
+
+      //add first dead child
+      IpAddress firstAddress = new IpAddress("127.0.0.1", 1234);
+      NodeSpiMock firstDeadNode = (NodeSpiMock) root.addChildDirect(BuddyFqnTransformer.getDeadBackupRoot(firstAddress));
+      firstDeadNode.addChildDirect(Fqn.fromElements(0));
+      firstDeadNode.addChildDirect(Fqn.fromElements(1));
+      firstDeadNode.addChildDirect(Fqn.fromElements(2));
+
+      //add second dead child
+      IpAddress secondAddress = new IpAddress("127.0.0.1", 4321);
+      NodeSpiMock secondDeadNode = (NodeSpiMock) root.addChildDirect(BuddyFqnTransformer.getDeadBackupRoot(secondAddress));
+      secondDeadNode.addChildDirect(Fqn.fromElements(0));
+
+
+      expect(spiMock.getNode(fqn)).andReturn(null);
+      NodeSPI buddyBackupRoot = (NodeSPI) root.getChild(BuddyManager.BUDDY_BACKUP_SUBTREE_FQN);
+      expect(containerMock.peek(BuddyManager.BUDDY_BACKUP_SUBTREE_FQN)).andReturn(buddyBackupRoot);
+
+      control.checkOrder(false);
+      expect(spiMock.getChildrenNames(firstDeadNode.getFqn())).andReturn(firstDeadNode.getChildrenNames());
+      Object fqnElement = fqn.getLastElement();//this is only composed from one element
+      expect(spiMock.peek(Fqn.fromRelativeElements(firstDeadNode.getFqn(), 0, fqnElement), false)).andReturn(null);
+      expect(spiMock.peek(Fqn.fromRelativeElements(firstDeadNode.getFqn(), 1, fqnElement), false)).andReturn(null);
+      expect(spiMock.peek(Fqn.fromRelativeElements(firstDeadNode.getFqn(), 2, fqnElement), false)).andReturn(null);
+
+      expect(spiMock.getChildrenNames(secondDeadNode.getFqn())).andReturn(secondDeadNode.getChildrenNames());
+      expect(spiMock.peek(Fqn.fromRelativeElements(secondDeadNode.getFqn(), 0, fqnElement), false)).andReturn(null);
+      control.checkOrder(true);
+
+      control.replay();
+      assert GravitateResult.noDataFound().equals(command.perform(ctx));
+      control.verify();
+   }
+}

Modified: core/trunk/src/test/java/org/jboss/cache/marshall/ReturnValueMarshallingTest.java
===================================================================
--- core/trunk/src/test/java/org/jboss/cache/marshall/ReturnValueMarshallingTest.java	2008-05-14 17:05:33 UTC (rev 5849)
+++ core/trunk/src/test/java/org/jboss/cache/marshall/ReturnValueMarshallingTest.java	2008-05-15 12:44:49 UTC (rev 5850)
@@ -128,7 +128,7 @@
       assertNotSame(MyList.class, cache2.get(fqn, key).getClass());
       assertSame(listClass, cache2.get(fqn, key).getClass());
 
-      GravitateDataCommand gravitateDataCommand = new GravitateDataCommand(fqn, false);
+      GravitateDataCommand gravitateDataCommand = new GravitateDataCommand(fqn, false, cache1.getRPCManager().getLocalAddress());
 
       List responses = cache1.getRPCManager().callRemoteMethods(null, gravitateDataCommand, true, 15000, false);
       GravitateResult data = (GravitateResult) responses.get(0);// response from the first (and only) node

Added: core/trunk/src/test/java/org/jboss/cache/mock/MockNodesFixture.java
===================================================================
--- core/trunk/src/test/java/org/jboss/cache/mock/MockNodesFixture.java	                        (rev 0)
+++ core/trunk/src/test/java/org/jboss/cache/mock/MockNodesFixture.java	2008-05-15 12:44:49 UTC (rev 5850)
@@ -0,0 +1,67 @@
+package org.jboss.cache.mock;
+
+import org.jboss.cache.Fqn;
+
+/**
+ * This class builds a tree of <code>NodeSpiMock</code>s that can be used through tests.
+ * <pre>
+ * It serves following purposes:
+ * - having a common known structure through all the tests is useful for test redability
+ * - not having to write again and again a new fixture for each test.
+ * </pre>
+ * Note: changing the fixture might cause tests depending on this class to fail, as the expect certain number of nodes,
+ * number of child etc.
+ *
+ * @author Mircea.Markus at jboss.com
+ * @since 2.2
+ */
+public class MockNodesFixture
+{
+   public NodeSpiMock root;
+   public NodeSpiMock aNode;
+   public Fqn a;
+   public Fqn ab;
+   public Fqn abc;
+   public Fqn ad;
+   public Fqn ade;
+   public Fqn adf;
+   public Fqn adfh;
+   public Fqn adfg;
+   public NodeSpiMock abNode;
+   public NodeSpiMock abcNode;
+   public NodeSpiMock adNode;
+   public NodeSpiMock adeNode;
+   public NodeSpiMock adfNode;
+   public NodeSpiMock adfhNode;
+   public NodeSpiMock adfgNode;
+   public Fqn notExistent = Fqn.fromString("aaa" + System.currentTimeMillis());
+
+   public MockNodesFixture()
+   {
+      this(Fqn.ROOT);
+   }
+
+   /**
+    * Will place the fqn prefix before all created nodes.
+    */
+   public MockNodesFixture(Fqn prefix)
+   {
+      a = Fqn.fromRelativeElements(prefix, "a");
+      ab = Fqn.fromRelativeElements(prefix, "a", "b");
+      abc = Fqn.fromRelativeElements(prefix, "a", "b", "c");
+      ad = Fqn.fromRelativeElements(prefix, "a", "d");
+      ade = Fqn.fromRelativeElements(prefix, "a", "d", "e");
+      adf = Fqn.fromRelativeElements(prefix, "a", "d", "f");
+      adfh = Fqn.fromRelativeElements(prefix, "a", "d", "f", "h");
+      adfg = Fqn.fromRelativeElements(prefix, "a", "d", "f", "g");
+      root = new NodeSpiMock(Fqn.ROOT);
+      aNode = (NodeSpiMock) root.addChild(a);
+      abNode = (NodeSpiMock) root.addChild(ab);
+      abcNode = (NodeSpiMock) root.addChild(abc);
+      adNode = (NodeSpiMock) root.addChild(ad);
+      adeNode = (NodeSpiMock) root.addChild(ade);
+      adfNode = (NodeSpiMock) root.addChild(adf);
+      adfhNode = (NodeSpiMock) root.addChild(adfh);
+      adfgNode = (NodeSpiMock) root.addChild(adfg);
+   }
+}

Modified: core/trunk/src/test/java/org/jboss/cache/notifications/AnnotationsTest.java
===================================================================
--- core/trunk/src/test/java/org/jboss/cache/notifications/AnnotationsTest.java	2008-05-14 17:05:33 UTC (rev 5849)
+++ core/trunk/src/test/java/org/jboss/cache/notifications/AnnotationsTest.java	2008-05-15 12:44:49 UTC (rev 5850)
@@ -23,13 +23,13 @@
 @Test(groups = {"functional"})
 public class AnnotationsTest
 {
-   private Notifier n;
+   private NotifierImpl n;
 
    @BeforeMethod(alwaysRun = true)
    public void setUp()
    {
       Cache c = new DefaultCacheFactory().createCache(false);
-      n = new Notifier(c);
+      n = new NotifierImpl(c);
    }
 
    public void testControl()

Modified: core/trunk/src/test/java/org/jboss/cache/notifications/RemoteCacheListenerTest.java
===================================================================
--- core/trunk/src/test/java/org/jboss/cache/notifications/RemoteCacheListenerTest.java	2008-05-14 17:05:33 UTC (rev 5849)
+++ core/trunk/src/test/java/org/jboss/cache/notifications/RemoteCacheListenerTest.java	2008-05-15 12:44:49 UTC (rev 5850)
@@ -114,7 +114,7 @@
       cr1 = TestingUtil.extractComponentRegistry(cache1);
       cr2 = TestingUtil.extractComponentRegistry(cache2);
       assert cr1 != cr2;
-      assert cr1.getComponent(Notifier.class) != cr2.getComponent(Notifier.class);
+      assert cr1.getComponent(NotifierImpl.class) != cr2.getComponent(NotifierImpl.class);
       assert eventLog1 != eventLog2;
       assert cache1.getLocalAddress() != cache2.getLocalAddress();
       CacheSPI spi1, spi2;




More information about the jbosscache-commits mailing list