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

jbosscache-commits at lists.jboss.org jbosscache-commits at lists.jboss.org
Tue May 20 18:02:20 EDT 2008


Author: mircea.markus
Date: 2008-05-20 18:02:19 -0400 (Tue, 20 May 2008)
New Revision: 5879

Added:
   core/trunk/src/main/java/org/jboss/cache/commands/write/ClearDataCommand.java
   core/trunk/src/main/java/org/jboss/cache/commands/write/OptimisticInvalidateCommand.java
   core/trunk/src/test/java/org/jboss/cache/commands/write/
   core/trunk/src/test/java/org/jboss/cache/commands/write/AbstractVersionedDataCommandTest.java
   core/trunk/src/test/java/org/jboss/cache/commands/write/ClearDataCommandTest.java
   core/trunk/src/test/java/org/jboss/cache/commands/write/CreateNodeCommandTest.java
   core/trunk/src/test/java/org/jboss/cache/commands/write/EvictCommandTest.java
   core/trunk/src/test/java/org/jboss/cache/commands/write/InvalidateCommandTest.java
   core/trunk/src/test/java/org/jboss/cache/commands/write/OptimisticInvalidateCommandTest.java
   core/trunk/src/test/java/org/jboss/cache/commands/write/PutDataMapCommandTest.java
   core/trunk/src/test/java/org/jboss/cache/commands/write/PutKeyValueCommandTest.java
   core/trunk/src/test/java/org/jboss/cache/commands/write/RemoveKeyCommandTest.java
Removed:
   core/trunk/src/main/java/org/jboss/cache/commands/write/RemoveDataCommand.java
Modified:
   core/trunk/src/main/java/org/jboss/cache/DataContainerImpl.java
   core/trunk/src/main/java/org/jboss/cache/buddyreplication/BuddyFqnTransformer.java
   core/trunk/src/main/java/org/jboss/cache/commands/AbstractVisitor.java
   core/trunk/src/main/java/org/jboss/cache/commands/Visitor.java
   core/trunk/src/main/java/org/jboss/cache/commands/read/AbstractDataCommand.java
   core/trunk/src/main/java/org/jboss/cache/commands/write/AbstractVersionedDataCommand.java
   core/trunk/src/main/java/org/jboss/cache/commands/write/CreateNodeCommand.java
   core/trunk/src/main/java/org/jboss/cache/commands/write/EvictCommand.java
   core/trunk/src/main/java/org/jboss/cache/commands/write/InvalidateCommand.java
   core/trunk/src/main/java/org/jboss/cache/commands/write/PutDataMapCommand.java
   core/trunk/src/main/java/org/jboss/cache/commands/write/PutKeyValueCommand.java
   core/trunk/src/main/java/org/jboss/cache/commands/write/RemoveKeyCommand.java
   core/trunk/src/main/java/org/jboss/cache/factories/CommandsFactory.java
   core/trunk/src/main/java/org/jboss/cache/interceptors/ActivationInterceptor.java
   core/trunk/src/main/java/org/jboss/cache/interceptors/CacheLoaderInterceptor.java
   core/trunk/src/main/java/org/jboss/cache/interceptors/CacheStoreInterceptor.java
   core/trunk/src/main/java/org/jboss/cache/interceptors/CallInterceptor.java
   core/trunk/src/main/java/org/jboss/cache/interceptors/EvictionInterceptor.java
   core/trunk/src/main/java/org/jboss/cache/interceptors/InvalidationInterceptor.java
   core/trunk/src/main/java/org/jboss/cache/interceptors/InvocationContextInterceptor.java
   core/trunk/src/main/java/org/jboss/cache/interceptors/MarshalledValueInterceptor.java
   core/trunk/src/main/java/org/jboss/cache/interceptors/OptimisticNodeInterceptor.java
   core/trunk/src/main/java/org/jboss/cache/interceptors/OptimisticReplicationInterceptor.java
   core/trunk/src/main/java/org/jboss/cache/interceptors/OptimisticTxInterceptor.java
   core/trunk/src/main/java/org/jboss/cache/interceptors/PessimisticLockInterceptor.java
   core/trunk/src/main/java/org/jboss/cache/interceptors/ReplicationInterceptor.java
   core/trunk/src/main/java/org/jboss/cache/interceptors/TxInterceptor.java
   core/trunk/src/main/java/org/jboss/cache/interceptors/base/PostProcessingCommandInterceptor.java
   core/trunk/src/main/java/org/jboss/cache/interceptors/base/SkipCheckChainedInterceptor.java
   core/trunk/src/main/java/org/jboss/cache/invocation/CacheInvocationDelegate.java
   core/trunk/src/test/java/org/jboss/cache/commands/read/AbstractDataCommandTest.java
   core/trunk/src/test/java/org/jboss/cache/interceptors/EvictionInterceptorTest.java
   core/trunk/src/test/java/org/jboss/cache/invalidation/VersionInconsistencyTest.java
   core/trunk/src/test/java/org/jboss/cache/mock/NodeSpiMock.java
Log:
JBCACHE-1338 - added unit tests for read commands and small refactorings

Modified: core/trunk/src/main/java/org/jboss/cache/DataContainerImpl.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/DataContainerImpl.java	2008-05-20 16:34:22 UTC (rev 5878)
+++ core/trunk/src/main/java/org/jboss/cache/DataContainerImpl.java	2008-05-20 22:02:19 UTC (rev 5879)
@@ -144,7 +144,7 @@
       if (n == null)
       {
          StringBuilder builder = new StringBuilder();
-         builder.append("Node ").append(fqn).append(" not found (gtx=").append(gtx).append(")");
+         builder.append("Node ").append(fqn).append(" not found");
          String errStr = builder.toString();
          if (trace) log.trace(errStr);
          throw new NodeNotExistsException(errStr);

Modified: core/trunk/src/main/java/org/jboss/cache/buddyreplication/BuddyFqnTransformer.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/buddyreplication/BuddyFqnTransformer.java	2008-05-20 16:34:22 UTC (rev 5878)
+++ core/trunk/src/main/java/org/jboss/cache/buddyreplication/BuddyFqnTransformer.java	2008-05-20 22:02:19 UTC (rev 5879)
@@ -92,11 +92,10 @@
    }
 
    @Override
-   public Object visitRemoveDataCommand(InvocationContext ctx, RemoveDataCommand command) throws Throwable
+   public Object visitClearDataCommand(InvocationContext ctx, ClearDataCommand command) throws Throwable
    {
       Fqn transformed = getBackupFqn(command.getFqn());
-      return factory.buildRemoveDataCommand(command.getGlobalTransaction(), transformed, command.isCreateUndoops(),
-            command.isSendNodeEvent(), command.isEviction());
+      return factory.buildClearDataCommand(command.getGlobalTransaction(), transformed);
    }
 
    @Override
@@ -117,7 +116,7 @@
    public Object visitRemoveKeyCommand(InvocationContext ctx, RemoveKeyCommand command) throws Throwable
    {
       Fqn transformed = getBackupFqn(command.getFqn());
-      return factory.buildRemoveKeyCommand(null, transformed, command.getKey(), command.isCreateUndoOps());
+      return factory.buildRemoveKeyCommand(null, transformed, command.getKey());
    }
 
    @Override

Modified: core/trunk/src/main/java/org/jboss/cache/commands/AbstractVisitor.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/commands/AbstractVisitor.java	2008-05-20 16:34:22 UTC (rev 5878)
+++ core/trunk/src/main/java/org/jboss/cache/commands/AbstractVisitor.java	2008-05-20 22:02:19 UTC (rev 5879)
@@ -45,7 +45,7 @@
       return handleDefault(ctx, command);
    }
 
-   public Object visitRemoveDataCommand(InvocationContext ctx, RemoveDataCommand command) throws Throwable
+   public Object visitClearDataCommand(InvocationContext ctx, ClearDataCommand command) throws Throwable
    {
       return handleDefault(ctx, command);
    }

Modified: core/trunk/src/main/java/org/jboss/cache/commands/Visitor.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/commands/Visitor.java	2008-05-20 16:34:22 UTC (rev 5878)
+++ core/trunk/src/main/java/org/jboss/cache/commands/Visitor.java	2008-05-20 22:02:19 UTC (rev 5879)
@@ -73,7 +73,7 @@
     * @return response from the visit
     * @throws Throwable in the event of problems.
     */
-   Object visitRemoveDataCommand(InvocationContext ctx, RemoveDataCommand command) throws Throwable;
+   Object visitClearDataCommand(InvocationContext ctx, ClearDataCommand command) throws Throwable;
 
    /**
     * Visits a EvictCommand.

Modified: core/trunk/src/main/java/org/jboss/cache/commands/read/AbstractDataCommand.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/commands/read/AbstractDataCommand.java	2008-05-20 16:34:22 UTC (rev 5878)
+++ core/trunk/src/main/java/org/jboss/cache/commands/read/AbstractDataCommand.java	2008-05-20 22:02:19 UTC (rev 5879)
@@ -25,6 +25,11 @@
       return fqn;
    }
 
+   void setFqn(Fqn fqn)
+   {
+      this.fqn = fqn;
+   }
+
    /**
     * Basic versions of these methods
     */

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-20 16:34:22 UTC (rev 5878)
+++ core/trunk/src/main/java/org/jboss/cache/commands/write/AbstractVersionedDataCommand.java	2008-05-20 22:02:19 UTC (rev 5879)
@@ -1,7 +1,7 @@
 package org.jboss.cache.commands.write;
 
+import org.jboss.cache.DataContainer;
 import org.jboss.cache.Fqn;
-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, DataContainerImpl dataContainer)
+   public void initialize(Notifier notifier, DataContainer dataContainer)
    {
       this.notifier = notifier;
       this.dataContainer = dataContainer;

Copied: core/trunk/src/main/java/org/jboss/cache/commands/write/ClearDataCommand.java (from rev 5877, core/trunk/src/main/java/org/jboss/cache/commands/write/RemoveDataCommand.java)
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/commands/write/ClearDataCommand.java	                        (rev 0)
+++ core/trunk/src/main/java/org/jboss/cache/commands/write/ClearDataCommand.java	2008-05-20 22:02:19 UTC (rev 5879)
@@ -0,0 +1,143 @@
+package org.jboss.cache.commands.write;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.jboss.cache.Fqn;
+import org.jboss.cache.InvocationContext;
+import org.jboss.cache.NodeSPI;
+import org.jboss.cache.commands.Visitor;
+import org.jboss.cache.notifications.event.NodeModifiedEvent;
+import org.jboss.cache.optimistic.DataVersion;
+import org.jboss.cache.transaction.GlobalTransaction;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Implements functionality defined by {@link org.jboss.cache.Cache#clearData(String)}}
+ *
+ * @author Mircea.Markus at jboss.com
+ * @since 2.2
+ */
+public class ClearDataCommand extends AbstractVersionedDataCommand
+{
+   public static final int METHOD_ID = 7;
+   public static final int VERSIONED_METHOD_ID = 42;
+
+   private static final Log log = LogFactory.getLog(ClearDataCommand.class);
+   private static boolean trace = log.isTraceEnabled();
+
+   /* parameters*/
+   private HashMap originalData;
+
+   public ClearDataCommand(GlobalTransaction gtx, Fqn fqn)
+   {
+      this.globalTransaction = gtx;
+      this.fqn = fqn;
+   }
+
+   public ClearDataCommand()
+   {
+   }
+
+   /**
+    * Clears the data map in the node referenced by the specified Fqn.
+    *
+    * @param ctx invocation context
+    * @return null
+    */
+   public Object perform(InvocationContext ctx)
+   {
+      if (trace) log.trace("perform(" + globalTransaction + ", \"" + fqn + "\")");
+      NodeSPI targetNode = dataContainer.peekVersioned(fqn, dataVersion);
+      if (targetNode == null)
+      {
+         log.warn("node " + fqn + " not found");
+         return null;
+      }
+
+      Map data = targetNode.getDataDirect();
+      prepareDataForRollback(data);
+      notifier.notifyNodeModified(fqn, true, NodeModifiedEvent.ModificationType.REMOVE_DATA, data, ctx);
+      targetNode.clearDataDirect();
+      notifier.notifyNodeModified(fqn, false, NodeModifiedEvent.ModificationType.REMOVE_DATA, data, ctx);
+      return null;
+   }
+
+   private void prepareDataForRollback(Map data)
+   {
+      if (globalTransaction != null && !data.isEmpty())
+      {
+         originalData = new HashMap(data);
+      }
+   }
+
+   public void rollback()
+   {
+      if (trace) log.trace("rollback(" + globalTransaction + ", \"" + fqn + "\", " + originalData + ")");
+      NodeSPI nodeSPI = dataContainer.peekStrict(globalTransaction, fqn, true);
+      nodeSPI.putAllDirect(originalData);
+   }
+
+   public Object acceptVisitor(InvocationContext ctx, Visitor visitor) throws Throwable
+   {
+      return visitor.visitClearDataCommand(ctx, this);
+   }
+
+   public int getCommandId()
+   {
+      return isVersioned() ? VERSIONED_METHOD_ID : METHOD_ID;
+   }
+
+   @Override
+   public Object[] getParameters()
+   {
+      if (isVersioned())
+         return new Object[]{globalTransaction, fqn, true, dataVersion};
+      else
+         return new Object[]{globalTransaction, fqn, true};
+   }
+
+   @Override
+   public void setParameters(int commandId, Object[] args)
+   {
+      globalTransaction = (GlobalTransaction) args[0];
+      fqn = (Fqn) args[1];
+      if (isVersionedId(commandId)) dataVersion = (DataVersion) args[3];
+   }
+
+   @Override
+   public boolean equals(Object o)
+   {
+      if (this == o) return true;
+      if (o == null || getClass() != o.getClass()) return false;
+      if (!super.equals(o)) return false;
+      ClearDataCommand that = (ClearDataCommand) o;
+      return !(globalTransaction != null ? !globalTransaction.equals(that.globalTransaction) : that.globalTransaction != null);
+   }
+
+   @Override
+   public int hashCode()
+   {
+      int result = super.hashCode();
+      result = 31 * result + (globalTransaction != null ? globalTransaction.hashCode() : 0);
+      return result;
+   }
+
+   @Override
+   protected boolean isVersionedId(int id)
+   {
+      return id == VERSIONED_METHOD_ID;
+   }
+
+   @Override
+   public String toString()
+   {
+      return "RemoveDataCommand{" +
+            "fqn=" + fqn +
+            ", dataVersion=" + dataVersion +
+            ", globalTransaction=" + globalTransaction +
+            ", originalData=" + originalData +
+            '}';
+   }
+}

Modified: core/trunk/src/main/java/org/jboss/cache/commands/write/CreateNodeCommand.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/commands/write/CreateNodeCommand.java	2008-05-20 16:34:22 UTC (rev 5878)
+++ core/trunk/src/main/java/org/jboss/cache/commands/write/CreateNodeCommand.java	2008-05-20 22:02:19 UTC (rev 5879)
@@ -49,12 +49,8 @@
 
    /**
     * Creates a node in the cache, specified by the given Fqn.
-    *
-    * @param ctx invocation context
-    * @return a Node
-    * @throws Throwable in the event of problems
     */
-   public Object perform(InvocationContext ctx) throws Throwable
+   public Object perform(InvocationContext ctx) 
    {
       Object[] results = dataContainer.createNodes(fqn);
       List<NodeSPI> created = (List<NodeSPI>) results[0];
@@ -68,7 +64,7 @@
             newlyCreated.add(n.getFqn());
          }
       }
-      if (!foundFqn) newlyCreated.remove(fqn);
+      if (newlyCreated != null && !foundFqn) newlyCreated.remove(fqn);
 
       return results[1];
    }
@@ -94,4 +90,9 @@
             ", newlyCreated=" + newlyCreated +
             '}';
    }
+
+   List<Fqn> getNewlyCreated()
+   {
+      return newlyCreated;
+   }
 }

Modified: core/trunk/src/main/java/org/jboss/cache/commands/write/EvictCommand.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/commands/write/EvictCommand.java	2008-05-20 16:34:22 UTC (rev 5878)
+++ core/trunk/src/main/java/org/jboss/cache/commands/write/EvictCommand.java	2008-05-20 22:02:19 UTC (rev 5879)
@@ -3,7 +3,10 @@
 import org.jboss.cache.Fqn;
 import org.jboss.cache.InvocationContext;
 import org.jboss.cache.NodeSPI;
+import org.jboss.cache.DataContainer;
+import org.jboss.cache.notifications.Notifier;
 import org.jboss.cache.commands.Visitor;
+import org.jboss.cache.commands.read.AbstractDataCommand;
 
 import java.util.List;
 
@@ -13,13 +16,15 @@
  * @author Mircea.Markus at jboss.com
  * @since 2.2
  */
-public class EvictCommand extends AbstractVersionedDataCommand
+public class EvictCommand extends AbstractDataCommand
 {
    public static final int METHOD_ID = 8;
    public static final int VERSIONED_METHOD_ID = 9;
 
    private boolean recursive = false;
 
+   protected Notifier notifier;
+
    public EvictCommand(Fqn fqn)
    {
       this.fqn = fqn;
@@ -29,32 +34,35 @@
    {
    }
 
+   public void initialize(Notifier notifier, DataContainer dataContainer)
+   {
+      super.initialize(dataContainer);
+      this.notifier = notifier;
+   }
+
    /**
     * Evicts a node.
     * <p/>
     * See {@link org.jboss.cache.interceptors.EvictionInterceptor#visitEvictFqnCommand(org.jboss.cache.InvocationContext, EvictCommand)}
     * which is where the return value is used
     *
-    * @param ctx invocaton context
-    * @return true if the node was removed from the tree.  Returns false if the node still exists; i.e. was only data removed because it still has children.
+    * @return true if the node was removed from the tree or if it is resident.  Returns false if the node still exists; i.e. was only data removed because it still has children.
     */
    public Object perform(InvocationContext ctx)
    {
-      NodeSPI node = dataContainer.peek(fqn, false);
+      NodeSPI node = dataContainer.peek(fqn, false, false);
       if (node != null && node.isResident())
       {
          return true;
       }
       if (recursive)
       {
-
          List<Fqn> nodesToEvict = dataContainer.getNodesForEviction(fqn, true);
-
          for (Fqn aFqn : nodesToEvict)
          {
             evictNode(aFqn, ctx);
          }
-         return null;
+         return !nodesToEvict.isEmpty();
       }
       else
       {
@@ -82,15 +90,9 @@
 
    public int getCommandId()
    {
-      return isVersioned() ? VERSIONED_METHOD_ID : METHOD_ID;
+      return METHOD_ID;
    }
 
-   @Override
-   protected boolean isVersionedId(int id)
-   {
-      return VERSIONED_METHOD_ID == id;
-   }
-
    public boolean isRecursive()
    {
       return recursive;
@@ -120,7 +122,6 @@
       return "EvictCommand{" +
             "fqn=" + fqn +
             ", recursive=" + recursive +
-            ", dataVersion=" + dataVersion +
             "}";
    }
 

Modified: core/trunk/src/main/java/org/jboss/cache/commands/write/InvalidateCommand.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/commands/write/InvalidateCommand.java	2008-05-20 16:34:22 UTC (rev 5878)
+++ core/trunk/src/main/java/org/jboss/cache/commands/write/InvalidateCommand.java	2008-05-20 22:02:19 UTC (rev 5879)
@@ -2,13 +2,10 @@
 
 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.Fqn;
-import org.jboss.cache.InvocationContext;
-import org.jboss.cache.Node;
-import org.jboss.cache.NodeSPI;
+import org.jboss.cache.*;
+import org.jboss.cache.notifications.Notifier;
 import org.jboss.cache.commands.Visitor;
+import org.jboss.cache.commands.read.AbstractDataCommand;
 import org.jboss.cache.config.Option;
 import org.jboss.cache.optimistic.DataVersion;
 
@@ -18,43 +15,36 @@
 import java.util.Map;
 
 /**
- * Very much like an evict(), except that regardless of whether there is a child present, this call will never
- * remove the node from memory - just remove its contents.
- * <p/>
- * Also, potentially throws a cache exception if data versioning is used and the node in memory has a newer data
- * version than what is passed in.
- * <p/>
- * Finally, the data version of the in-memory node is updated to the version being evicted to prevent versions
- * going out of sync.
+ * Removes a node's content from memory - never removes the node.
+ * It also clenups data for resident nodes - which are not being touched by eviction. 
  *
  * @author Mircea.Markus at jboss.com
  * @since 2.2
  */
-public class InvalidateCommand extends EvictCommand
+public class InvalidateCommand extends AbstractDataCommand
 {
    public static final int METHOD_ID = 47;
    private static final Log log = LogFactory.getLog(InvalidateCommand.class);
    private static boolean trace = log.isTraceEnabled();
 
    /* dependencies*/
-   private boolean isOptimisticLocking;
-   private TransactionManager transactionManager;
-   private CacheSPI spi;
+   protected CacheSPI spi;
+   protected Notifier notifier;
 
    public InvalidateCommand(Fqn fqn)
    {
-      super(fqn);
+      this.fqn = fqn;
    }
 
    public InvalidateCommand()
    {
    }
 
-   public void initialize(TransactionManager txManager, CacheSPI cacheSpi, boolean optimistic)
+   public void initialize(CacheSPI cacheSpi, DataContainer dataContainer, Notifier notifier)
    {
-      this.transactionManager = txManager;
       this.spi = cacheSpi;
-      this.isOptimisticLocking = optimistic;
+      this.dataContainer = dataContainer;
+      this.notifier = notifier;
    }
 
    /**
@@ -63,117 +53,60 @@
     * @param ctx invocation context
     * @return null
     */
-   @Override
    public Object perform(InvocationContext ctx)
    {
-      //TODO: 2.2.0: rather than using CacheSPI this should use peek().  The other interceptors should obtain locks and load nodes if necessary for this InvalidateCommand.
-      Node node = spi.getNode(fqn); // force interceptor chain, load if necessary from cache loader.
-
+      NodeSPI node = enforceNodeLoading();
       if (trace) log.trace("Invalidating fqn:" + fqn);
       if (node == null)
       {
-         // if pessimistic locking, just return.
-         if (!isOptimisticLocking) return null;
-
-         // check if a tombstone already exists
-         NodeSPI nodeSPI = dataContainer.peek(fqn, false, true);
-         if (nodeSPI == null)
-         {
-            if (dataVersion == null)
-            {
-               if (trace)
-                  log.trace("Would have created a tombstone since the node doesn't exist, but the version to invalidate is null and hence cannot create a tombstone!");
-               return null;
-            }
-            if (trace)
-               log.trace("Node doesn't exist; creating a tombstone with data version " + dataVersion);
-            // create the node we need.
-            Map m = Collections.emptyMap();
-            InvocationContext ic = spi.getInvocationContext();
-            Option o = ic.getOptionOverrides();
-            boolean origCacheModeLocal = o.isCacheModeLocal();
-            o.setCacheModeLocal(true);
-            o.setDataVersion(dataVersion);
-            // if we are in a tx this call should happen outside of any tx
-            try
-            {
-               Transaction suspended = null;
-               if (transactionManager != null)
-               {
-                  suspended = transactionManager.suspend();
-               }
-               spi.put(fqn, m);
-               if (suspended != null) transactionManager.resume(suspended);
-               ic.getOptionOverrides().setCacheModeLocal(origCacheModeLocal);
-            }
-            catch (Exception e)
-            {
-               log.error("Unable to create tombstone!", e);
-            }
-            nodeSPI = (NodeSPI) dataContainer.getRoot().getChild(fqn);
-         }
-         node = nodeSPI;
+         return null;
       }
-
-      if (isOptimisticLocking)
-         removeData();
-      else
-         super.perform(ctx);
-
-      // 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.
-      NodeSPI nSPI = (NodeSPI) node;
-      nSPI.setValid(false, true);
-      // root nodes can never be invalid
-      if (fqn.isRoot()) nSPI.setValid(true, false); // non-recursive.
-
-      if (dataVersion != null)
-      {
-         NodeSPI n = dataContainer.peek(fqn, false, true);
-         n.setVersion(dataVersion);
-      }
+      evictNode(fqn, ctx);
+      invalidateNode(node);
       return null;
    }
 
-   private void removeData()
-         throws CacheException
+   boolean evictNode(Fqn fqn, InvocationContext ctx)
    {
-      // Find the node. This will lock it (if <tt>locking</tt> is true) and
-      // add the temporarily created parent nodes to the TX's node list if tx != null)
-      NodeSPI n = dataContainer.peekVersioned(fqn, dataVersion);
-      if (n == null)
+      notifier.notifyNodeEvicted(fqn, true, ctx);
+      try
       {
-         log.warn("node " + fqn + " not found");
-         return;
+         return dataContainer.evict(fqn);
       }
-      InvocationContext ctx = spi.getInvocationContext();
-      notifier.notifyNodeEvicted(fqn, true, ctx);
-      n.clearDataDirect();
-      n.setDataLoaded(false);
-      notifier.notifyNodeEvicted(fqn, false, ctx);
+      finally
+      {
+         notifier.notifyNodeEvicted(fqn, false, ctx);
+      }
    }
 
-   @Override
-   public Object acceptVisitor(InvocationContext ctx, Visitor visitor) throws Throwable
+
+   /**
+    * //TODO: 2.2.0: rather than using CacheSPI this should use peek().  The other interceptors should obtain locks and load nodes if necessary for this InvalidateCommand.
+      //Even better - this can be handles in the interceptors before call interceptor
+    */
+   protected NodeSPI enforceNodeLoading()
    {
-      return visitor.visitInvalidateCommand(ctx, this);
+      return spi.getNode(fqn);
    }
 
-   @Override
-   public boolean isVersioned()
+
+   /**
+    *  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.
+    */
+   protected void invalidateNode(NodeSPI node)
    {
-      // invalidate commands are *always* versioned.
-      return true;
+      node.setValid(false, true);
+      // root nodes can never be invalid
+      if (fqn.isRoot()) node.setValid(true, false); // non-recursive.
    }
 
-   @Override
-   protected boolean isVersionedId(int id)
+
+   public Object acceptVisitor(InvocationContext ctx, Visitor visitor) throws Throwable
    {
-      // invalidate commands are *always* versioned.
-      return true;
+      return visitor.visitInvalidateCommand(ctx, this);
    }
 
-   @Override
    public int getCommandId()
    {
       return METHOD_ID;
@@ -184,21 +117,23 @@
    {
       return "InvalidateCommand{" +
             "fqn=" + fqn +
-            ", dataVersion=" + dataVersion +
             '}';
    }
 
    @Override
    public Object[] getParameters()
    {
-      return new Object[]{fqn, dataVersion};
+      return new Object[]{fqn};
    }
 
    @Override
    public void setParameters(int commandId, Object[] args)
    {
       fqn = (Fqn) args[0];
-      dataVersion = (DataVersion) args[1];
    }
 
+   void setFqn(Fqn newFqn)
+   {
+      this.fqn = newFqn;
+   }
 }

Added: core/trunk/src/main/java/org/jboss/cache/commands/write/OptimisticInvalidateCommand.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/commands/write/OptimisticInvalidateCommand.java	                        (rev 0)
+++ core/trunk/src/main/java/org/jboss/cache/commands/write/OptimisticInvalidateCommand.java	2008-05-20 22:02:19 UTC (rev 5879)
@@ -0,0 +1,189 @@
+package org.jboss.cache.commands.write;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.jboss.cache.CacheException;
+import org.jboss.cache.Fqn;
+import org.jboss.cache.InvocationContext;
+import org.jboss.cache.NodeSPI;
+import org.jboss.cache.commands.VersionedDataCommand;
+import org.jboss.cache.config.Option;
+import org.jboss.cache.optimistic.DataVersion;
+import org.jboss.cache.transaction.GlobalTransaction;
+
+import javax.transaction.Transaction;
+import javax.transaction.TransactionManager;
+import java.util.Collections;
+import java.util.Map;
+
+/**
+ * Behaves like {@link org.jboss.cache.commands.write.InvalidateCommand}. Also, potentially throws a cache exception if
+ * data versioning is used and the node in memory has a newer data version than what is passed in.
+ * <p/>
+ * Finally, the data version of the in-memory node is updated to the version being evicted to prevent versions
+ * going out of sync.
+ * <p/>
+ *
+ * @author Mircea.Markus at jboss.com
+ * @since 2.2
+ */
+public class OptimisticInvalidateCommand extends InvalidateCommand implements VersionedDataCommand
+{
+   private static final Log log = LogFactory.getLog(OptimisticInvalidateCommand.class);
+   private static boolean trace = log.isTraceEnabled();
+
+   /*
+     dependencies
+    */
+   private TransactionManager transactionManager;
+
+   /**
+    * Params.
+    */
+   protected GlobalTransaction globalTransaction;
+   private DataVersion dataVersion;
+
+   public OptimisticInvalidateCommand(Fqn fqn)
+   {
+      super(fqn);
+   }
+
+   public OptimisticInvalidateCommand()
+   {
+   }
+
+   public void initialize(TransactionManager txManager)
+   {
+      this.transactionManager = txManager;
+   }
+
+   @Override
+   public Object perform(InvocationContext ctx)
+   {
+      NodeSPI node = enforceNodeLoading();
+      if (trace) log.trace("Invalidating fqn:" + fqn);
+      if (node == null)
+      {
+         // check if a tombstone already exists
+         NodeSPI nodeSPI = dataContainer.peek(fqn, false, true);
+         if (nodeSPI == null)
+         {
+            if (dataVersion == null)
+            {
+               if (trace)
+                  log.trace("Would have created a tombstone since the node doesn't exist, but the version to invalidate is null and hence cannot create a tombstone!");
+               return null;
+            }
+            createTombstone(ctx);
+            nodeSPI = (NodeSPI) dataContainer.getRoot().getChild(fqn);
+         }
+         node = nodeSPI;
+      }
+      removeData(ctx);
+      invalidateNode(node);
+      updateDataVersion();
+      return null;
+   }
+
+   protected void createTombstone(InvocationContext ctx)
+   {
+      if (trace)
+         log.trace("Node doesn't exist; creating a tombstone with data version " + dataVersion);
+      // create the node we need.
+      Option o = ctx.getOptionOverrides();
+      boolean origCacheModeLocal = o.isCacheModeLocal();
+      o.setCacheModeLocal(true);
+      o.setDataVersion(dataVersion);
+      // if we are in a tx this call should happen outside of any tx
+      try
+      {
+         Transaction suspended = null;
+         if (transactionManager != null)
+         {
+            suspended = transactionManager.suspend();
+         }
+         spi.put(fqn, Collections.emptyMap());
+         if (suspended != null) transactionManager.resume(suspended);
+         ctx.getOptionOverrides().setCacheModeLocal(origCacheModeLocal);
+      }
+      catch (Exception e)
+      {
+         log.error("Unable to create tombstone!", e);
+      }
+   }
+
+   private void updateDataVersion()
+   {
+      if (dataVersion != null)
+      {
+         NodeSPI n = dataContainer.peek(fqn, false, true);
+         n.setVersion(dataVersion);
+      }
+   }
+
+   protected void removeData(InvocationContext ctx) throws CacheException
+   {
+      NodeSPI n = dataContainer.peekVersioned(fqn, dataVersion);
+      if (n == null)
+      {
+         log.warn("node " + fqn + " not found");
+         return;
+      }
+      notifier.notifyNodeEvicted(fqn, true, ctx);
+      n.clearDataDirect();
+      n.setDataLoaded(false);
+      notifier.notifyNodeEvicted(fqn, false, ctx);
+   }
+
+   public DataVersion getDataVersion()
+   {
+      return dataVersion;
+   }
+
+   public void setDataVersion(DataVersion dataVersion)
+   {
+      this.dataVersion = dataVersion;
+   }
+
+   public GlobalTransaction getGlobalTransaction()
+   {
+      return globalTransaction;
+   }
+
+   public void setGlobalTransaction(GlobalTransaction gtx)
+   {
+      this.globalTransaction = gtx;
+   }
+
+   public boolean isVersioned()
+   {
+      return dataVersion != null;
+   }
+
+   @Override
+   public String toString()
+   {
+      return "OptimisticInvalidateCommand{" +
+            "dataVersion=" + dataVersion +
+            " ,fqn=" + fqn +
+            '}';
+   }
+
+   @Override
+   public Object[] getParameters()
+   {
+      return new Object[]{fqn, dataVersion};
+   }
+
+   @Override
+   public void setParameters(int commandId, Object[] args)
+   {
+      fqn = (Fqn) args[0];
+      dataVersion = (DataVersion) args[1];
+   }
+
+   public void rollback()
+   {
+      //no op
+   }
+}

Modified: core/trunk/src/main/java/org/jboss/cache/commands/write/PutDataMapCommand.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/commands/write/PutDataMapCommand.java	2008-05-20 16:34:22 UTC (rev 5878)
+++ core/trunk/src/main/java/org/jboss/cache/commands/write/PutDataMapCommand.java	2008-05-20 22:02:19 UTC (rev 5879)
@@ -29,6 +29,7 @@
 
    private static final Log log = LogFactory.getLog(PutDataMapCommand.class);
    private static boolean trace = log.isTraceEnabled();
+
    /* parameters*/
    private Map data;
    boolean createUndoOps;
@@ -62,10 +63,10 @@
          log.trace("perform(" + globalTransaction + ", \"" + fqn + "\", " + data + " undo=" + createUndoOps + " erase=" + eraseContents + ")");
       }
       NodeSPI nodeSPI = dataContainer.peekStrict(globalTransaction, fqn, false);
-      Map dataDirect = nodeSPI.getDataDirect();
-      if (!dataDirect.isEmpty())
+      Map existingData = nodeSPI.getDataDirect();
+      if (!existingData.isEmpty())
       {
-         oldData = new HashMap(dataDirect); // defensive copy
+         oldData = new HashMap(existingData); // defensive copy
       }
       notifier.notifyNodeModified(fqn, true, NodeModifiedEvent.ModificationType.PUT_MAP, oldData == null ? Collections.emptyMap() : oldData, ctx);
 
@@ -79,8 +80,7 @@
    public void rollback()
    {
       if (trace) log.trace("rollback(" + globalTransaction + ", " + fqn + ", " + data + ")");
-
-      NodeSPI n = dataContainer.peekVersioned(fqn, null, true);
+      NodeSPI n = dataContainer.peek(fqn, false, true);
       if (n != null)
       {
          n.clearDataDirect();
@@ -192,4 +192,14 @@
             ", globalTransaction=" + globalTransaction +
             '}';
    }
+
+   Map getOldData()
+   {
+      return oldData;
+   }
+
+   void setEraseContents(boolean eraseContents)
+   {
+      this.eraseContents = eraseContents;
+   }
 }

Modified: core/trunk/src/main/java/org/jboss/cache/commands/write/PutKeyValueCommand.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/commands/write/PutKeyValueCommand.java	2008-05-20 16:34:22 UTC (rev 5878)
+++ core/trunk/src/main/java/org/jboss/cache/commands/write/PutKeyValueCommand.java	2008-05-20 22:02:19 UTC (rev 5879)
@@ -60,12 +60,8 @@
          log.trace(new StringBuffer("perform(").append(globalTransaction).append(", \"").
                append(fqn).append("\", k=").append(key).append(", v=").append(value).append(")"));
       }
-      // if this is a rollback then don't fire notifications.
-      boolean isRollback = false;
-
-      NodeSPI n = dataContainer.peekStrict(globalTransaction, fqn, isRollback);
-      Map rawData = n.getDataDirect();
-      notifier.notifyNodeModified(fqn, true, NodeModifiedEvent.ModificationType.PUT_DATA, rawData, ctx);
+      NodeSPI n = dataContainer.peekStrict(globalTransaction, fqn, false);
+      notifier.notifyNodeModified(fqn, true, NodeModifiedEvent.ModificationType.PUT_DATA, n.getDataDirect(), ctx);
       oldValue = n.putDirect(key, value);
 
       Map newData = Collections.singletonMap(key, value);
@@ -75,16 +71,14 @@
 
    public void rollback()
    {
-      if (this.oldValue == null)
+      NodeSPI n = dataContainer.peek(fqn, false, false);
+      if (n == null) throw new CacheException("node " + fqn + " not found for rollback!");
+      if (oldValue == null)
       {
-         NodeSPI n = dataContainer.peek(fqn);
-         if (n == null) throw new CacheException("node " + fqn + " not found for rollback!");
          n.removeDirect(key);
       }
       else
       {
-         log.trace("Rolling back, setting the old value : " + oldValue);
-         NodeSPI n = dataContainer.peekStrict(globalTransaction, fqn, false);
          n.putDirect(key, oldValue);
       }
    }

Deleted: core/trunk/src/main/java/org/jboss/cache/commands/write/RemoveDataCommand.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/commands/write/RemoveDataCommand.java	2008-05-20 16:34:22 UTC (rev 5878)
+++ core/trunk/src/main/java/org/jboss/cache/commands/write/RemoveDataCommand.java	2008-05-20 22:02:19 UTC (rev 5879)
@@ -1,216 +0,0 @@
-package org.jboss.cache.commands.write;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.jboss.cache.Fqn;
-import org.jboss.cache.InvocationContext;
-import org.jboss.cache.NodeSPI;
-import org.jboss.cache.commands.Visitor;
-import org.jboss.cache.notifications.event.NodeModifiedEvent;
-import org.jboss.cache.optimistic.DataVersion;
-import org.jboss.cache.transaction.GlobalTransaction;
-
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * Implements functionality defined by {@link org.jboss.cache.Cache#remove(String, Object)}
- *
- * @author Mircea.Markus at jboss.com
- * @since 2.2
- */
-public class RemoveDataCommand extends AbstractVersionedDataCommand
-{
-   public static final int METHOD_ID = 7;
-   public static final int VERSIONED_METHOD_ID = 42;
-
-   private static final Log log = LogFactory.getLog(RemoveDataCommand.class);
-   private static boolean trace = log.isTraceEnabled();
-
-   /* parameters*/
-   private boolean createUndoops;
-   private boolean sendNodeEvent;
-   private boolean eviction;
-   private HashMap originalData;
-
-   public RemoveDataCommand(GlobalTransaction gtx, Fqn fqn, boolean createUndoops, boolean sendNodeEvent, boolean eviction)
-   {
-      this.globalTransaction = gtx;
-      this.fqn = fqn;
-      this.createUndoops = createUndoops;
-      this.sendNodeEvent = sendNodeEvent;
-      this.eviction = eviction;
-   }
-
-   public RemoveDataCommand()
-   {
-   }
-
-   /**
-    * Clears the data map in the node referenced by the specified Fqn.
-    *
-    * @param ctx invocation context
-    * @return null
-    */
-   public Object perform(InvocationContext ctx)
-   {
-      if (trace) log.trace("perform(" + globalTransaction + ", \"" + fqn + "\")");
-      NodeSPI targetNode = dataContainer.peekVersioned(fqn, dataVersion);
-      if (targetNode == null)
-      {
-         log.warn("node " + fqn + " not found");
-         return null;
-      }
-
-      Map data = targetNode.getDataDirect();
-      prepareDataForRollback(data);
-
-      notifyBefore(data, ctx);
-
-      targetNode.clearDataDirect();
-      if (eviction) targetNode.setDataLoaded(false);
-
-      notifyAfter(data, ctx);
-
-      return null;
-   }
-
-   private void prepareDataForRollback(Map data)
-   {
-      if (globalTransaction != null && createUndoops && !eviction && !data.isEmpty())
-      {
-         originalData = new HashMap(data);
-      }
-   }
-
-   private void notifyAfter(Map data, InvocationContext ctx)
-   {
-      if (sendNodeEvent)
-      {
-         notifier.notifyNodeVisited(fqn, false, ctx);
-      }
-      else
-      {
-         if (eviction)
-         {
-            notifier.notifyNodeEvicted(fqn, false, ctx);
-         }
-         else
-         {
-            notifier.notifyNodeModified(fqn, false, NodeModifiedEvent.ModificationType.REMOVE_DATA, data, ctx);
-         }
-      }
-   }
-
-   private void notifyBefore(Map data, InvocationContext ctx)
-   {
-      if (eviction)
-      {
-         notifier.notifyNodeEvicted(fqn, true, ctx);
-      }
-      else
-      {
-         notifier.notifyNodeModified(fqn, true, NodeModifiedEvent.ModificationType.REMOVE_DATA, data, ctx);
-      }
-   }
-
-   public void rollback()
-   {
-      if (trace) log.trace("rollback(" + globalTransaction + ", \"" + fqn + "\", " + originalData + ")");
-      boolean isRollback = true;
-      NodeSPI nodeSPI = dataContainer.peekStrict(globalTransaction, fqn, isRollback);
-      nodeSPI.putAllDirect(originalData);
-   }
-
-   public Object acceptVisitor(InvocationContext ctx, Visitor visitor) throws Throwable
-   {
-      return visitor.visitRemoveDataCommand(ctx, this);
-   }
-
-   public boolean isEviction()
-   {
-      return eviction;
-   }
-
-   public boolean isSendNodeEvent()
-   {
-      return sendNodeEvent;
-   }
-
-   public boolean isCreateUndoops()
-   {
-      return createUndoops;
-   }
-
-   public int getCommandId()
-   {
-      return isVersioned() ? VERSIONED_METHOD_ID : METHOD_ID;
-   }
-
-   @Override
-   public Object[] getParameters()
-   {
-      if (isVersioned())
-         return new Object[]{globalTransaction, fqn, createUndoops, dataVersion};
-      else
-         return new Object[]{globalTransaction, fqn, createUndoops};
-   }
-
-   @Override
-   public void setParameters(int commandId, Object[] args)
-   {
-      globalTransaction = (GlobalTransaction) args[0];
-      fqn = (Fqn) args[1];
-      createUndoops = (Boolean) args[2];
-      if (isVersionedId(commandId)) dataVersion = (DataVersion) args[3];
-   }
-
-   @Override
-   public boolean equals(Object o)
-   {
-      if (this == o) return true;
-      if (o == null || getClass() != o.getClass()) return false;
-      if (!super.equals(o)) return false;
-
-      RemoveDataCommand that = (RemoveDataCommand) o;
-
-      if (createUndoops != that.createUndoops) return false;
-      if (eviction != that.eviction) return false;
-      if (sendNodeEvent != that.sendNodeEvent) return false;
-      if (globalTransaction != null ? !globalTransaction.equals(that.globalTransaction) : that.globalTransaction != null)
-         return false;
-
-      return true;
-   }
-
-   @Override
-   public int hashCode()
-   {
-      int result = super.hashCode();
-      result = 31 * result + (globalTransaction != null ? globalTransaction.hashCode() : 0);
-      result = 31 * result + (createUndoops ? 1 : 0);
-      result = 31 * result + (sendNodeEvent ? 1 : 0);
-      result = 31 * result + (eviction ? 1 : 0);
-      return result;
-   }
-
-   @Override
-   protected boolean isVersionedId(int id)
-   {
-      return id == VERSIONED_METHOD_ID;
-   }
-
-   @Override
-   public String toString()
-   {
-      return "RemoveDataCommand{" +
-            "fqn=" + fqn +
-            ", dataVersion=" + dataVersion +
-            ", globalTransaction=" + globalTransaction +
-            ", createUndoops=" + createUndoops +
-            ", sendNodeEvent=" + sendNodeEvent +
-            ", eviction=" + eviction +
-            ", originalData=" + originalData +
-            '}';
-   }
-}

Modified: core/trunk/src/main/java/org/jboss/cache/commands/write/RemoveKeyCommand.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/commands/write/RemoveKeyCommand.java	2008-05-20 16:34:22 UTC (rev 5878)
+++ core/trunk/src/main/java/org/jboss/cache/commands/write/RemoveKeyCommand.java	2008-05-20 22:02:19 UTC (rev 5879)
@@ -29,15 +29,15 @@
 
    /* parameters */
    private Object key;
-   private boolean createUndoOps;
+
+   /* internally used for rollback */
    private Object oldValue;
 
-   public RemoveKeyCommand(GlobalTransaction gtx, Fqn fqn, Object key, boolean createUndoOps)
+   public RemoveKeyCommand(GlobalTransaction gtx, Fqn fqn, Object key)
    {
       this.globalTransaction = gtx;
       this.fqn = fqn;
       this.key = key;
-      this.createUndoOps = createUndoOps;
    }
 
    public RemoveKeyCommand()
@@ -54,7 +54,7 @@
    {
       if (trace) log.trace("perform(" + globalTransaction + ", \"" + fqn + "\", key=" + key + ")");
 
-      NodeSPI n = dataContainer.peek(fqn);
+      NodeSPI n = dataContainer.peek(fqn, false, false);
       if (n == null)
       {
          if (log.isDebugEnabled()) log.debug("node " + fqn + " not found");
@@ -85,11 +85,6 @@
       return key;
    }
 
-   public boolean isCreateUndoOps()
-   {
-      return createUndoOps;
-   }
-
    public void setKey(Object key)
    {
       this.key = key;
@@ -104,9 +99,9 @@
    public Object[] getParameters()
    {
       if (isVersioned())
-         return new Object[]{globalTransaction, fqn, key, createUndoOps, dataVersion};
+         return new Object[]{globalTransaction, fqn, key, true, dataVersion};
       else
-         return new Object[]{globalTransaction, fqn, key, createUndoOps};
+         return new Object[]{globalTransaction, fqn, key, true};
    }
 
    @Override
@@ -115,7 +110,6 @@
       globalTransaction = (GlobalTransaction) args[0];
       fqn = (Fqn) args[1];
       key = args[2];
-      createUndoOps = (Boolean) args[3];
       if (isVersionedId(commandId)) dataVersion = (DataVersion) args[4];
    }
 
@@ -128,7 +122,6 @@
 
       RemoveKeyCommand that = (RemoveKeyCommand) o;
 
-      if (createUndoOps != that.createUndoOps) return false;
       if (globalTransaction != null ? !globalTransaction.equals(that.globalTransaction) : that.globalTransaction != null)
          return false;
       if (key != null ? !key.equals(that.key) : that.key != null) return false;
@@ -142,7 +135,6 @@
       int result = super.hashCode();
       result = 31 * result + (globalTransaction != null ? globalTransaction.hashCode() : 0);
       result = 31 * result + (key != null ? key.hashCode() : 0);
-      result = 31 * result + (createUndoOps ? 1 : 0);
       return result;
    }
 
@@ -160,7 +152,6 @@
             ", dataVersion=" + dataVersion +
             ", globalTransaction=" + globalTransaction +
             ", key=" + key +
-            ", createUndoOps=" + createUndoOps +
             ", oldValue=" + oldValue +
             '}';
    }

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-20 16:34:22 UTC (rev 5878)
+++ core/trunk/src/main/java/org/jboss/cache/factories/CommandsFactory.java	2008-05-20 22:02:19 UTC (rev 5879)
@@ -158,9 +158,9 @@
       return command;
    }
 
-   public RemoveDataCommand buildRemoveDataCommand(GlobalTransaction gtx, Fqn fqn, boolean createUndoops, boolean sendNodeEvent, boolean eviction)
+   public ClearDataCommand buildClearDataCommand(GlobalTransaction gtx, Fqn fqn)
    {
-      RemoveDataCommand command = new RemoveDataCommand(gtx, fqn, createUndoops, sendNodeEvent, eviction);
+      ClearDataCommand command = new ClearDataCommand(gtx, fqn);
       command.initialize(notifier, dataContainer);
       return command;
    }
@@ -174,15 +174,24 @@
 
    public InvalidateCommand buildInvalidateCommand(Fqn fqn)
    {
-      InvalidateCommand command = new InvalidateCommand(fqn);
-      command.initialize(notifier, dataContainer);
-      command.initialize(txManager, cacheSpi, configuration.isNodeLockingOptimistic());
-      return command;
+      if (configuration.isNodeLockingOptimistic())
+      {
+         OptimisticInvalidateCommand command = new OptimisticInvalidateCommand(fqn);
+         command.initialize(txManager);
+         command.initialize(cacheSpi, dataContainer, notifier);
+         return command;
+      }
+      else
+      {
+         InvalidateCommand command = new InvalidateCommand(fqn);
+         command.initialize(cacheSpi, dataContainer, notifier);
+         return command;
+      }
    }
 
-   public RemoveKeyCommand buildRemoveKeyCommand(GlobalTransaction tx, Fqn<?> fqn, Object key, boolean b)
+   public RemoveKeyCommand buildRemoveKeyCommand(GlobalTransaction tx, Fqn<?> fqn, Object key)
    {
-      RemoveKeyCommand command = new RemoveKeyCommand(tx, fqn, key, b);
+      RemoveKeyCommand command = new RemoveKeyCommand(tx, fqn, key);
       command.initialize(notifier, dataContainer);
       return command;
    }
@@ -375,10 +384,10 @@
             command = returnValue;
             break;
          }
-         case RemoveDataCommand.METHOD_ID:
-         case RemoveDataCommand.VERSIONED_METHOD_ID:
+         case ClearDataCommand.METHOD_ID:
+         case ClearDataCommand.VERSIONED_METHOD_ID:
          {
-            RemoveDataCommand returnValue = new RemoveDataCommand();
+            ClearDataCommand returnValue = new ClearDataCommand();
             returnValue.initialize(notifier, dataContainer);
             command = returnValue;
             break;
@@ -445,10 +454,19 @@
 
          case InvalidateCommand.METHOD_ID:
          {
-            InvalidateCommand returnValue = new InvalidateCommand();
-            returnValue.initialize(txManager, cacheSpi, configuration.isNodeLockingOptimistic());
-            returnValue.initialize(notifier, dataContainer);
-            command = returnValue;
+            if (configuration.isNodeLockingOptimistic())
+            {
+               OptimisticInvalidateCommand returnValue = new OptimisticInvalidateCommand();
+               returnValue.initialize(txManager);
+               returnValue.initialize(cacheSpi, dataContainer, notifier);
+               command = returnValue;
+            }
+            else
+            {
+               InvalidateCommand returnValue = new InvalidateCommand();
+               returnValue.initialize(cacheSpi, dataContainer, notifier);
+               command = returnValue;
+            }
             break;
          }
 

Modified: core/trunk/src/main/java/org/jboss/cache/interceptors/ActivationInterceptor.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/interceptors/ActivationInterceptor.java	2008-05-20 16:34:22 UTC (rev 5878)
+++ core/trunk/src/main/java/org/jboss/cache/interceptors/ActivationInterceptor.java	2008-05-20 22:02:19 UTC (rev 5879)
@@ -11,13 +11,8 @@
 import org.jboss.cache.commands.read.GetNodeCommand;
 import org.jboss.cache.commands.tx.OptimisticPrepareCommand;
 import org.jboss.cache.commands.tx.PrepareCommand;
-import org.jboss.cache.commands.write.MoveCommand;
-import org.jboss.cache.commands.write.PutDataMapCommand;
-import org.jboss.cache.commands.write.PutForExternalReadCommand;
-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.ClearDataCommand;
+import org.jboss.cache.commands.write.*;
 import org.jboss.cache.factories.annotations.Inject;
 import org.jboss.cache.factories.annotations.Start;
 import org.jboss.cache.transaction.GlobalTransaction;
@@ -73,9 +68,9 @@
    }
 
    @Override
-   public Object visitRemoveDataCommand(InvocationContext ctx, RemoveDataCommand command) throws Throwable
+   public Object visitClearDataCommand(InvocationContext ctx, ClearDataCommand command) throws Throwable
    {
-      Object returnValue = super.visitRemoveDataCommand(ctx, command);
+      Object returnValue = super.visitClearDataCommand(ctx, command);
       if (trace)
          log.trace("This is a remove data operation; removing the data from the loader, no activation processing needed.");
       loader.removeData(command.getFqn());

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-20 16:34:22 UTC (rev 5878)
+++ core/trunk/src/main/java/org/jboss/cache/interceptors/CacheLoaderInterceptor.java	2008-05-20 22:02:19 UTC (rev 5879)
@@ -16,7 +16,7 @@
 import org.jboss.cache.commands.write.PutDataMapCommand;
 import org.jboss.cache.commands.write.PutForExternalReadCommand;
 import org.jboss.cache.commands.write.PutKeyValueCommand;
-import org.jboss.cache.commands.write.RemoveDataCommand;
+import org.jboss.cache.commands.write.ClearDataCommand;
 import org.jboss.cache.commands.write.RemoveKeyCommand;
 import org.jboss.cache.commands.write.RemoveNodeCommand;
 import org.jboss.cache.config.Configuration;
@@ -230,7 +230,7 @@
    }
 
    @Override
-   public Object visitRemoveDataCommand(InvocationContext ctx, RemoveDataCommand command) throws Throwable
+   public Object visitClearDataCommand(InvocationContext ctx, ClearDataCommand command) throws Throwable
    {
       Fqn fqn = command.getFqn();
       if (fqn != null && !useCacheStore)

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-20 16:34:22 UTC (rev 5878)
+++ core/trunk/src/main/java/org/jboss/cache/interceptors/CacheStoreInterceptor.java	2008-05-20 22:02:19 UTC (rev 5879)
@@ -13,13 +13,8 @@
 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.PutForExternalReadCommand;
-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.ClearDataCommand;
+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;
@@ -214,7 +209,7 @@
    }
 
    @Override
-   protected Object handleRemoveDataCommand(InvocationContext ctx, RemoveDataCommand command) throws Throwable
+   protected Object handleRemoveDataCommand(InvocationContext ctx, ClearDataCommand command) throws Throwable
    {
       if (!inTransaction())
       {
@@ -424,7 +419,7 @@
       }
 
       @Override
-      public Object visitRemoveDataCommand(InvocationContext ctx, RemoveDataCommand command) throws Throwable
+      public Object visitClearDataCommand(InvocationContext ctx, ClearDataCommand command) throws Throwable
       {
          modifications.add(new Modification(Modification.ModificationType.REMOVE_DATA, command.getFqn()));
          affectedFqns.add(command.getFqn());

Modified: core/trunk/src/main/java/org/jboss/cache/interceptors/CallInterceptor.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/interceptors/CallInterceptor.java	2008-05-20 16:34:22 UTC (rev 5878)
+++ core/trunk/src/main/java/org/jboss/cache/interceptors/CallInterceptor.java	2008-05-20 22:02:19 UTC (rev 5879)
@@ -12,7 +12,7 @@
 import org.jboss.cache.commands.write.PutDataMapCommand;
 import org.jboss.cache.commands.write.PutForExternalReadCommand;
 import org.jboss.cache.commands.write.PutKeyValueCommand;
-import org.jboss.cache.commands.write.RemoveDataCommand;
+import org.jboss.cache.commands.write.ClearDataCommand;
 import org.jboss.cache.commands.write.RemoveKeyCommand;
 import org.jboss.cache.commands.write.RemoveNodeCommand;
 import org.jboss.cache.factories.annotations.Inject;
@@ -132,7 +132,7 @@
    }
 
    @Override
-   public Object visitRemoveDataCommand(InvocationContext ctx, RemoveDataCommand command) throws Throwable
+   public Object visitClearDataCommand(InvocationContext ctx, ClearDataCommand command) throws Throwable
    {
       return handleAlterCacheMethod(ctx, command);
    }

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-20 16:34:22 UTC (rev 5878)
+++ core/trunk/src/main/java/org/jboss/cache/interceptors/EvictionInterceptor.java	2008-05-20 22:02:19 UTC (rev 5879)
@@ -16,13 +16,8 @@
 import org.jboss.cache.commands.read.GetDataMapCommand;
 import org.jboss.cache.commands.read.GetKeyValueCommand;
 import org.jboss.cache.commands.read.GetNodeCommand;
-import org.jboss.cache.commands.write.EvictCommand;
-import org.jboss.cache.commands.write.PutDataMapCommand;
-import org.jboss.cache.commands.write.PutForExternalReadCommand;
-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.ClearDataCommand;
+import org.jboss.cache.commands.write.*;
 import org.jboss.cache.eviction.EvictedEventNode;
 import org.jboss.cache.eviction.NodeEventType;
 import org.jboss.cache.factories.annotations.Inject;
@@ -219,7 +214,7 @@
    }
 
    @Override
-   public Object visitRemoveDataCommand(InvocationContext ctx, RemoveDataCommand command) throws Throwable
+   public Object visitClearDataCommand(InvocationContext ctx, ClearDataCommand command) throws Throwable
    {
       Object retVal = invokeNextInterceptor(ctx, command);
       Region r;

Modified: core/trunk/src/main/java/org/jboss/cache/interceptors/InvalidationInterceptor.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/interceptors/InvalidationInterceptor.java	2008-05-20 16:34:22 UTC (rev 5878)
+++ core/trunk/src/main/java/org/jboss/cache/interceptors/InvalidationInterceptor.java	2008-05-20 22:02:19 UTC (rev 5879)
@@ -15,14 +15,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.InvalidateCommand;
-import org.jboss.cache.commands.write.MoveCommand;
-import org.jboss.cache.commands.write.PutDataMapCommand;
-import org.jboss.cache.commands.write.PutForExternalReadCommand;
-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.Option;
 import org.jboss.cache.factories.CommandsFactory;
 import org.jboss.cache.factories.annotations.Inject;
@@ -117,7 +110,7 @@
    }
 
    @Override
-   public Object visitRemoveDataCommand(InvocationContext ctx, RemoveDataCommand command) throws Throwable
+   public Object visitClearDataCommand(InvocationContext ctx, ClearDataCommand command) throws Throwable
    {
       return handleWriteMethod(ctx, command.getFqn(), null, command);
    }
@@ -320,7 +313,7 @@
       }
 
       @Override
-      public Object visitRemoveDataCommand(InvocationContext ctx, RemoveDataCommand command) throws Throwable
+      public Object visitClearDataCommand(InvocationContext ctx, ClearDataCommand command) throws Throwable
       {
          result.add(command.getFqn());
          return null;
@@ -371,11 +364,12 @@
       {
          // increment invalidations counter if statistics maintained
          incrementInvalidations();
-         InvalidateCommand call = commandsFactory.buildInvalidateCommand(fqn);
-         call.setDataVersion(getNodeVersion(workspace, fqn));
-         if (log.isDebugEnabled()) log.debug("Cache [" + rpcManager.getLocalAddress() + "] replicating " + call);
+         InvalidateCommand command = commandsFactory.buildInvalidateCommand(fqn);
+         DataVersion dataVersion = getNodeVersion(workspace, fqn);
+         if (dataVersion != null) ((OptimisticInvalidateCommand) command).setDataVersion(dataVersion);
+         if (log.isDebugEnabled()) log.debug("Cache [" + rpcManager.getLocalAddress() + "] replicating " + command);
          // voila, invalidated!
-         replicateCall(ctx, call, synchronous, ctx.getOptionOverrides());
+         replicateCall(ctx, command, synchronous, ctx.getOptionOverrides());
       }
    }
 

Modified: core/trunk/src/main/java/org/jboss/cache/interceptors/InvocationContextInterceptor.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/interceptors/InvocationContextInterceptor.java	2008-05-20 16:34:22 UTC (rev 5878)
+++ core/trunk/src/main/java/org/jboss/cache/interceptors/InvocationContextInterceptor.java	2008-05-20 22:02:19 UTC (rev 5879)
@@ -16,7 +16,7 @@
 import org.jboss.cache.commands.write.PutDataMapCommand;
 import org.jboss.cache.commands.write.PutForExternalReadCommand;
 import org.jboss.cache.commands.write.PutKeyValueCommand;
-import org.jboss.cache.commands.write.RemoveDataCommand;
+import org.jboss.cache.commands.write.ClearDataCommand;
 import org.jboss.cache.commands.write.RemoveKeyCommand;
 import org.jboss.cache.commands.write.RemoveNodeCommand;
 import org.jboss.cache.config.Option;
@@ -67,7 +67,7 @@
    }
 
    @Override
-   public Object visitRemoveDataCommand(InvocationContext ctx, RemoveDataCommand command) throws Throwable
+   public Object visitClearDataCommand(InvocationContext ctx, ClearDataCommand command) throws Throwable
    {
       return handleAll(ctx, command, command.getGlobalTransaction(), false);
    }

Modified: core/trunk/src/main/java/org/jboss/cache/interceptors/MarshalledValueInterceptor.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/interceptors/MarshalledValueInterceptor.java	2008-05-20 16:34:22 UTC (rev 5878)
+++ core/trunk/src/main/java/org/jboss/cache/interceptors/MarshalledValueInterceptor.java	2008-05-20 22:02:19 UTC (rev 5879)
@@ -7,11 +7,8 @@
 import org.jboss.cache.commands.read.GetKeyValueCommand;
 import org.jboss.cache.commands.read.GetKeysCommand;
 import org.jboss.cache.commands.read.GetNodeCommand;
-import org.jboss.cache.commands.write.PutDataMapCommand;
-import org.jboss.cache.commands.write.PutForExternalReadCommand;
-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.ClearDataCommand;
+import org.jboss.cache.commands.write.*;
 import org.jboss.cache.interceptors.base.CommandInterceptor;
 import org.jboss.cache.marshall.MarshalledValue;
 import org.jboss.cache.marshall.MarshalledValueHelper;
@@ -96,7 +93,7 @@
    }
 
    @Override
-   public Object visitRemoveDataCommand(InvocationContext ctx, RemoveDataCommand command) throws Throwable
+   public Object visitClearDataCommand(InvocationContext ctx, ClearDataCommand command) throws Throwable
    {
       Object retVal = invokeNextInterceptor(ctx, command);
       return processRetVal(retVal);

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-20 16:34:22 UTC (rev 5878)
+++ core/trunk/src/main/java/org/jboss/cache/interceptors/OptimisticNodeInterceptor.java	2008-05-20 22:02:19 UTC (rev 5879)
@@ -24,7 +24,7 @@
 import org.jboss.cache.commands.write.PutDataMapCommand;
 import org.jboss.cache.commands.write.PutForExternalReadCommand;
 import org.jboss.cache.commands.write.PutKeyValueCommand;
-import org.jboss.cache.commands.write.RemoveDataCommand;
+import org.jboss.cache.commands.write.ClearDataCommand;
 import org.jboss.cache.commands.write.RemoveKeyCommand;
 import org.jboss.cache.commands.write.RemoveNodeCommand;
 import org.jboss.cache.config.Option;
@@ -179,7 +179,7 @@
    }
 
    @Override
-   public Object visitRemoveDataCommand(InvocationContext ctx, RemoveDataCommand command) throws Throwable
+   public Object visitClearDataCommand(InvocationContext ctx, ClearDataCommand command) throws Throwable
    {
       TransactionWorkspace workspace = getTransactionWorkspace(ctx);
       WorkspaceNode workspaceNode = fetchWorkspaceNode(ctx, command.getFqn(), workspace, true, true);

Modified: core/trunk/src/main/java/org/jboss/cache/interceptors/OptimisticReplicationInterceptor.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/interceptors/OptimisticReplicationInterceptor.java	2008-05-20 16:34:22 UTC (rev 5878)
+++ core/trunk/src/main/java/org/jboss/cache/interceptors/OptimisticReplicationInterceptor.java	2008-05-20 22:02:19 UTC (rev 5879)
@@ -19,12 +19,11 @@
 import org.jboss.cache.commands.tx.OptimisticPrepareCommand;
 import org.jboss.cache.commands.tx.RollbackCommand;
 import org.jboss.cache.commands.write.CreateNodeCommand;
-import org.jboss.cache.commands.write.EvictCommand;
 import org.jboss.cache.commands.write.MoveCommand;
 import org.jboss.cache.commands.write.PutDataMapCommand;
 import org.jboss.cache.commands.write.PutForExternalReadCommand;
 import org.jboss.cache.commands.write.PutKeyValueCommand;
-import org.jboss.cache.commands.write.RemoveDataCommand;
+import org.jboss.cache.commands.write.ClearDataCommand;
 import org.jboss.cache.commands.write.RemoveKeyCommand;
 import org.jboss.cache.commands.write.RemoveNodeCommand;
 import org.jboss.cache.factories.CommandsFactory;
@@ -279,14 +278,6 @@
       }
 
       @Override
-      public Object visitEvictFqnCommand(InvocationContext ctx, EvictCommand command) throws Throwable
-      {
-         VersionedDataCommand clone = commandsFactory.buildEvictFqnCommand(command.getFqn());
-         setDataVersion(clone, command.getFqn());
-         return null;
-      }
-
-      @Override
       public Object visitPutDataMapCommand(InvocationContext ctx, PutDataMapCommand command) throws Throwable
       {
          VersionedDataCommand clone = commandsFactory.buildPutDataMapCommand(null, command.getFqn(), command.getData(), command.isCreateUndoOps(), command.isEraseContents());
@@ -322,16 +313,16 @@
       @Override
       public Object visitRemoveKeyCommand(InvocationContext ctx, RemoveKeyCommand command) throws Throwable
       {
-         VersionedDataCommand clone = commandsFactory.buildRemoveKeyCommand(null, command.getFqn(), command.getKey(), command.isCreateUndoOps());
+         VersionedDataCommand clone = commandsFactory.buildRemoveKeyCommand(null, command.getFqn(), command.getKey());
          setDataVersion(clone, command.getFqn());
          return null;
       }
 
       @Override
-      public Object visitRemoveDataCommand(InvocationContext ctx, RemoveDataCommand command) throws Throwable
+      public Object visitClearDataCommand(InvocationContext ctx, ClearDataCommand command) throws Throwable
       {
-         VersionedDataCommand clone = commandsFactory.buildRemoveDataCommand(command.getGlobalTransaction(), command.getFqn(), command.isCreateUndoops(),
-               command.isSendNodeEvent(), command.isEviction());
+         VersionedDataCommand clone = commandsFactory.buildClearDataCommand(command.getGlobalTransaction(), command.getFqn()
+         );
          setDataVersion(clone, command.getFqn());
          return null;
       }

Modified: core/trunk/src/main/java/org/jboss/cache/interceptors/OptimisticTxInterceptor.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/interceptors/OptimisticTxInterceptor.java	2008-05-20 16:34:22 UTC (rev 5878)
+++ core/trunk/src/main/java/org/jboss/cache/interceptors/OptimisticTxInterceptor.java	2008-05-20 22:02:19 UTC (rev 5879)
@@ -6,11 +6,8 @@
 import org.jboss.cache.commands.VisitableCommand;
 import org.jboss.cache.commands.tx.OptimisticPrepareCommand;
 import org.jboss.cache.commands.tx.PrepareCommand;
-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.ClearDataCommand;
+import org.jboss.cache.commands.write.*;
 import org.jboss.cache.config.Option;
 import org.jboss.cache.transaction.GlobalTransaction;
 import org.jboss.cache.transaction.OptimisticTransactionEntry;
@@ -185,7 +182,7 @@
       }
 
       @Override
-      public Object visitRemoveDataCommand(InvocationContext ctx, RemoveDataCommand command) throws Throwable
+      public Object visitClearDataCommand(InvocationContext ctx, ClearDataCommand command) throws Throwable
       {
          return handleDataVersionCommand(ctx, command);
       }

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-20 16:34:22 UTC (rev 5878)
+++ core/trunk/src/main/java/org/jboss/cache/interceptors/PessimisticLockInterceptor.java	2008-05-20 22:02:19 UTC (rev 5879)
@@ -19,14 +19,8 @@
 import org.jboss.cache.commands.tx.CommitCommand;
 import org.jboss.cache.commands.tx.PrepareCommand;
 import org.jboss.cache.commands.tx.RollbackCommand;
-import org.jboss.cache.commands.write.EvictCommand;
-import org.jboss.cache.commands.write.MoveCommand;
-import org.jboss.cache.commands.write.PutDataMapCommand;
-import org.jboss.cache.commands.write.PutForExternalReadCommand;
-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.ClearDataCommand;
+import org.jboss.cache.commands.write.*;
 import org.jboss.cache.factories.annotations.Inject;
 import org.jboss.cache.factories.annotations.Start;
 import org.jboss.cache.interceptors.base.PostProcessingCommandInterceptor;
@@ -265,7 +259,7 @@
    }
 
    @Override
-   protected Object handleRemoveDataCommand(InvocationContext ctx, RemoveDataCommand command) throws Throwable
+   protected Object handleRemoveDataCommand(InvocationContext ctx, ClearDataCommand command) throws Throwable
    {
       lockManager.acquireLocksWithTimeout(ctx, command.getFqn(), NodeLock.LockType.WRITE, false, false, false, false, null, false);
       return invokeNextInterceptor(ctx, command);

Modified: core/trunk/src/main/java/org/jboss/cache/interceptors/ReplicationInterceptor.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/interceptors/ReplicationInterceptor.java	2008-05-20 16:34:22 UTC (rev 5878)
+++ core/trunk/src/main/java/org/jboss/cache/interceptors/ReplicationInterceptor.java	2008-05-20 22:02:19 UTC (rev 5879)
@@ -10,7 +10,7 @@
 import org.jboss.cache.commands.write.PutDataMapCommand;
 import org.jboss.cache.commands.write.PutForExternalReadCommand;
 import org.jboss.cache.commands.write.PutKeyValueCommand;
-import org.jboss.cache.commands.write.RemoveDataCommand;
+import org.jboss.cache.commands.write.ClearDataCommand;
 import org.jboss.cache.commands.write.RemoveKeyCommand;
 import org.jboss.cache.commands.write.RemoveNodeCommand;
 import org.jboss.cache.config.Configuration;
@@ -113,7 +113,7 @@
    }
 
    @Override
-   public Object visitRemoveDataCommand(InvocationContext ctx, RemoveDataCommand command) throws Throwable
+   public Object visitClearDataCommand(InvocationContext ctx, ClearDataCommand command) throws Throwable
    {
       return handleCrudMethod(ctx, command, false);
    }

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-20 16:34:22 UTC (rev 5878)
+++ core/trunk/src/main/java/org/jboss/cache/interceptors/TxInterceptor.java	2008-05-20 22:02:19 UTC (rev 5879)
@@ -18,13 +18,8 @@
 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.CreateNodeCommand;
-import org.jboss.cache.commands.write.InvalidateCommand;
-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.ClearDataCommand;
+import org.jboss.cache.commands.write.*;
 import org.jboss.cache.config.Option;
 import org.jboss.cache.factories.CommandsFactory;
 import org.jboss.cache.factories.ComponentRegistry;
@@ -809,7 +804,7 @@
          }
 
          @Override
-         public Object visitRemoveDataCommand(InvocationContext ctx, RemoveDataCommand command) throws Throwable
+         public Object visitClearDataCommand(InvocationContext ctx, ClearDataCommand command) throws Throwable
          {
             command.setGlobalTransaction(gtx);
             return null;

Modified: core/trunk/src/main/java/org/jboss/cache/interceptors/base/PostProcessingCommandInterceptor.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/interceptors/base/PostProcessingCommandInterceptor.java	2008-05-20 16:34:22 UTC (rev 5878)
+++ core/trunk/src/main/java/org/jboss/cache/interceptors/base/PostProcessingCommandInterceptor.java	2008-05-20 22:02:19 UTC (rev 5879)
@@ -19,7 +19,7 @@
 import org.jboss.cache.commands.write.PutDataMapCommand;
 import org.jboss.cache.commands.write.PutForExternalReadCommand;
 import org.jboss.cache.commands.write.PutKeyValueCommand;
-import org.jboss.cache.commands.write.RemoveDataCommand;
+import org.jboss.cache.commands.write.ClearDataCommand;
 import org.jboss.cache.commands.write.RemoveKeyCommand;
 import org.jboss.cache.commands.write.RemoveNodeCommand;
 
@@ -113,7 +113,7 @@
    }
 
    @Override
-   public final Object visitRemoveDataCommand(InvocationContext ctx, RemoveDataCommand command) throws Throwable
+   public final Object visitClearDataCommand(InvocationContext ctx, ClearDataCommand command) throws Throwable
    {
       try
       {
@@ -125,7 +125,7 @@
       }
    }
 
-   protected Object handleRemoveDataCommand(InvocationContext ctx, RemoveDataCommand command) throws Throwable
+   protected Object handleRemoveDataCommand(InvocationContext ctx, ClearDataCommand command) throws Throwable
    {
       return handleDefault(ctx, command);
    }

Modified: core/trunk/src/main/java/org/jboss/cache/interceptors/base/SkipCheckChainedInterceptor.java
===================================================================
--- core/trunk/src/main/java/org/jboss/cache/interceptors/base/SkipCheckChainedInterceptor.java	2008-05-20 16:34:22 UTC (rev 5878)
+++ core/trunk/src/main/java/org/jboss/cache/interceptors/base/SkipCheckChainedInterceptor.java	2008-05-20 22:02:19 UTC (rev 5879)
@@ -13,15 +13,8 @@
 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.EvictCommand;
-import org.jboss.cache.commands.write.InvalidateCommand;
-import org.jboss.cache.commands.write.MoveCommand;
-import org.jboss.cache.commands.write.PutDataMapCommand;
-import org.jboss.cache.commands.write.PutForExternalReadCommand;
-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.ClearDataCommand;
+import org.jboss.cache.commands.write.*;
 
 /**
  * This interceptor will call {@link #skipInterception(org.jboss.cache.InvocationContext,org.jboss.cache.commands.VisitableCommand)} before invoking each visit method
@@ -100,7 +93,7 @@
    }
 
    @Override
-   public final Object visitRemoveDataCommand(InvocationContext ctx, RemoveDataCommand command) throws Throwable
+   public final Object visitClearDataCommand(InvocationContext ctx, ClearDataCommand command) throws Throwable
    {
       if (skipInterception(ctx, command))
       {
@@ -109,7 +102,7 @@
       return handleRemoveDataCommand(ctx, command);
    }
 
-   protected Object handleRemoveDataCommand(InvocationContext ctx, RemoveDataCommand command) throws Throwable
+   protected Object handleRemoveDataCommand(InvocationContext ctx, ClearDataCommand command) throws Throwable
    {
       return handleAll(ctx, command);
    }

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-20 16:34:22 UTC (rev 5878)
+++ core/trunk/src/main/java/org/jboss/cache/invocation/CacheInvocationDelegate.java	2008-05-20 22:02:19 UTC (rev 5879)
@@ -419,7 +419,7 @@
       InvocationContext ctx = invocationContextContainer.get();
       cacheStatusCheck(ctx);
       GlobalTransaction tx = transactionTable.getCurrentTransaction();
-      RemoveKeyCommand command = commandsFactory.buildRemoveKeyCommand(tx, fqn, key, true);
+      RemoveKeyCommand command = commandsFactory.buildRemoveKeyCommand(tx, fqn, key);
       return (V) invoker.invoke(ctx, command);
    }
 
@@ -547,7 +547,7 @@
       InvocationContext ctx = invocationContextContainer.get();
       cacheStatusCheck(ctx);
       GlobalTransaction tx = getCurrentTransaction();
-      invoker.invoke(ctx, commandsFactory.buildRemoveDataCommand(tx, fqn, true, false, false));
+      invoker.invoke(ctx, commandsFactory.buildClearDataCommand(tx, fqn));
    }
 
    /**

Modified: core/trunk/src/test/java/org/jboss/cache/commands/read/AbstractDataCommandTest.java
===================================================================
--- core/trunk/src/test/java/org/jboss/cache/commands/read/AbstractDataCommandTest.java	2008-05-20 16:34:22 UTC (rev 5878)
+++ core/trunk/src/test/java/org/jboss/cache/commands/read/AbstractDataCommandTest.java	2008-05-20 22:02:19 UTC (rev 5879)
@@ -3,6 +3,7 @@
 import static org.easymock.EasyMock.createMock;
 import org.jboss.cache.DataContainer;
 import org.jboss.cache.Fqn;
+import org.jboss.cache.InvocationContext;
 import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
 
@@ -17,11 +18,13 @@
 {
    protected Fqn testFqn = Fqn.fromString("/testfqn");
    protected DataContainer containerMock;
+   protected InvocationContext ctx;
 
    @BeforeMethod
    final public void setUp()
    {
       containerMock = createMock(DataContainer.class);
+      ctx = new InvocationContext();
       moreSetup();
    }
 

Added: core/trunk/src/test/java/org/jboss/cache/commands/write/AbstractVersionedDataCommandTest.java
===================================================================
--- core/trunk/src/test/java/org/jboss/cache/commands/write/AbstractVersionedDataCommandTest.java	                        (rev 0)
+++ core/trunk/src/test/java/org/jboss/cache/commands/write/AbstractVersionedDataCommandTest.java	2008-05-20 22:02:19 UTC (rev 5879)
@@ -0,0 +1,50 @@
+package org.jboss.cache.commands.write;
+
+import static org.easymock.EasyMock.*;
+import org.jboss.cache.notifications.Notifier;
+import org.jboss.cache.DataContainer;
+import org.jboss.cache.Fqn;
+import org.jboss.cache.InvocationContext;
+import org.jboss.cache.transaction.GlobalTransaction;
+import org.jboss.cache.optimistic.DataVersion;
+import org.jboss.cache.optimistic.DefaultDataVersion;
+import org.jboss.cache.mock.MockNodesFixture;
+import org.easymock.IMocksControl;
+import org.testng.annotations.BeforeMethod;
+
+/**
+ * Base class for testing {@link AbstractVersionedDataCommand}.
+ *
+ * @author Mircea.Markus at jboss.com
+ * @since 2.2
+ */
+public abstract class AbstractVersionedDataCommandTest
+{
+   Notifier notifier;
+   DataContainer container;
+   IMocksControl control;
+
+   MockNodesFixture nodes;
+   DataVersion dataVersion;
+   GlobalTransaction globalTransaction;
+   Fqn fqn = Fqn.fromString("/test/fqn");
+   InvocationContext ctx;
+   
+
+   @BeforeMethod
+   public final void setUp() 
+   {
+      control = createStrictControl();
+      container = control.createMock(DataContainer.class);
+      notifier = control.createMock(Notifier.class);
+      nodes = new MockNodesFixture();
+      globalTransaction = new GlobalTransaction();
+      dataVersion = new DefaultDataVersion(10);
+      ctx = new InvocationContext();
+
+      AbstractVersionedDataCommand command = moreSetUp();
+      command.initialize(notifier, container);
+   }
+
+   public abstract AbstractVersionedDataCommand moreSetUp();
+}

Added: core/trunk/src/test/java/org/jboss/cache/commands/write/ClearDataCommandTest.java
===================================================================
--- core/trunk/src/test/java/org/jboss/cache/commands/write/ClearDataCommandTest.java	                        (rev 0)
+++ core/trunk/src/test/java/org/jboss/cache/commands/write/ClearDataCommandTest.java	2008-05-20 22:02:19 UTC (rev 5879)
@@ -0,0 +1,55 @@
+package org.jboss.cache.commands.write;
+
+import static org.easymock.EasyMock.*;
+import org.testng.annotations.Test;
+import org.jboss.cache.notifications.event.NodeModifiedEvent;
+
+import java.util.Collections;
+
+/**
+ * tester class for {@link ClearDataCommand}.
+ *
+ * @author Mircea.Markus at jboss.com
+ * @since 2.2
+ */
+ at Test (groups = "unit")
+public class ClearDataCommandTest extends AbstractVersionedDataCommandTest
+{
+
+   ClearDataCommand command;
+
+   public AbstractVersionedDataCommand moreSetUp()
+   {
+      command = new ClearDataCommand(globalTransaction, fqn);
+      command.setDataVersion(dataVersion);
+      return command;
+   }
+
+   public void testNonexistentNode()
+   {
+      expect(container.peekVersioned(fqn, dataVersion)).andReturn(null);
+      control.replay();
+      assert null == command.perform(ctx);
+      control.verify();
+   }
+
+   public void testExistentData()
+   {
+      nodes.adfgNode.put("key", "value");
+      expect(container.peekVersioned(fqn, dataVersion)).andReturn(nodes.adfgNode);
+      notifier.notifyNodeModified(fqn, true, NodeModifiedEvent.ModificationType.REMOVE_DATA, nodes.adfgNode.getDataDirect(), ctx);
+      notifier.notifyNodeModified(fqn, false, NodeModifiedEvent.ModificationType.REMOVE_DATA, Collections.EMPTY_MAP, ctx);
+      control.replay();
+      assert null == command.perform(ctx);
+      assert nodes.adfgNode.getData().isEmpty();
+      control.verify();
+
+      //now do a rollback
+      control.reset();
+      expect(container.peekStrict(globalTransaction, fqn, true)).andReturn(nodes.aNode);
+      control.replay();
+      command.rollback();
+      assert nodes.aNode.dataSize() == 1;
+      assert nodes.aNode.getData().get("key").equals("value");
+   }
+}

Added: core/trunk/src/test/java/org/jboss/cache/commands/write/CreateNodeCommandTest.java
===================================================================
--- core/trunk/src/test/java/org/jboss/cache/commands/write/CreateNodeCommandTest.java	                        (rev 0)
+++ core/trunk/src/test/java/org/jboss/cache/commands/write/CreateNodeCommandTest.java	2008-05-20 22:02:19 UTC (rev 5879)
@@ -0,0 +1,75 @@
+package org.jboss.cache.commands.write;
+
+import static org.easymock.EasyMock.*;
+
+import org.testng.annotations.Test;
+import org.testng.annotations.BeforeMethod;
+import org.jboss.cache.commands.read.AbstractDataCommandTest;
+import org.jboss.cache.mock.MockNodesFixture;
+
+import java.util.ArrayList;
+
+/**
+ * Tester class for {@link CreateNodeCommand}
+ *
+ * @author Mircea.Markus at jboss.com
+ * @since 2.2
+ */
+ at Test(groups = "unit")
+public class CreateNodeCommandTest extends AbstractDataCommandTest
+{
+   CreateNodeCommand command;
+   private Object[] result;
+   private ArrayList createdNodes;
+
+   protected void moreSetup()
+   {
+      command = new CreateNodeCommand(testFqn);
+      command.initialize(containerMock);
+      createdNodes = new ArrayList();
+      result = new Object[2];
+      result[0] = this.createdNodes;
+   }
+
+   public void testPerformNoNodesCreated()
+   {
+      expect(containerMock.createNodes(testFqn)).andReturn(result);
+      replay(containerMock);
+      assert null == command.perform(ctx);
+      assert command.getNewlyCreated().isEmpty();
+   }
+
+   public void testPerformWithCreatedNodes()
+   {
+      MockNodesFixture nodes = new MockNodesFixture();
+      createdNodes.add(nodes.aNode);
+      createdNodes.add(nodes.abNode);
+      createdNodes.add(nodes.abcNode);
+      result[1] = nodes.abcNode;
+
+      expect(containerMock.createNodes(testFqn)).andReturn(result);
+      replay(containerMock);
+      assert nodes.abcNode == command.perform(ctx);
+      assert command.getNewlyCreated().size() == 3;
+      assert command.getNewlyCreated().contains(nodes.a);
+      assert command.getNewlyCreated().contains(nodes.ab);
+      assert command.getNewlyCreated().contains(nodes.abc);
+   }
+
+   public void testRollback()
+   {
+      MockNodesFixture nodes = new MockNodesFixture();
+      createdNodes.add(nodes.aNode);
+      createdNodes.add(nodes.abNode);
+      createdNodes.add(nodes.abcNode);
+      expect(containerMock.createNodes(testFqn)).andReturn(result);
+      expect(containerMock.removeFromDataStructure(nodes.a, true)).andReturn(Boolean.TRUE);
+      expect(containerMock.removeFromDataStructure(nodes.ab, true)).andReturn(Boolean.TRUE);
+      expect(containerMock.removeFromDataStructure(nodes.abc, true)).andReturn(Boolean.TRUE);
+      replay(containerMock);
+      command.perform(ctx);
+      command.rollback();
+      verify(containerMock);
+   }
+
+}

Added: core/trunk/src/test/java/org/jboss/cache/commands/write/EvictCommandTest.java
===================================================================
--- core/trunk/src/test/java/org/jboss/cache/commands/write/EvictCommandTest.java	                        (rev 0)
+++ core/trunk/src/test/java/org/jboss/cache/commands/write/EvictCommandTest.java	2008-05-20 22:02:19 UTC (rev 5879)
@@ -0,0 +1,83 @@
+package org.jboss.cache.commands.write;
+
+import static org.easymock.EasyMock.*;
+import org.easymock.IMocksControl;
+import org.testng.annotations.Test;
+import org.jboss.cache.commands.read.AbstractDataCommandTest;
+import org.jboss.cache.notifications.Notifier;
+import org.jboss.cache.mock.MockNodesFixture;
+import org.jboss.cache.DataContainer;
+import org.jboss.cache.Fqn;
+
+import java.util.List;
+import java.util.ArrayList;
+
+/**
+ * tester class for {@link EvictCommand}
+ *
+ * @author Mircea.Markus at jboss.com
+ * @since 2.2
+ */
+ at Test(groups = "unit")
+public class EvictCommandTest extends AbstractDataCommandTest
+{
+   EvictCommand command;
+   Notifier notifier;
+   IMocksControl control;
+   MockNodesFixture nodes;
+
+   protected void moreSetup()
+   {
+      control = createStrictControl();
+      notifier = control.createMock(Notifier.class);
+      containerMock = control.createMock(DataContainer.class);
+      command = new EvictCommand(testFqn);
+      command.initialize(notifier, containerMock);
+      nodes = new MockNodesFixture();
+   }
+
+   public void testResidentNodesEviction()
+   {
+      nodes.abNode.setResident(true);
+      expect(containerMock.peek(testFqn, false,false)).andReturn(nodes.abNode);
+      control.replay();
+      assert Boolean.TRUE == command.perform(ctx);
+      control.verify();
+   }
+
+   public void testSimpleEviction()
+   {
+      expect(containerMock.peek(testFqn, false,false)).andReturn(nodes.abNode);
+      notifier.notifyNodeEvicted(testFqn, true, ctx);
+      expect(containerMock.evict(testFqn)).andReturn(true);
+      notifier.notifyNodeEvicted(testFqn, false, ctx);
+      control.replay();
+      assert Boolean.TRUE == command.perform(ctx);
+      control.verify();
+   }
+
+   public void testRecursiveEviction()
+   {
+      List<Fqn> nodesToEvict = new ArrayList<Fqn>();
+      nodesToEvict.add(nodes.a);
+      nodesToEvict.add(nodes.ab);
+      command.setRecursive(true);
+      expect(containerMock.peek(testFqn, false,false)).andReturn(nodes.aNode);
+
+      expect(containerMock.getNodesForEviction(testFqn, true)).andReturn(nodesToEvict);
+      control.checkOrder(false);
+      //evict a
+      notifier.notifyNodeEvicted(nodes.a, true, ctx);
+      expect(containerMock.evict(nodes.a)).andReturn(true);
+      notifier.notifyNodeEvicted(nodes.a, false, ctx);
+
+      //evict b
+      notifier.notifyNodeEvicted(nodes.ab, true, ctx);
+      expect(containerMock.evict(nodes.ab)).andReturn(true);
+      notifier.notifyNodeEvicted(nodes.ab, false, ctx);
+
+      control.replay();
+      assert Boolean.TRUE == command.perform(ctx);
+      control.verify();
+   }
+}

Added: core/trunk/src/test/java/org/jboss/cache/commands/write/InvalidateCommandTest.java
===================================================================
--- core/trunk/src/test/java/org/jboss/cache/commands/write/InvalidateCommandTest.java	                        (rev 0)
+++ core/trunk/src/test/java/org/jboss/cache/commands/write/InvalidateCommandTest.java	2008-05-20 22:02:19 UTC (rev 5879)
@@ -0,0 +1,87 @@
+package org.jboss.cache.commands.write;
+
+import static org.easymock.EasyMock.*;
+import org.testng.annotations.Test;
+import org.jboss.cache.notifications.Notifier;
+import org.jboss.cache.mock.MockNodesFixture;
+import org.jboss.cache.DataContainer;
+import org.jboss.cache.CacheSPI;
+import org.jboss.cache.Fqn;
+import org.jboss.cache.commands.read.AbstractDataCommandTest;
+import org.easymock.IMocksControl;
+import static org.easymock.EasyMock.createStrictControl;
+
+import javax.transaction.TransactionManager;
+
+/**
+ * Tester class for {@link org.jboss.cache.commands.write.InvalidateCommand}
+ *
+ * @author Mircea.Markus at jboss.com
+ * @since 2.2
+ */
+ at Test(groups = "unit")
+public class InvalidateCommandTest extends AbstractDataCommandTest
+{
+   InvalidateCommand command;
+   Notifier notifier;
+   IMocksControl control;
+   MockNodesFixture nodes;
+   TransactionManager tmMock;
+   CacheSPI spiMock;
+
+   protected void moreSetup()
+   {
+      control = createStrictControl();
+      notifier = control.createMock(Notifier.class);
+      containerMock = control.createMock(DataContainer.class);
+      tmMock = control.createMock(TransactionManager.class);
+      spiMock = control.createMock(CacheSPI.class);
+
+      command = new InvalidateCommand(testFqn);
+      command.initialize(spiMock, containerMock, notifier);
+      nodes = new MockNodesFixture();
+   }
+
+   public void testNullNode()
+   {
+      expect(spiMock.getNode(testFqn)).andReturn(null);
+      control.replay();
+      assert null == command.perform(ctx);
+      control.verify();
+   }
+
+   public void testExistingNode()
+   {
+      expect(spiMock.getNode(testFqn)).andReturn(nodes.adfNode);
+      notifier.notifyNodeEvicted(testFqn, true, ctx);
+      expect(containerMock.evict(testFqn)).andReturn(Boolean.TRUE);
+      notifier.notifyNodeEvicted(testFqn, false, ctx);
+      control.replay();
+      assert null == command.perform(ctx);
+      assert !nodes.adfNode.isValid() : "node should had been invalidated";
+      assert !nodes.adfgNode.isValid() : "child should had been invalidated";
+      assert !nodes.adfhNode.isValid() : "child should had been invalidated";
+      control.verify();
+   }
+
+   public void testRootNodeInvalidation()
+   {
+      command.setFqn(Fqn.ROOT);
+      nodes.adfgNode.put("key","value");
+      expect(spiMock.getNode(Fqn.ROOT)).andReturn(nodes.root);
+      notifier.notifyNodeEvicted(Fqn.ROOT, true, ctx);
+      expect(containerMock.evict(Fqn.ROOT)).andReturn(Boolean.TRUE);
+      notifier.notifyNodeEvicted(Fqn.ROOT, false, ctx);
+      control.replay();
+      assert null == command.perform(ctx);
+      assert nodes.root.isValid() : "root should NOT had been invalidated";
+      assert !nodes.adfgNode.isValid() : "node should had been invalidated";
+      control.verify();
+   }
+
+   public void testInvalidateResidentNode()
+   {
+      nodes.adfNode.setResident(true);
+      testExistingNode();
+   }
+}

Added: core/trunk/src/test/java/org/jboss/cache/commands/write/OptimisticInvalidateCommandTest.java
===================================================================
--- core/trunk/src/test/java/org/jboss/cache/commands/write/OptimisticInvalidateCommandTest.java	                        (rev 0)
+++ core/trunk/src/test/java/org/jboss/cache/commands/write/OptimisticInvalidateCommandTest.java	2008-05-20 22:02:19 UTC (rev 5879)
@@ -0,0 +1,137 @@
+package org.jboss.cache.commands.write;
+
+import static org.easymock.EasyMock.*;
+import org.easymock.IMocksControl;
+import org.jboss.cache.CacheSPI;
+import org.jboss.cache.DataContainer;
+import org.jboss.cache.optimistic.DataVersion;
+import org.jboss.cache.optimistic.DefaultDataVersion;
+import org.jboss.cache.commands.read.AbstractDataCommandTest;
+import org.jboss.cache.mock.MockNodesFixture;
+import org.jboss.cache.notifications.Notifier;
+import org.testng.annotations.Test;
+
+import javax.transaction.TransactionManager;
+import javax.transaction.Transaction;
+import java.util.Collections;
+
+/**
+ * tester class for {@link OptimisticInvalidateCommand}.
+ *
+ * @author Mircea.Markus at jboss.com
+ * @since 2.2
+ */
+ at Test(groups = "unit")
+public class OptimisticInvalidateCommandTest extends AbstractDataCommandTest
+{
+   DataVersion dataVersion;
+   OptimisticInvalidateCommand command;
+   IMocksControl control;
+
+   Notifier notifier;
+   TransactionManager tmMock;
+
+   MockNodesFixture nodes;
+   CacheSPI spiMock;
+
+   protected void moreSetup()
+   {
+      control = createStrictControl();
+      notifier = control.createMock(Notifier.class);
+      containerMock = control.createMock(DataContainer.class);
+      tmMock = control.createMock(TransactionManager.class);
+      spiMock = control.createMock(CacheSPI.class);
+      nodes = new MockNodesFixture();
+
+      command = new OptimisticInvalidateCommand(testFqn);
+      dataVersion = new DefaultDataVersion(10);
+      command.setDataVersion(dataVersion);
+      command.initialize(spiMock, containerMock, notifier);
+      command.initialize(tmMock);
+   }
+
+   public void testWithExistingNode()
+   {
+      nodes.adfNode.put("key", "value");
+      nodes.adfNode.setDataLoaded(true);
+      expect(spiMock.getNode(testFqn)).andReturn(nodes.adfNode);
+      expect(containerMock.peekVersioned(testFqn, dataVersion)).andReturn(nodes.adfNode);
+      notifier.notifyNodeEvicted(testFqn, true, ctx);
+      notifier.notifyNodeEvicted(testFqn, false, ctx);
+      expect(containerMock.peek(testFqn, false, true)).andReturn(nodes.adfNode);
+
+      control.replay();
+      assert null == command.perform(ctx);
+      assert nodes.adfNode.getData().isEmpty();
+      assert !nodes.adfNode.isDataLoaded();
+      assert !nodes.adfNode.isValid();
+      assert nodes.adfNode.getVersion().equals(dataVersion);
+
+      control.verify();
+   }
+
+   public void testWithExistingNodeInvalidVersion()
+   {
+      nodes.adfNode.put("key", "value");
+      nodes.adfNode.setDataLoaded(true);
+      expect(spiMock.getNode(testFqn)).andReturn(nodes.adfNode);
+      expect(containerMock.peekVersioned(testFqn, dataVersion)).andThrow(new RuntimeException());
+      control.replay();
+
+      try
+      {
+         command.perform(ctx);
+         assert false : "exception expected";
+      } catch (Exception e)
+      {
+         //expected as there is a version mismatch
+      }
+      assert !nodes.adfNode.getData().isEmpty();
+      assert nodes.adfNode.isDataLoaded();
+      assert nodes.adfNode.isValid();
+      assert !dataVersion.equals(nodes.adfNode.getVersion());
+
+      control.verify();
+   }
+
+   public void testExistingTumbstone()
+   {
+      nodes.adfNode.setValid(false, true);
+      expect(spiMock.getNode(testFqn)).andReturn(null);
+      expect(containerMock.peek(testFqn, false, true)).andReturn(nodes.adfNode);
+      expect(containerMock.peekVersioned(testFqn, dataVersion)).andReturn(nodes.adfNode);
+      notifier.notifyNodeEvicted(testFqn, true, ctx);
+      notifier.notifyNodeEvicted(testFqn, false, ctx);
+      expect(containerMock.peek(testFqn, false, true)).andReturn(nodes.adfNode);
+
+      control.replay();
+      assert null == command.perform(ctx);
+      assert nodes.adfNode.getData().isEmpty();
+      assert !nodes.adfNode.isDataLoaded();
+      assert !nodes.adfNode.isValid();
+      assert nodes.adfNode.getVersion().equals(dataVersion);
+      control.verify();
+   }
+
+   public void testCreateTumbstone() throws Exception
+   {
+      Transaction tx = control.createMock(Transaction.class);
+      expect(tmMock.suspend()).andReturn(tx);
+      spiMock.put(testFqn, Collections.emptyMap());
+      tmMock.resume(tx);
+
+      control.replay();
+      command.createTombstone(ctx);
+      control.verify();
+   }
+
+   public void testCreateTumbstoneNoTx() throws Exception
+   {
+      expect(tmMock.suspend()).andReturn(null);
+      spiMock.put(testFqn, Collections.EMPTY_MAP);
+
+      control.replay();
+      command.createTombstone(ctx);
+      control.verify();
+   }
+}

Added: core/trunk/src/test/java/org/jboss/cache/commands/write/PutDataMapCommandTest.java
===================================================================
--- core/trunk/src/test/java/org/jboss/cache/commands/write/PutDataMapCommandTest.java	                        (rev 0)
+++ core/trunk/src/test/java/org/jboss/cache/commands/write/PutDataMapCommandTest.java	2008-05-20 22:02:19 UTC (rev 5879)
@@ -0,0 +1,103 @@
+package org.jboss.cache.commands.write;
+
+import static org.easymock.EasyMock.*;
+import org.easymock.IMocksControl;
+import org.jboss.cache.commands.read.AbstractDataCommandTest;
+import org.jboss.cache.transaction.GlobalTransaction;
+import org.jboss.cache.notifications.Notifier;
+import org.jboss.cache.notifications.event.NodeModifiedEvent;
+import org.jboss.cache.Fqn;
+import org.jboss.cache.DataContainer;
+import org.jboss.cache.NodeSPI;
+import org.jboss.cache.mock.NodeSpiMock;
+import org.testng.annotations.Test;
+import org.testng.annotations.BeforeMethod;
+
+import java.util.Map;
+import java.util.HashMap;
+import java.util.Collections;
+
+/**
+ * Tester class for {@link PutDataMapCommand}
+ *
+ * @author Mircea.Markus at jboss.com
+ * @since 2.2
+ */
+ at Test(groups = "unit")
+public class PutDataMapCommandTest
+{
+   Fqn testFqn = Fqn.fromString("/testfqn");
+   PutDataMapCommand command;
+
+   GlobalTransaction gtx;
+   Notifier notifier;
+   DataContainer container;
+   Map dataMap;
+   IMocksControl control;
+   NodeSpiMock node;
+
+
+   @BeforeMethod
+   protected void setUp()
+   {
+      gtx = new GlobalTransaction();
+      dataMap = new HashMap();
+      command = new PutDataMapCommand(gtx, testFqn, dataMap, true, false);
+      control = createStrictControl();
+      notifier = control.createMock(Notifier.class);
+      container = control.createMock(DataContainer.class);
+      command.initialize(notifier, container);
+      node = new NodeSpiMock(testFqn);
+      node.put("k","v");
+   }
+
+   public void testAddDataNoErase()
+   {
+      expect(container.peekStrict(gtx, testFqn, false)).andReturn(node);
+      dataMap.put("k2", "v2");
+      Map expected = new HashMap(dataMap);
+      expected.putAll(node.getDataDirect());
+      notifier.notifyNodeModified(testFqn, true, NodeModifiedEvent.ModificationType.PUT_MAP, node.getData(), null);
+      notifier.notifyNodeModified(testFqn, false, NodeModifiedEvent.ModificationType.PUT_MAP, expected, null);
+      
+      control.replay();
+      assert null == command.perform(null) : "null result is always expected";
+      assert command.getOldData().size() == 1;
+      assert command.getOldData().get("k").equals("v");
+      control.verify();
+   }
+   public void testAddDataWithErase()
+   {
+      command.setEraseContents(true);
+      expect(container.peekStrict(gtx, testFqn, false)).andReturn(node);
+      dataMap.put("k2", "v2");
+      Map expected = new HashMap(dataMap);
+      notifier.notifyNodeModified(testFqn, true, NodeModifiedEvent.ModificationType.PUT_MAP, node.getData(), null);
+      notifier.notifyNodeModified(testFqn, false, NodeModifiedEvent.ModificationType.PUT_MAP, expected, null);
+
+      control.replay();
+      assert null == command.perform(null) : "null result is always expected";
+      assert command.getOldData().size() == 1;
+      assert command.getOldData().get("k").equals("v");
+      assert node.getData().size() == 1;
+      assert node.getData().get("k2").equals("v2");
+      control.verify();
+      control.reset();
+      
+      //check rollback now
+      expect(container.peek(testFqn, false, true)).andReturn(node);
+      control.replay();
+      command.rollback();
+      assert node.getData().size() == 1;
+      assert node.getData().containsKey("k");
+      control.verify();
+   }
+
+   public void testRollbackNonexistentNode()
+   {
+      expect(container.peek(testFqn, false, true)).andReturn(null);
+      control.replay();
+      command.rollback();
+      control.verify();
+   }
+}

Added: core/trunk/src/test/java/org/jboss/cache/commands/write/PutKeyValueCommandTest.java
===================================================================
--- core/trunk/src/test/java/org/jboss/cache/commands/write/PutKeyValueCommandTest.java	                        (rev 0)
+++ core/trunk/src/test/java/org/jboss/cache/commands/write/PutKeyValueCommandTest.java	2008-05-20 22:02:19 UTC (rev 5879)
@@ -0,0 +1,91 @@
+package org.jboss.cache.commands.write;
+
+import static org.easymock.EasyMock.*;
+import org.testng.annotations.Test;
+import org.jboss.cache.CacheException;
+import org.jboss.cache.notifications.event.NodeModifiedEvent;
+
+import java.util.Map;
+import java.util.HashMap;
+import java.util.Collections;
+
+/**
+ * tester class for {@link PutKeyValueCommand}.
+ *
+ * @author Mircea.Markus at jboss.com
+ * @since 2.2
+ */
+ at Test(groups = "unit")
+public class PutKeyValueCommandTest extends AbstractVersionedDataCommandTest
+{
+   PutKeyValueCommand command;
+
+   public AbstractVersionedDataCommand moreSetUp()
+   {
+      command = new PutForExternalReadCommand(globalTransaction, fqn, "k", "v", true);
+      return command;
+   }
+
+   public void testInexistentNode()
+   {
+      expect(container.peekStrict(globalTransaction, fqn, false)).andThrow(new CacheException());
+      control.replay();
+      try
+      {
+         command.perform(ctx);
+         assert false : "exception should have been thrown as data does not exists.";
+      } catch (Exception e)
+      {
+         //expected
+      }
+      control.verify();
+   }
+
+   public void testAddNewData()
+   {
+      nodes.adfNode.put("existingKey", "existingValue");
+      expect(container.peekStrict(globalTransaction, fqn, false)).andReturn(nodes.adfNode);
+      notifier.notifyNodeModified(fqn, true, NodeModifiedEvent.ModificationType.PUT_DATA, nodes.adfNode.getDataDirect(), ctx);
+      Map expected = new HashMap();
+      expected.put("k", "v");
+      notifier.notifyNodeModified(fqn, false, NodeModifiedEvent.ModificationType.PUT_DATA, expected, ctx);
+      control.replay();
+      assert null == command.perform(ctx) : "no pre existing value";
+      assert nodes.adfNode.getData().size() == 2;
+      assert "v".equals(nodes.adfNode.getData().get("k"));
+      assert "existingValue".equals(nodes.adfNode.getData().get("existingKey"));
+      control.verify();
+
+      control.reset();
+      expect(container.peek(fqn, false, false)).andReturn(nodes.adfNode);
+      control.replay();
+      command.rollback();
+      assert nodes.adfNode.getData().size() == 1;
+      assert "existingValue".equals(nodes.adfNode.getData().get("existingKey"));
+      control.verify();
+      
+   }
+
+   public void testOverWriteData()
+   {
+      nodes.adfNode.put("k", "oldValue");
+      expect(container.peekStrict(globalTransaction, fqn, false)).andReturn(nodes.adfNode);
+      notifier.notifyNodeModified(fqn, true, NodeModifiedEvent.ModificationType.PUT_DATA, nodes.adfNode.getDataDirect(), ctx);
+      Map expected = new HashMap();
+      expected.put("k", "v");
+      notifier.notifyNodeModified(fqn, false, NodeModifiedEvent.ModificationType.PUT_DATA, expected, ctx);
+      control.replay();
+      assert "oldValue".equals(command.perform(ctx)) : "no pre existing value";
+      assert nodes.adfNode.getData().size() == 1;
+      assert "v".equals(nodes.adfNode.getData().get("k"));
+      control.verify();
+
+      control.reset();
+      expect(container.peek(fqn, false, false)).andReturn(nodes.adfNode);
+      control.replay();
+      command.rollback();
+      assert nodes.adfNode.getData().size() == 1;
+      assert "oldValue".equals(nodes.adfNode.getData().get("k"));
+      control.verify();      
+   }
+}

Added: core/trunk/src/test/java/org/jboss/cache/commands/write/RemoveKeyCommandTest.java
===================================================================
--- core/trunk/src/test/java/org/jboss/cache/commands/write/RemoveKeyCommandTest.java	                        (rev 0)
+++ core/trunk/src/test/java/org/jboss/cache/commands/write/RemoveKeyCommandTest.java	2008-05-20 22:02:19 UTC (rev 5879)
@@ -0,0 +1,67 @@
+package org.jboss.cache.commands.write;
+
+import static org.easymock.EasyMock.*;
+import org.testng.annotations.Test;
+import org.jboss.cache.notifications.event.NodeModifiedEvent;
+
+import java.util.Collections;
+import java.util.Map;
+import java.util.HashMap;
+
+/**
+ * tester class for {@link RemoveKeyCommand}.
+ *
+ * @author Mircea.Markus at jboss.com
+ * @since 2.2
+ */
+ at Test(groups="unit")
+public class RemoveKeyCommandTest extends AbstractVersionedDataCommandTest
+{
+   RemoveKeyCommand command;
+   private String key;
+
+   public AbstractVersionedDataCommand moreSetUp()
+   {
+      key = "key";
+      command = new RemoveKeyCommand(globalTransaction, fqn, key);
+      return command;
+   }
+
+   public void testNonexistentNode()
+   {
+      expect(container.peek(fqn, false, false)).andReturn(null);
+      control.replay();
+      assert null == command.perform(ctx);
+      control.verify();
+   }
+
+   public void testRemoveNonexistentPair()
+   {
+      Map expected = new HashMap();
+      expected.put("newKey","newValue");
+      nodes.adfgNode.putAll(expected);
+      expect(container.peek(fqn, false, false)).andReturn(nodes.adfgNode);
+      notifier.notifyNodeModified(fqn, true, NodeModifiedEvent.ModificationType.REMOVE_DATA, expected, ctx);
+      expected = new HashMap();
+      expected.put(key,null);
+      notifier.notifyNodeModified(fqn, false, NodeModifiedEvent.ModificationType.REMOVE_DATA, expected, ctx);
+      control.replay();
+      assert null == command.perform(ctx);
+      control.verify();
+   }
+
+   public void testRemoveExistentPair()
+   {
+      Map expected = new HashMap();
+      expected.put(key,"newValue");
+      nodes.adfgNode.putAll(expected);
+      expect(container.peek(fqn, false, false)).andReturn(nodes.adfgNode);
+      notifier.notifyNodeModified(fqn, true, NodeModifiedEvent.ModificationType.REMOVE_DATA, expected, ctx);
+      expected = new HashMap();
+      expected.put(key,null);
+      notifier.notifyNodeModified(fqn, false, NodeModifiedEvent.ModificationType.REMOVE_DATA, expected, ctx);
+      control.replay();
+      assert null == command.perform(ctx);
+      control.verify();
+   }
+}

Modified: core/trunk/src/test/java/org/jboss/cache/interceptors/EvictionInterceptorTest.java
===================================================================
--- core/trunk/src/test/java/org/jboss/cache/interceptors/EvictionInterceptorTest.java	2008-05-20 16:34:22 UTC (rev 5878)
+++ core/trunk/src/test/java/org/jboss/cache/interceptors/EvictionInterceptorTest.java	2008-05-20 22:02:19 UTC (rev 5879)
@@ -18,7 +18,7 @@
 import org.jboss.cache.commands.read.GetNodeCommand;
 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.ClearDataCommand;
 import org.jboss.cache.commands.write.RemoveKeyCommand;
 import org.jboss.cache.commands.write.RemoveNodeCommand;
 import org.jboss.cache.config.EvictionConfig;
@@ -417,8 +417,8 @@
       putQuietly(fqn, "a", "b");
       putQuietly(fqn, "b", "c");
 
-      RemoveDataCommand removeDataCommand = commandsFactory.buildRemoveDataCommand(null, fqn, false, false, false);
-      invoker.invoke(removeDataCommand);
+      ClearDataCommand clearDataCommand = commandsFactory.buildClearDataCommand(null, fqn);
+      invoker.invoke(clearDataCommand);
 
       assertEquals(0, cache.peek(fqn, false, false).getDataDirect().size());
       Region region = regionManager.getRegion(fqn.toString(), false);
@@ -443,7 +443,7 @@
       putQuietly(fqn, "a", "b");
       putQuietly(fqn, "b", "c");
 
-      RemoveKeyCommand removeKeyCommand = commandsFactory.buildRemoveKeyCommand(null, fqn, "a", false);
+      RemoveKeyCommand removeKeyCommand = commandsFactory.buildRemoveKeyCommand(null, fqn, "a");
       invoker.invoke(removeKeyCommand);
 
       assertNull(cache.get(fqn, "a"));
@@ -454,7 +454,7 @@
       assertEquals(1, event.getElementDifference());
       assertNull(region.takeLastEventNode());
 
-      RemoveKeyCommand removeKeyCommand2 = commandsFactory.buildRemoveKeyCommand(null, fqn, "b", false);
+      RemoveKeyCommand removeKeyCommand2 = commandsFactory.buildRemoveKeyCommand(null, fqn, "b");
       invoker.invoke(removeKeyCommand2);
 
       assertNull(cache.get(fqn, "b"));
@@ -464,7 +464,7 @@
       assertEquals(1, event.getElementDifference());
       assertNull(region.takeLastEventNode());
 
-      RemoveKeyCommand removeKeyCommand3 = commandsFactory.buildRemoveKeyCommand(null, fqn, "a", false);
+      RemoveKeyCommand removeKeyCommand3 = commandsFactory.buildRemoveKeyCommand(null, fqn, "a");
       invoker.invoke(removeKeyCommand3);
 
       event = region.takeLastEventNode();
@@ -528,7 +528,7 @@
       assertEquals(fqn, event.getFqn());
       assertNull(region.takeLastEventNode());
 
-      RemoveKeyCommand removeKeyCommand = commandsFactory.buildRemoveKeyCommand(null, fqn, key, false);
+      RemoveKeyCommand removeKeyCommand = commandsFactory.buildRemoveKeyCommand(null, fqn, key);
       invoker.invoke(removeKeyCommand);
 
       assertNull(cache.get(fqn, key));

Modified: core/trunk/src/test/java/org/jboss/cache/invalidation/VersionInconsistencyTest.java
===================================================================
--- core/trunk/src/test/java/org/jboss/cache/invalidation/VersionInconsistencyTest.java	2008-05-20 16:34:22 UTC (rev 5878)
+++ core/trunk/src/test/java/org/jboss/cache/invalidation/VersionInconsistencyTest.java	2008-05-20 22:02:19 UTC (rev 5879)
@@ -1,16 +1,12 @@
 package org.jboss.cache.invalidation;
 
-import org.jboss.cache.Cache;
-import org.jboss.cache.CacheSPI;
-import org.jboss.cache.DefaultCacheFactory;
-import org.jboss.cache.Fqn;
-import org.jboss.cache.NodeSPI;
+import org.jboss.cache.*;
 import org.jboss.cache.config.Configuration;
 import org.jboss.cache.misc.TestingUtil;
 import org.jboss.cache.optimistic.DefaultDataVersion;
 import org.jboss.cache.transaction.DummyTransactionManagerLookup;
-import org.testng.annotations.AfterTest;
-import org.testng.annotations.BeforeTest;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
 
 import javax.transaction.Transaction;
@@ -29,7 +25,7 @@
    private TransactionManager tm1, tm2;
    private Fqn node = Fqn.fromString("/a");
 
-   @BeforeTest
+   @BeforeMethod
    public void setUp()
    {
       cache1 = new DefaultCacheFactory().createCache(false);
@@ -53,7 +49,7 @@
       TestingUtil.blockUntilViewsReceived(1000, cache1, cache2);
    }
 
-   @AfterTest
+   @AfterMethod
    public void tearDown()
    {
       cache1.stop();

Modified: core/trunk/src/test/java/org/jboss/cache/mock/NodeSpiMock.java
===================================================================
--- core/trunk/src/test/java/org/jboss/cache/mock/NodeSpiMock.java	2008-05-20 16:34:22 UTC (rev 5878)
+++ core/trunk/src/test/java/org/jboss/cache/mock/NodeSpiMock.java	2008-05-20 22:02:19 UTC (rev 5879)
@@ -211,7 +211,7 @@
 
    public void putAllDirect(Map data)
    {
-      data.putAll(data);
+      this.data.putAll(data);
    }
 
    public Map getDataDirect()
@@ -355,7 +355,7 @@
 
    public void putAll(Map map)
    {
-      putAllDirect(data);
+      putAllDirect(map);
    }
 
    public void replaceAll(Map map)




More information about the jbosscache-commits mailing list