[jbosscache-commits] JBoss Cache SVN: r6869 - in core/branches/flat/src/main/java/org/jboss/starobrno: commands and 6 other directories.

jbosscache-commits at lists.jboss.org jbosscache-commits at lists.jboss.org
Wed Oct 8 07:53:03 EDT 2008


Author: manik.surtani at jboss.com
Date: 2008-10-08 07:53:03 -0400 (Wed, 08 Oct 2008)
New Revision: 6869

Added:
   core/branches/flat/src/main/java/org/jboss/starobrno/commands/read/GravitateDataCommand.java
   core/branches/flat/src/main/java/org/jboss/starobrno/commands/remote/
   core/branches/flat/src/main/java/org/jboss/starobrno/commands/remote/AnnounceBuddyPoolNameCommand.java
   core/branches/flat/src/main/java/org/jboss/starobrno/commands/remote/AssignToBuddyGroupCommand.java
   core/branches/flat/src/main/java/org/jboss/starobrno/commands/remote/ClusteredGetCommand.java
   core/branches/flat/src/main/java/org/jboss/starobrno/commands/remote/DataGravitationCleanupCommand.java
   core/branches/flat/src/main/java/org/jboss/starobrno/commands/remote/RemoveFromBuddyGroupCommand.java
   core/branches/flat/src/main/java/org/jboss/starobrno/commands/remote/ReplicateCommand.java
   core/branches/flat/src/main/java/org/jboss/starobrno/transaction/TransactionTable.java
Removed:
   core/branches/flat/src/main/java/org/jboss/starobrno/transaction/TransactionContext.java
Modified:
   core/branches/flat/src/main/java/org/jboss/starobrno/Cache.java
   core/branches/flat/src/main/java/org/jboss/starobrno/CacheImpl.java
   core/branches/flat/src/main/java/org/jboss/starobrno/commands/TransactionBoundaryCommand.java
   core/branches/flat/src/main/java/org/jboss/starobrno/commands/tx/AbstractTransactionBoundaryCommand.java
   core/branches/flat/src/main/java/org/jboss/starobrno/commands/tx/CommitCommand.java
   core/branches/flat/src/main/java/org/jboss/starobrno/commands/tx/PrepareCommand.java
   core/branches/flat/src/main/java/org/jboss/starobrno/commands/tx/RollbackCommand.java
   core/branches/flat/src/main/java/org/jboss/starobrno/context/InvocationContextImpl.java
   core/branches/flat/src/main/java/org/jboss/starobrno/context/TransactionContext.java
   core/branches/flat/src/main/java/org/jboss/starobrno/context/TransactionContextImpl.java
   core/branches/flat/src/main/java/org/jboss/starobrno/factories/context/ContextFactory.java
Log:
Fixed stuff

Modified: core/branches/flat/src/main/java/org/jboss/starobrno/Cache.java
===================================================================
--- core/branches/flat/src/main/java/org/jboss/starobrno/Cache.java	2008-10-08 11:51:17 UTC (rev 6868)
+++ core/branches/flat/src/main/java/org/jboss/starobrno/Cache.java	2008-10-08 11:53:03 UTC (rev 6869)
@@ -21,8 +21,8 @@
  */
 package org.jboss.starobrno;
 
-import org.jboss.cache.InvocationContext;
-import org.jboss.cache.config.Configuration;
+import org.jboss.starobrno.config.Configuration;
+import org.jboss.starobrno.context.InvocationContext;
 import org.jboss.starobrno.lifecycle.Lifecycle;
 
 import java.util.Set;

Modified: core/branches/flat/src/main/java/org/jboss/starobrno/CacheImpl.java
===================================================================
--- core/branches/flat/src/main/java/org/jboss/starobrno/CacheImpl.java	2008-10-08 11:51:17 UTC (rev 6868)
+++ core/branches/flat/src/main/java/org/jboss/starobrno/CacheImpl.java	2008-10-08 11:53:03 UTC (rev 6869)
@@ -21,14 +21,15 @@
  */
 package org.jboss.starobrno;
 
+import org.jboss.starobrno.config.CacheConfig;
+import org.jboss.starobrno.config.Configuration;
+import org.jboss.starobrno.context.InvocationContext;
 import org.jboss.util.NotImplementedException;
-import org.jboss.starobrno.config.CacheConfig;
 
-import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.ConcurrentHashMap;
+import java.util.Collection;
 import java.util.Map;
 import java.util.Set;
-import java.util.Collection;
+import java.util.concurrent.ConcurrentHashMap;
 
 /**
  * @author Mircea.Markus at jboss.com
@@ -36,7 +37,7 @@
 public class CacheImpl implements Cache
 {
    private ConcurrentHashMap data = new ConcurrentHashMap();
-   private Map<String, AtomicGroup> atomicGroups = new ConcurrentHashMap<String, AtomicGroup>(); 
+   private Map<String, AtomicGroup> atomicGroups = new ConcurrentHashMap<String, AtomicGroup>();
    private CacheConfig cacheConfig;
 
 
@@ -141,4 +142,49 @@
    {
       return (data != null ? data.hashCode() : 0);
    }
+
+   public void evict(Object key)
+   {
+      //TODO: Autogenerated.  Implement me properly
+   }
+
+   public Configuration getConfiguration()
+   {
+      return null;  //TODO: Autogenerated.  Implement me properly
+   }
+
+   public void addCacheListener(Object listener)
+   {
+      //TODO: Autogenerated.  Implement me properly
+   }
+
+   public void removeCacheListener(Object listener)
+   {
+      //TODO: Autogenerated.  Implement me properly
+   }
+
+   public Set getCacheListeners()
+   {
+      return null;  //TODO: Autogenerated.  Implement me properly
+   }
+
+   public InvocationContext getInvocationContext()
+   {
+      return null;  //TODO: Autogenerated.  Implement me properly
+   }
+
+   public void setInvocationContext(InvocationContext ctx)
+   {
+      //TODO: Autogenerated.  Implement me properly
+   }
+
+   public void start()
+   {
+      //TODO: Autogenerated.  Implement me properly
+   }
+
+   public void stop()
+   {
+      //TODO: Autogenerated.  Implement me properly
+   }
 }

Modified: core/branches/flat/src/main/java/org/jboss/starobrno/commands/TransactionBoundaryCommand.java
===================================================================
--- core/branches/flat/src/main/java/org/jboss/starobrno/commands/TransactionBoundaryCommand.java	2008-10-08 11:51:17 UTC (rev 6868)
+++ core/branches/flat/src/main/java/org/jboss/starobrno/commands/TransactionBoundaryCommand.java	2008-10-08 11:53:03 UTC (rev 6869)
@@ -21,7 +21,7 @@
  */
 package org.jboss.starobrno.commands;
 
-import org.jboss.cache.transaction.GlobalTransaction;
+import org.jboss.starobrno.transaction.GlobalTransaction;
 
 /**
  * // TODO: MANIK: Document this

Added: core/branches/flat/src/main/java/org/jboss/starobrno/commands/read/GravitateDataCommand.java
===================================================================
--- core/branches/flat/src/main/java/org/jboss/starobrno/commands/read/GravitateDataCommand.java	                        (rev 0)
+++ core/branches/flat/src/main/java/org/jboss/starobrno/commands/read/GravitateDataCommand.java	2008-10-08 11:53:03 UTC (rev 6869)
@@ -0,0 +1,265 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2000 - 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.starobrno.commands.read;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.jboss.cache.CacheSPI;
+import org.jboss.cache.buddyreplication.BuddyFqnTransformer;
+import org.jboss.starobrno.DataContainer;
+import org.jboss.starobrno.commands.DataCommand;
+import org.jboss.starobrno.commands.Visitor;
+import org.jboss.starobrno.context.InvocationContext;
+import org.jgroups.Address;
+
+/**
+ * Used with buddy replication's {@link org.jboss.cache.interceptors.DataGravitatorInterceptor}.
+ * <p/>
+ * This is the equivalent of the old MethodCallDefinitions.dataGravitationMethod method call from 2.1.x.
+ * <p/>
+ *
+ * @author Manik Surtani
+ * @since 2.2.0
+ */
+public class GravitateDataCommand implements DataCommand
+{
+   public static final int METHOD_ID = 35;
+
+   /* dependencies */
+   private CacheSPI spi;
+
+   /* parametres */
+   protected boolean searchSubtrees;
+   private Address localAddress;
+
+   private static final Log log = LogFactory.getLog(GravitateDataCommand.class);
+   private static final boolean trace = log.isTraceEnabled();
+   private BuddyFqnTransformer buddyFqnTransformer;
+   private Object key;
+   private DataContainer dataContainer;
+
+   public GravitateDataCommand(Object key, boolean searchSubtrees, Address localAddress)
+   {
+      this.key = key;
+      this.searchSubtrees = searchSubtrees;
+      this.localAddress = localAddress;
+   }
+
+   public GravitateDataCommand(Address localAddress)
+   {
+      this.localAddress = localAddress;
+   }
+
+   public void initialize(DataContainer dataContainer, CacheSPI spi, BuddyFqnTransformer transformer)
+   {
+      this.dataContainer = dataContainer;
+      this.spi = spi;
+      buddyFqnTransformer = transformer;
+   }
+
+   /**
+    * Searches for data to gravitate given an Fqn and whether buddy backup subtrees are to be searched as well.  Note that
+    * data stored under the Fqn, along with all children, are retrieved.
+    *
+    * @param ctx invocation context
+    * @return a {@link org.jboss.cache.buddyreplication.GravitateResult} containing node data, as well as information on whether this was found in a primary or backup tree.
+    */
+   @SuppressWarnings("unchecked")
+   public Object perform(InvocationContext ctx)
+   {
+      /*
+      // TODO: Test this with MVCC.
+
+      // for now, perform a very simple series of getData calls.
+      if (trace) log.trace("Caller is asking for " + key);
+      try
+      {
+         ctx.setOriginLocal(false);
+         // use a get() call into the cache to make sure cache loading takes place.
+         // no need to cache the original skipDataGravitation setting here - it will always be false of we got here!!
+         //todo 2.2  use dataContainer for peek and load the data in the CLInterceptor rather than using the SPI for than!!!
+         ctx.getOptionOverrides().setSkipDataGravitation(true);
+         Node actualNode = spi.getNode(fqn);
+         ctx.getOptionOverrides().setSkipDataGravitation(false);
+
+         if (trace) log.trace("In local tree, this is " + actualNode);
+
+         Fqn backupNodeFqn = null;
+         if (actualNode == null && searchSubtrees)
+         {
+            log.trace("Looking at backup trees.");
+
+            // need to loop through backupSubtree's children
+            Set allGroupNames = getBackupRoots();
+            if (allGroupNames != null)
+            {
+               for (Object groupName : allGroupNames)
+               {
+                  // groupName is the name of a buddy group since all child names in this
+                  // collection are direct children of BUDDY_BACKUP_SUBTREE_FQN
+                  Fqn backupRoot = Fqn.fromRelativeElements(BuddyManager.BUDDY_BACKUP_SUBTREE_FQN, (String) groupName);
+                  if (buddyFqnTransformer.isDeadBackupRoot(backupRoot))
+                  {
+                     Set<Integer> deadChildNames = new TreeSet<Integer>(spi.getChildrenNames(backupRoot));
+                     Integer[] elems = deadChildNames.toArray(new Integer[deadChildNames.size()]);
+
+                     // these are integers.  we need to start with the highest/most recent.
+                     for (int i = elems.length - 1; i > -1; i--)
+                     {
+                        Integer versionOfDefunctData = elems[i];
+                        backupNodeFqn = Fqn.fromRelativeFqn(Fqn.fromRelativeElements(backupRoot, versionOfDefunctData), fqn);
+
+                        // use a get() call into the cache to make sure cache loading takes place.
+                        ctx.getOptionOverrides().setSkipDataGravitation(true);
+                        actualNode = spi.peek(backupNodeFqn, false);
+                        ctx.getOptionOverrides().setSkipDataGravitation(false);
+
+                        // break out of the inner loop searching through the dead node's various backups
+                        if (actualNode != null) break;
+                     }
+                  }
+                  else
+                  {
+                     backupNodeFqn = Fqn.fromRelativeFqn(backupRoot, fqn);
+                     // use a get() call into the cache to make sure cache loading takes place.
+                     ctx.getOptionOverrides().setSkipDataGravitation(true);
+                     actualNode = spi.getNode(backupNodeFqn);
+                     ctx.getOptionOverrides().setSkipDataGravitation(false);
+                  }
+
+                  if (trace)
+                     log.trace("Looking for " + backupNodeFqn + ". Search result: " + actualNode);
+
+                  // break out of outer loop searching through all available backups.
+                  if (actualNode != null) break;
+               }
+            }
+
+         }
+
+         if (actualNode == null)
+         {
+            return GravitateResult.noDataFound();
+         }
+         else
+         {
+            // make sure we LOAD data for this node!!
+            actualNode.getData();
+         }
+
+         if (backupNodeFqn == null && searchSubtrees)
+         {
+            backupNodeFqn = buddyFqnTransformer.getBackupFqn(buddyFqnTransformer.getGroupNameFromAddress(localAddress), fqn);
+         }
+
+         List<NodeData> list = dataContainer.buildNodeData(new LinkedList<NodeData>(), (NodeSPI) actualNode, false);
+
+         return GravitateResult.subtreeResult(list, backupNodeFqn);
+      }
+      catch (RuntimeException re)
+      {
+         if (trace) log.trace("Caught throwable", re);
+         throw re;
+      }
+      finally
+      {
+         ctx.setOriginLocal(true);
+      }
+      */
+
+      throw new UnsupportedOperationException("FIX ME");
+      // TODO: implement BR on flat cache
+   }
+
+   /**
+    * @return a Set of child node names that hang directly off the backup tree root, or null if the backup tree root doesn't exist.
+    */
+//   protected Set<Object> getBackupRoots()
+//   {
+//      InternalNode backupSubtree = dataContainer.peekInternalNode(BuddyManager.BUDDY_BACKUP_SUBTREE_FQN, false);
+//      if (backupSubtree == null) return null;
+//      return backupSubtree.getChildrenNames();
+//   }
+   public Object acceptVisitor(InvocationContext ctx, Visitor visitor) throws Throwable
+   {
+      // TODO implement me
+      return null;
+//      return visitor.visitGravitateDataCommand(ctx, this);
+   }
+
+   public int getCommandId()
+   {
+      return METHOD_ID;
+   }
+
+   public boolean isSearchSubtrees()
+   {
+      return searchSubtrees;
+   }
+
+   public Object[] getParameters()
+   {
+      return new Object[]{key, searchSubtrees};
+   }
+
+   public void setParameters(int commandId, Object[] args)
+   {
+      key = args[0];
+      searchSubtrees = (Boolean) args[1];
+   }
+
+   @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;
+
+      GravitateDataCommand that = (GravitateDataCommand) o;
+
+      if (searchSubtrees != that.searchSubtrees) return false;
+
+      return true;
+   }
+
+   @Override
+   public int hashCode()
+   {
+      int result = super.hashCode();
+      result = 31 * result + (searchSubtrees ? 1 : 0);
+      return result;
+   }
+
+   @Override
+   public String toString()
+   {
+      return "GravitateDataCommand{" +
+            "key=" + key +
+            ", searchSubtrees=" + searchSubtrees +
+            '}';
+   }
+
+   public Object getKey()
+   {
+      return null;  //TODO: Autogenerated.  Implement me properly
+   }
+}

Added: core/branches/flat/src/main/java/org/jboss/starobrno/commands/remote/AnnounceBuddyPoolNameCommand.java
===================================================================
--- core/branches/flat/src/main/java/org/jboss/starobrno/commands/remote/AnnounceBuddyPoolNameCommand.java	                        (rev 0)
+++ core/branches/flat/src/main/java/org/jboss/starobrno/commands/remote/AnnounceBuddyPoolNameCommand.java	2008-10-08 11:53:03 UTC (rev 6869)
@@ -0,0 +1,140 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2000 - 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.starobrno.commands.remote;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.jboss.cache.buddyreplication.BuddyManager;
+import org.jboss.starobrno.commands.ReplicableCommand;
+import org.jboss.starobrno.context.InvocationContext;
+import org.jgroups.Address;
+
+/**
+ * Announces a buddy pool name to the cluster.  This is not a {@link org.jboss.cache.commands.VisitableCommand} and hence
+ * not passed up the {@link org.jboss.cache.interceptors.base.CommandInterceptor} chain.
+ * <p/>
+ *
+ * @author Mircea.Markus at jboss.com
+ * @since 2.2.0
+ */
+public class AnnounceBuddyPoolNameCommand implements ReplicableCommand
+{
+   public static final int METHOD_ID = 28;
+   private static final Log log = LogFactory.getLog(AnnounceBuddyPoolNameCommand.class);
+
+   /* dependencies*/
+   private BuddyManager buddyManager;
+
+   /*parameters */
+   private Address address;
+   private String buddyPoolName;
+
+   public AnnounceBuddyPoolNameCommand()
+   {
+   }
+
+   public AnnounceBuddyPoolNameCommand(Address address, String buddyPoolName)
+   {
+      this.address = address;
+      this.buddyPoolName = buddyPoolName;
+   }
+
+   public void initialize(BuddyManager buddyManager)
+   {
+      this.buddyManager = buddyManager;
+   }
+
+   /**
+    * This method calls the relevant handler on the buddy manager to deal with this pool broadcast.
+    *
+    * @param ctx invocation context, ignored.
+    * @return null
+    * @throws Throwable in the event of problems
+    */
+   public Object perform(InvocationContext ctx) throws Throwable
+   {
+      if (buddyManager != null)
+         buddyManager.handlePoolNameBroadcast(address, buddyPoolName);
+      else if (log.isWarnEnabled())
+         log.warn("Received annouceBuddyPoolName call from [" + address + "] but buddy replication is not enabled on this node!");
+      return null;
+   }
+
+   public int getCommandId()
+   {
+      return METHOD_ID;
+   }
+
+   public Address getAddress()
+   {
+      return address;
+   }
+
+   public String getBuddyPoolName()
+   {
+      return buddyPoolName;
+   }
+
+   public Object[] getParameters()
+   {
+      return new Object[]{address, buddyPoolName};
+   }
+
+   public void setParameters(int commandId, Object[] args)
+   {
+      address = (Address) args[0];
+      buddyPoolName = (String) args[1];
+   }
+
+   @Override
+   public boolean equals(Object o)
+   {
+      if (this == o) return true;
+      if (o == null || getClass() != o.getClass()) return false;
+
+      AnnounceBuddyPoolNameCommand that = (AnnounceBuddyPoolNameCommand) o;
+
+      if (address != null ? !address.equals(that.address) : that.address != null) return false;
+      if (buddyPoolName != null ? !buddyPoolName.equals(that.buddyPoolName) : that.buddyPoolName != null) return false;
+
+      return true;
+   }
+
+   @Override
+   public int hashCode()
+   {
+      int result;
+      result = (address != null ? address.hashCode() : 0);
+      result = 31 * result + (buddyPoolName != null ? buddyPoolName.hashCode() : 0);
+      return result;
+   }
+
+   @Override
+   public String toString()
+   {
+      return "AnnounceBuddyPoolNameCommand{" +
+            "buddyManager=" + buddyManager +
+            ", address=" + address +
+            ", buddyPoolName='" + buddyPoolName + '\'' +
+            '}';
+   }
+}

Added: core/branches/flat/src/main/java/org/jboss/starobrno/commands/remote/AssignToBuddyGroupCommand.java
===================================================================
--- core/branches/flat/src/main/java/org/jboss/starobrno/commands/remote/AssignToBuddyGroupCommand.java	                        (rev 0)
+++ core/branches/flat/src/main/java/org/jboss/starobrno/commands/remote/AssignToBuddyGroupCommand.java	2008-10-08 11:53:03 UTC (rev 6869)
@@ -0,0 +1,140 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2000 - 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.starobrno.commands.remote;
+
+import org.jboss.cache.Fqn;
+import org.jboss.cache.buddyreplication.BuddyGroup;
+import org.jboss.cache.buddyreplication.BuddyManager;
+import org.jboss.starobrno.commands.ReplicableCommand;
+import org.jboss.starobrno.context.InvocationContext;
+
+import java.util.Arrays;
+import java.util.Map;
+
+/**
+ * Assigns a buddy to a group.  This is not a {@link org.jboss.cache.commands.VisitableCommand} and hence
+ * not passed up the {@link org.jboss.cache.interceptors.base.CommandInterceptor} chain.
+ * <p/>
+ *
+ * @author Mircea.Markus at jboss.com
+ * @since 2.2.0
+ */
+public class AssignToBuddyGroupCommand implements ReplicableCommand
+{
+   public static final int METHOD_ID = 29;
+
+   /* dependencies */
+   private BuddyManager buddyManager;
+
+   /* parameters */
+   private BuddyGroup group;
+   private Map<Fqn, byte[]> state;
+
+   public AssignToBuddyGroupCommand(BuddyGroup group, Map<Fqn, byte[]> state)
+   {
+      this.group = group;
+      this.state = state;
+   }
+
+   public AssignToBuddyGroupCommand()
+   {
+   }
+
+   public void initialize(BuddyManager manager)
+   {
+      this.buddyManager = manager;
+   }
+
+   /**
+    * This method calls the relevant handler on the buddy manager to deal with being assigned to a buddy group
+    *
+    * @param ctx invocation context, ignored.
+    * @return null
+    * @throws Throwable in the event of problems
+    */
+   public Object perform(InvocationContext ctx) throws Throwable
+   {
+      if (buddyManager != null)
+         buddyManager.handleAssignToBuddyGroup(group, state);
+      return null;
+   }
+
+   public int getCommandId()
+   {
+      return METHOD_ID;
+   }
+
+   public BuddyGroup getGroup()
+   {
+      return group;
+   }
+
+   public Map<Fqn, byte[]> getState()
+   {
+      return state;
+   }
+
+   public Object[] getParameters()
+   {
+      return new Object[]{group, state};
+   }
+
+   @SuppressWarnings("unchecked")
+   public void setParameters(int commandId, Object[] args)
+   {
+      group = (BuddyGroup) args[0];
+      state = (Map<Fqn, byte[]>) args[1];
+   }
+
+   @Override
+   public boolean equals(Object o)
+   {
+      if (this == o) return true;
+      if (o == null || getClass() != o.getClass()) return false;
+
+      AssignToBuddyGroupCommand that = (AssignToBuddyGroupCommand) o;
+
+      if (group != null ? !group.equals(that.group) : that.group != null) return false;
+      if (state != null ? !state.equals(that.state) : that.state != null) return false;
+
+      return true;
+   }
+
+   @Override
+   public int hashCode()
+   {
+      int result;
+      result = (group != null ? group.hashCode() : 0);
+      result = 31 * result + (state != null ? state.hashCode() : 0);
+      return result;
+   }
+
+   @Override
+   public String toString()
+   {
+      return "AssignToBuddyGroupCommand{" +
+            "buddyManager=" + buddyManager +
+            ", group=" + group +
+            ", state=" + (state == null ? null : Arrays.asList(state)) +
+            '}';
+   }
+}

Added: core/branches/flat/src/main/java/org/jboss/starobrno/commands/remote/ClusteredGetCommand.java
===================================================================
--- core/branches/flat/src/main/java/org/jboss/starobrno/commands/remote/ClusteredGetCommand.java	                        (rev 0)
+++ core/branches/flat/src/main/java/org/jboss/starobrno/commands/remote/ClusteredGetCommand.java	2008-10-08 11:53:03 UTC (rev 6869)
@@ -0,0 +1,177 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2000 - 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.starobrno.commands.remote;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.jboss.starobrno.DataContainer;
+import org.jboss.starobrno.commands.DataCommand;
+import org.jboss.starobrno.commands.ReplicableCommand;
+import org.jboss.starobrno.context.InvocationContext;
+import org.jboss.starobrno.interceptors.InterceptorChain;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Issues a clustered get call, for use primarily by the {@link org.jboss.cache.loader.ClusteredCacheLoader}.  This is
+ * not a {@link org.jboss.cache.commands.VisitableCommand} and hence
+ * not passed up the {@link org.jboss.cache.interceptors.base.CommandInterceptor} chain.
+ * <p/>
+ *
+ * @author Mircea.Markus at jboss.com
+ * @since 2.2.0
+ */
+public class ClusteredGetCommand implements ReplicableCommand
+{
+   public static final int METHOD_ID = 22;
+
+   private DataCommand dataCommand;
+   private boolean searchBackupSubtrees;
+   private DataContainer dataContainer;
+   private InterceptorChain interceptorChain;
+
+   private static final Log log = LogFactory.getLog(ClusteredGetCommand.class);
+   private static final boolean trace = log.isTraceEnabled();
+
+   public ClusteredGetCommand(boolean searchBackupSubtrees, DataCommand dataCommand)
+   {
+      this.searchBackupSubtrees = searchBackupSubtrees;
+      this.dataCommand = dataCommand;
+   }
+
+   public ClusteredGetCommand()
+   {
+   }
+
+   public void initialize(DataContainer dataContainer, InterceptorChain interceptorChain)
+   {
+      this.dataContainer = dataContainer;
+      this.interceptorChain = interceptorChain;
+   }
+
+   /**
+    * Invokes a {@link org.jboss.cache.commands.DataCommand} on a remote cache and returns results.
+    *
+    * @param context invocation context, ignored.
+    * @return a List containing 2 elements: a boolean, (true or false) and a value (Object) which is the result of invoking a remote get specified by {@link #getDataCommand()}.  If buddy replication is used one further element is added - an Fqn of the backup subtree in which this node may be found.
+    */
+   public Object perform(InvocationContext context) throws Throwable
+   {
+      if (trace)
+         log.trace("Clustered Get called with params: " + dataCommand + ", " + searchBackupSubtrees);
+
+      Object callResults = null;
+      try
+      {
+         InvocationContext ctx = interceptorChain.getInvocationContext();
+         ctx.setOriginLocal(false);
+         // very hacky to be calling this command directly.
+         callResults = dataCommand.perform(ctx);
+         boolean found = true; // TODO: Revisit this!!
+         if (trace) log.trace("Got result " + callResults + ", found=" + found);
+         if (found && callResults == null) callResults = createEmptyResults();
+      }
+      catch (Exception e)
+      {
+         log.warn("Problems processing clusteredGet call", e);
+      }
+
+      List<Object> results = new ArrayList<Object>(2);
+      if (callResults != null)
+      {
+         results.add(true);
+         results.add(callResults);
+      }
+      else
+      {
+         results.add(false);
+         results.add(null);
+      }
+      return results;
+   }
+
+   public int getCommandId()
+   {
+      return METHOD_ID;
+   }
+
+   /**
+    * Creates an empty Collection class based on the return type of the method called.
+    */
+   private Object createEmptyResults()
+   {
+      return null;
+   }
+
+   public Boolean getSearchBackupSubtrees()
+   {
+      return searchBackupSubtrees;
+   }
+
+   public DataCommand getDataCommand()
+   {
+      return dataCommand;
+   }
+
+   public Object[] getParameters()
+   {
+      return new Object[]{dataCommand, searchBackupSubtrees};  //To change body of implemented methods use File | Settings | File Templates.
+   }
+
+   public void setParameters(int commandId, Object[] args)
+   {
+      dataCommand = (DataCommand) args[0];
+      searchBackupSubtrees = (Boolean) args[1];
+   }
+
+   @Override
+   public boolean equals(Object o)
+   {
+      if (this == o) return true;
+      if (o == null || getClass() != o.getClass()) return false;
+
+      ClusteredGetCommand that = (ClusteredGetCommand) o;
+
+      if (dataCommand != null ? !dataCommand.equals(that.dataCommand) : that.dataCommand != null)
+         return false;
+      return searchBackupSubtrees == that.searchBackupSubtrees;
+   }
+
+   @Override
+   public int hashCode()
+   {
+      int result;
+      result = (dataCommand != null ? dataCommand.hashCode() : 0);
+      result = 31 * result + (searchBackupSubtrees ? 1 : 0);
+      return result;
+   }
+
+   @Override
+   public String toString()
+   {
+      return "ClusteredGetCommand{" +
+            "dataCommand=" + dataCommand +
+            ", searchBackupSubtrees=" + searchBackupSubtrees +
+            '}';
+   }
+}

Added: core/branches/flat/src/main/java/org/jboss/starobrno/commands/remote/DataGravitationCleanupCommand.java
===================================================================
--- core/branches/flat/src/main/java/org/jboss/starobrno/commands/remote/DataGravitationCleanupCommand.java	                        (rev 0)
+++ core/branches/flat/src/main/java/org/jboss/starobrno/commands/remote/DataGravitationCleanupCommand.java	2008-10-08 11:53:03 UTC (rev 6869)
@@ -0,0 +1,245 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2000 - 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.starobrno.commands.remote;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.jboss.cache.Fqn;
+import org.jboss.cache.buddyreplication.BuddyFqnTransformer;
+import org.jboss.cache.buddyreplication.BuddyManager;
+import org.jboss.cache.commands.CommandsFactory;
+import org.jboss.starobrno.DataContainer;
+import org.jboss.starobrno.commands.ReplicableCommand;
+import org.jboss.starobrno.context.InvocationContext;
+import org.jboss.starobrno.interceptors.InterceptorChain;
+import org.jboss.starobrno.transaction.GlobalTransaction;
+import org.jboss.starobrno.transaction.TransactionTable;
+
+/**
+ * Data gravitation cleanup handler.  Primarily used by the {@link org.jboss.cache.interceptors.DataGravitatorInterceptor}.
+ * This is not a {@link org.jboss.cache.commands.VisitableCommand} and hence
+ * not passed up the {@link org.jboss.cache.interceptors.base.CommandInterceptor} chain.
+ * <p/>
+ *
+ * @author Mircea.Markus at jboss.com
+ * @since 2.2
+ */
+public class DataGravitationCleanupCommand implements ReplicableCommand
+{
+   public static final int METHOD_ID = 34;
+   private static final Log log = LogFactory.getLog(DataGravitationCleanupCommand.class);
+   private static final boolean trace = log.isTraceEnabled();
+
+   /* dependencies */
+   private BuddyManager buddyManager;
+   private TransactionTable transactionTable;
+   private InterceptorChain invoker;
+   private CommandsFactory commandsFactory;
+   private DataContainer dataContainer;
+
+   /* parameters */
+   private GlobalTransaction globalTransaction;
+   private Fqn fqn;
+   private Fqn backup;
+   private BuddyFqnTransformer buddyFqnTransformer;
+
+
+   public DataGravitationCleanupCommand(Fqn primary, Fqn backup)
+   {
+      this.fqn = primary;
+      this.backup = backup;
+   }
+
+   public DataGravitationCleanupCommand()
+   {
+   }
+
+   public void initialize(BuddyManager buddyManager, InterceptorChain invoker, TransactionTable transactionTable,
+                          CommandsFactory commandsFactory, DataContainer dataContainer, BuddyFqnTransformer buddyFqnTransformer)
+   {
+      this.buddyManager = buddyManager;
+      this.invoker = invoker;
+      this.transactionTable = transactionTable;
+      this.commandsFactory = commandsFactory;
+      this.dataContainer = dataContainer;
+      this.buddyFqnTransformer = buddyFqnTransformer;
+   }
+
+   /**
+    * Performs a cleanup on nodes that would have been previously gravitated away from the current cache instance.
+    */
+   public Object perform(InvocationContext ctx) throws Throwable
+   {/*
+      if (buddyManager.isDataGravitationRemoveOnFind())
+      {
+         if (trace)
+            log.trace("DataGravitationCleanup: Removing primary (" + fqn + ") and backup (" + backup + ")");
+
+         GlobalTransaction gtx = transactionTable.getCurrentTransaction();
+         if (!executeRemove(gtx, fqn))
+         {
+            // only attempt to clean up the backup if the primary did not exist - a waste of a call otherwise.
+            Object result = executeRemove(gtx, backup);
+            if (wasNodeRemoved(result))
+            {
+               // if this is a DIRECT child of a DEAD buddy backup region, then remove the empty dead region structural node.
+               if (buddyFqnTransformer.isDeadBackupFqn(backup) && buddyFqnTransformer.isDeadBackupRoot(backup.getAncestor(backup.size() - 2)))
+               {
+                  Fqn deadBackupRootFqn = backup.getParent();
+                  if (!dataContainer.hasChildren(deadBackupRootFqn))
+                  {
+                     if (trace) log.trace("Removing dead backup region " + deadBackupRootFqn);
+                     executeRemove(gtx, deadBackupRootFqn);
+
+                     // now check the grand parent and see if we are free of versions
+                     deadBackupRootFqn = deadBackupRootFqn.getParent();
+                     if (!dataContainer.hasChildren(deadBackupRootFqn))
+                     {
+                        if (trace) log.trace("Removing dead backup region " + deadBackupRootFqn);
+                        executeRemove(gtx, deadBackupRootFqn);
+                     }
+                  }
+               }
+            }
+         }
+         else
+         {
+            if (trace) log.trace("Managed to remove primary (" + fqn + ").  Not bothering with backups.");
+         }
+      }
+      else
+      {
+         if (trace)
+            log.trace("DataGravitationCleanup: Evicting primary (" + fqn + ") and backup (" + backup + ")");
+         evictNode(fqn);
+         evictNode(backup);
+      }
+      return null;  */
+      // TODO - needs implementation
+      throw new UnsupportedOperationException("Fix me!");
+   }
+
+   /**
+    * Returns true if such a node was removed.
+    */
+//   private boolean executeRemove(GlobalTransaction gtx, Fqn toRemove) throws Throwable
+//   {
+//      Object result;
+//      RemoveNodeCommand removeBackupCommand = commandsFactory.buildRemoveNodeCommand(gtx, toRemove);
+//
+//      InvocationContext ctx = invoker.getInvocationContext();
+//      ctx.getOptionOverrides().setCacheModeLocal(true);
+//      result = invoker.invoke(ctx, removeBackupCommand);
+//      return result != null && (Boolean) result;
+//   }
+   private boolean wasNodeRemoved(Object result)
+   {
+      return result != null && (Boolean) result;
+   }
+
+//   private void evictNode(Fqn fqn) throws Throwable
+//   {
+//      if (dataContainer.exists(fqn))
+//      {
+//         List<Fqn> toEvict = dataContainer.getNodesForEviction(fqn, true);
+//         for (Fqn aFqn : toEvict)
+//         {
+//            EvictCommand evictFqnCommand = commandsFactory.buildEvictFqnCommand(aFqn);
+//            invoker.invoke(evictFqnCommand);
+//         }
+//      }
+//      else
+//      {
+//         if (trace) log.trace("Not evicting " + fqn + " as it doesn't exist");
+//      }
+//   }
+
+   public int getCommandId()
+   {
+      return METHOD_ID;
+   }
+
+   public Fqn getBackup()
+   {
+      return backup;
+   }
+
+   public GlobalTransaction getGlobalTransaction()
+   {
+      return globalTransaction;
+   }
+
+   public void setGlobalTransaction(GlobalTransaction gtx)
+   {
+      this.globalTransaction = gtx;
+   }
+
+   public Fqn getFqn()
+   {
+      return fqn;
+   }
+
+   public Object[] getParameters()
+   {
+      return new Object[]{fqn, backup};  //To change body of implemented methods use File | Settings | File Templates.
+   }
+
+   public void setParameters(int commandId, Object[] args)
+   {
+      fqn = (Fqn) args[0];
+      backup = (Fqn) args[1];
+   }
+
+   @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;
+
+      DataGravitationCleanupCommand that = (DataGravitationCleanupCommand) o;
+
+      if (backup != null ? !backup.equals(that.backup) : that.backup != null) 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 + (backup != null ? backup.hashCode() : 0);
+      return result;
+   }
+
+   @Override
+   public String toString()
+   {
+      return "DataGravitationCleanupCommand{" +
+            "fqn=" + fqn +
+            ", backup=" + backup +
+            '}';
+   }
+}

Added: core/branches/flat/src/main/java/org/jboss/starobrno/commands/remote/RemoveFromBuddyGroupCommand.java
===================================================================
--- core/branches/flat/src/main/java/org/jboss/starobrno/commands/remote/RemoveFromBuddyGroupCommand.java	                        (rev 0)
+++ core/branches/flat/src/main/java/org/jboss/starobrno/commands/remote/RemoveFromBuddyGroupCommand.java	2008-10-08 11:53:03 UTC (rev 6869)
@@ -0,0 +1,118 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2000 - 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.starobrno.commands.remote;
+
+import org.jboss.cache.buddyreplication.BuddyManager;
+import org.jboss.starobrno.commands.ReplicableCommand;
+import org.jboss.starobrno.context.InvocationContext;
+
+/**
+ * Removes a buddy from a group.  This is not a {@link org.jboss.cache.commands.VisitableCommand} and hence
+ * not passed up the {@link org.jboss.cache.interceptors.base.CommandInterceptor} chain.
+ * <p/>
+ *
+ * @author Mircea.Markus at jboss.com
+ * @since 2.2
+ */
+public class RemoveFromBuddyGroupCommand implements ReplicableCommand
+{
+   public static final int METHOD_ID = 30;
+
+   private BuddyManager buddyManager;
+
+   private String groupName;
+
+   public RemoveFromBuddyGroupCommand(String groupName)
+   {
+      this.groupName = groupName;
+   }
+
+   public RemoveFromBuddyGroupCommand()
+   {
+   }
+
+   public void initialize(BuddyManager buddyManager)
+   {
+      this.buddyManager = buddyManager;
+   }
+
+   /**
+    * This method calls the relevant handler on the buddy manager to deal with being removed from a buddy group
+    *
+    * @param ctx invocation context, ignored.
+    * @return null
+    */
+   public Object perform(InvocationContext ctx)
+   {
+      if (buddyManager != null)
+         buddyManager.handleRemoveFromBuddyGroup(groupName);
+      return null;
+   }
+
+   public int getCommandId()
+   {
+      return METHOD_ID;
+   }
+
+   public String getGroupName()
+   {
+      return groupName;
+   }
+
+   public Object[] getParameters()
+   {
+      return new Object[]{groupName};
+   }
+
+   public void setParameters(int commandId, Object[] args)
+   {
+      groupName = (String) args[0];
+   }
+
+   @Override
+   public boolean equals(Object o)
+   {
+      if (this == o) return true;
+      if (o == null || getClass() != o.getClass()) return false;
+
+      RemoveFromBuddyGroupCommand that = (RemoveFromBuddyGroupCommand) o;
+
+      if (groupName != null ? !groupName.equals(that.groupName) : that.groupName != null) return false;
+
+      return true;
+   }
+
+   @Override
+   public int hashCode()
+   {
+      return (groupName != null ? groupName.hashCode() : 0);
+   }
+
+   @Override
+   public String toString()
+   {
+      return "RemoveFromBuddyGroupCommand{" +
+            "buddyManager=" + buddyManager +
+            ", groupName='" + groupName + '\'' +
+            '}';
+   }
+}

Added: core/branches/flat/src/main/java/org/jboss/starobrno/commands/remote/ReplicateCommand.java
===================================================================
--- core/branches/flat/src/main/java/org/jboss/starobrno/commands/remote/ReplicateCommand.java	                        (rev 0)
+++ core/branches/flat/src/main/java/org/jboss/starobrno/commands/remote/ReplicateCommand.java	2008-10-08 11:53:03 UTC (rev 6869)
@@ -0,0 +1,278 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2000 - 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.starobrno.commands.remote;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.jboss.cache.commands.read.GravitateDataCommand;
+import org.jboss.starobrno.commands.ReplicableCommand;
+import org.jboss.starobrno.commands.VisitableCommand;
+import org.jboss.starobrno.context.InvocationContext;
+import org.jboss.starobrno.interceptors.InterceptorChain;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Command that implements cluster replication logic.  Essentially mimics the replicate() and replicateAll() methods
+ * in 2.1.x, we may need to revisit the usefulness of such a command.
+ * <p/>
+ * This is not a {@link org.jboss.cache.commands.VisitableCommand} and hence
+ * not passed up the {@link org.jboss.cache.interceptors.base.CommandInterceptor} chain.
+ * <p/>
+ *
+ * @author Mircea.Markus at jboss.com
+ * @since 2.2
+ */
+public class ReplicateCommand implements ReplicableCommand
+{
+   public static final int SINGLE_METHOD_ID = 13;
+   public static final int MULTIPLE_METHOD_ID = 14;
+
+   private InterceptorChain invoker;
+
+   private static final Log log = LogFactory.getLog(ReplicateCommand.class);
+   private static final boolean trace = log.isTraceEnabled();
+
+   /**
+    * optimisation - rather than constructing a new list each for scenarios where a single modification needs
+    * to be replicated rather use this instance.
+    */
+   private ReplicableCommand singleModification;
+   private List<ReplicableCommand> modifications;
+
+   public ReplicateCommand(List<ReplicableCommand> modifications)
+   {
+      if (modifications != null && modifications.size() == 1)
+      {
+         singleModification = modifications.get(0);
+      }
+      else
+      {
+         this.modifications = modifications;
+      }
+   }
+
+   public ReplicateCommand(ReplicableCommand command)
+   {
+      this.singleModification = command;
+   }
+
+   public ReplicateCommand()
+   {
+   }
+
+   public void initialize(InterceptorChain interceptorChain)
+   {
+      this.invoker = interceptorChain;
+   }
+
+   public void setSingleModification(ReplicableCommand singleModification)
+   {
+      this.singleModification = singleModification;
+   }
+
+   public void setModifications(List<ReplicableCommand> modifications)
+   {
+      if (modifications != null && modifications.size() == 1)
+         singleModification = modifications.get(0);
+      else
+         this.modifications = modifications;
+   }
+
+   /**
+    * Executes commands replicated to the current cache instance by other cache instances.
+    *
+    * @param ctx invocation context, ignored.
+    * @return if this is a single command being processed <b>and</b> it is a {@link org.jboss.cache.commands.read.GravitateDataCommand}, the result of processing this command is returned.  Otherwise, null is returned.
+    * @throws Throwable
+    */
+   public Object perform(InvocationContext ctx) throws Throwable
+   {
+      if (isSingleCommand())
+      {
+         Object retVal = processSingleCommand(singleModification);
+
+         // only send back the result of the execution if it is a data gravitation command.
+         // all other commands don't need to send back return values, there will be an unnecessary overhead of
+         // marshalling results that won't ever be used.
+         if (singleModification instanceof GravitateDataCommand)
+            return retVal;
+         else
+            return null;
+      }
+      for (ReplicableCommand command : modifications) processSingleCommand(command);
+      return null;
+   }
+
+   private Object processSingleCommand(ReplicableCommand cacheCommand)
+         throws Throwable
+   {
+      Object result;
+      try
+      {
+         if (trace) log.trace("Invoking command " + cacheCommand + ", with originLocal flag set to false.");
+
+         if (cacheCommand instanceof VisitableCommand)
+         {
+            Object retVal = invoker.invokeRemote((VisitableCommand) cacheCommand);
+            // we only need to return values for a set of remote calls; not every call.
+            if (returnValueForRemoteCall(cacheCommand))
+            {
+               result = retVal;
+            }
+            else
+            {
+               result = null;
+            }
+         }
+         else
+         {
+            result = cacheCommand.perform(null);
+         }
+      }
+      catch (Throwable ex)
+      {
+         // TODO deal with PFER
+//         if (!(cacheCommand instanceof PutForExternalReadCommand))
+//         {
+         throw ex;
+//         }
+//         else
+//         {
+//            if (trace)
+//               log.trace("Caught an exception, but since this is a putForExternalRead() call, suppressing the exception.  Exception is:", ex);
+//            result = null;
+//         }
+      }
+      return result;
+   }
+
+   private boolean returnValueForRemoteCall(ReplicableCommand cacheCommand)
+   {
+      return cacheCommand instanceof GravitateDataCommand || cacheCommand instanceof ClusteredGetCommand;
+   }
+
+   public int getCommandId()
+   {
+      return isSingleCommand() ? SINGLE_METHOD_ID : MULTIPLE_METHOD_ID;
+   }
+
+   public List<ReplicableCommand> getModifications()
+   {
+      return modifications;
+   }
+
+   public ReplicableCommand getSingleModification()
+   {
+      return singleModification;
+   }
+
+   public Object[] getParameters()
+   {
+      if (isSingleCommand())
+         return new Object[]{singleModification};
+      else
+         return new Object[]{modifications};
+   }
+
+   @SuppressWarnings("unchecked")
+   public void setParameters(int commandId, Object[] args)
+   {
+      if (commandId == SINGLE_METHOD_ID)
+      {
+         singleModification = (ReplicableCommand) args[0];
+      }
+      else
+      {
+         modifications = (List<ReplicableCommand>) args[0];
+      }
+   }
+
+   public boolean isSingleCommand()
+   {
+      return singleModification != null;
+   }
+
+   @Override
+   public boolean equals(Object o)
+   {
+      if (this == o) return true;
+      if (o == null || getClass() != o.getClass()) return false;
+
+      ReplicateCommand that = (ReplicateCommand) o;
+
+      if (modifications != null ? !modifications.equals(that.modifications) : that.modifications != null) return false;
+      if (singleModification != null ? !singleModification.equals(that.singleModification) : that.singleModification != null)
+         return false;
+
+      return true;
+   }
+
+   @Override
+   public int hashCode()
+   {
+      int result;
+      result = (singleModification != null ? singleModification.hashCode() : 0);
+      result = 31 * result + (modifications != null ? modifications.hashCode() : 0);
+      return result;
+   }
+
+   @Override
+   public String toString()
+   {
+      return "ReplicateCommand{" +
+            "cmds=" + (isSingleCommand() ? singleModification : modifications) +
+            '}';
+   }
+
+   /**
+    * Creates a copy of this command, amking a deep copy of any collections but everything else copied shallow.
+    *
+    * @return a copy
+    */
+   public ReplicateCommand copy()
+   {
+      ReplicateCommand clone;
+      clone = new ReplicateCommand();
+      clone.invoker = invoker;
+      clone.modifications = modifications == null ? null : new ArrayList<ReplicableCommand>(modifications);
+      clone.singleModification = singleModification;
+      return clone;
+   }
+
+   public boolean containsCommandType(Class<? extends ReplicableCommand> aClass)
+   {
+      if (isSingleCommand())
+      {
+         return getSingleModification().getClass().equals(aClass);
+      }
+      else
+      {
+         for (ReplicableCommand command : getModifications())
+         {
+            if (command.getClass().equals(aClass)) return true;
+         }
+      }
+      return false;
+   }
+}
\ No newline at end of file

Modified: core/branches/flat/src/main/java/org/jboss/starobrno/commands/tx/AbstractTransactionBoundaryCommand.java
===================================================================
--- core/branches/flat/src/main/java/org/jboss/starobrno/commands/tx/AbstractTransactionBoundaryCommand.java	2008-10-08 11:51:17 UTC (rev 6868)
+++ core/branches/flat/src/main/java/org/jboss/starobrno/commands/tx/AbstractTransactionBoundaryCommand.java	2008-10-08 11:53:03 UTC (rev 6869)
@@ -21,9 +21,9 @@
  */
 package org.jboss.starobrno.commands.tx;
 
-import org.jboss.cache.transaction.GlobalTransaction;
 import org.jboss.starobrno.commands.TransactionBoundaryCommand;
 import org.jboss.starobrno.context.InvocationContext;
+import org.jboss.starobrno.transaction.GlobalTransaction;
 
 /**
  * // TODO: MANIK: Document this

Modified: core/branches/flat/src/main/java/org/jboss/starobrno/commands/tx/CommitCommand.java
===================================================================
--- core/branches/flat/src/main/java/org/jboss/starobrno/commands/tx/CommitCommand.java	2008-10-08 11:51:17 UTC (rev 6868)
+++ core/branches/flat/src/main/java/org/jboss/starobrno/commands/tx/CommitCommand.java	2008-10-08 11:53:03 UTC (rev 6869)
@@ -21,9 +21,9 @@
  */
 package org.jboss.starobrno.commands.tx;
 
-import org.jboss.cache.transaction.GlobalTransaction;
 import org.jboss.starobrno.commands.Visitor;
 import org.jboss.starobrno.context.InvocationContext;
+import org.jboss.starobrno.transaction.GlobalTransaction;
 
 /**
  * // TODO: MANIK: Document this

Modified: core/branches/flat/src/main/java/org/jboss/starobrno/commands/tx/PrepareCommand.java
===================================================================
--- core/branches/flat/src/main/java/org/jboss/starobrno/commands/tx/PrepareCommand.java	2008-10-08 11:51:17 UTC (rev 6868)
+++ core/branches/flat/src/main/java/org/jboss/starobrno/commands/tx/PrepareCommand.java	2008-10-08 11:53:03 UTC (rev 6869)
@@ -21,11 +21,11 @@
  */
 package org.jboss.starobrno.commands.tx;
 
-import org.jboss.cache.commands.WriteCommand;
-import org.jboss.cache.transaction.GlobalTransaction;
 import org.jboss.starobrno.commands.ReplicableCommand;
 import org.jboss.starobrno.commands.Visitor;
+import org.jboss.starobrno.commands.WriteCommand;
 import org.jboss.starobrno.context.InvocationContext;
+import org.jboss.starobrno.transaction.GlobalTransaction;
 import org.jgroups.Address;
 
 import java.util.ArrayList;
@@ -42,11 +42,11 @@
 {
    public static final int METHOD_ID = 10;
 
-   protected List<ReplicableCommand> modifications;
+   protected List<WriteCommand> modifications;
    protected Address localAddress;
    protected boolean onePhaseCommit;
 
-   public PrepareCommand(GlobalTransaction gtx, List<ReplicableCommand> modifications, Address localAddress, boolean onePhaseCommit)
+   public PrepareCommand(GlobalTransaction gtx, List<WriteCommand> modifications, Address localAddress, boolean onePhaseCommit)
    {
       this.gtx = gtx;
       this.modifications = modifications;
@@ -70,7 +70,7 @@
 //      return visitor.visitPrepareCommand(ctx, this);
    }
 
-   public List<ReplicableCommand> getModifications()
+   public List<WriteCommand> getModifications()
    {
       return modifications;
    }
@@ -111,7 +111,7 @@
    public void setParameters(int commandId, Object[] args)
    {
       gtx = (GlobalTransaction) args[0];
-      modifications = (List<ReplicableCommand>) args[1];
+      modifications = (List<WriteCommand>) args[1];
       localAddress = (Address) args[2];
       onePhaseCommit = (Boolean) args[3];
    }
@@ -147,7 +147,7 @@
       PrepareCommand copy = new PrepareCommand();
       copy.gtx = gtx;
       copy.localAddress = localAddress;
-      copy.modifications = modifications == null ? null : new ArrayList<ReplicableCommand>(modifications);
+      copy.modifications = modifications == null ? null : new ArrayList<WriteCommand>(modifications);
       copy.onePhaseCommit = onePhaseCommit;
       return copy;
    }
@@ -165,7 +165,7 @@
 
    public boolean containsModificationType(Class<? extends ReplicableCommand> replicableCommandClass)
    {
-      for (ReplicableCommand mod : getModifications())
+      for (WriteCommand mod : getModifications())
       {
          if (mod.getClass().equals(replicableCommandClass))
          {

Modified: core/branches/flat/src/main/java/org/jboss/starobrno/commands/tx/RollbackCommand.java
===================================================================
--- core/branches/flat/src/main/java/org/jboss/starobrno/commands/tx/RollbackCommand.java	2008-10-08 11:51:17 UTC (rev 6868)
+++ core/branches/flat/src/main/java/org/jboss/starobrno/commands/tx/RollbackCommand.java	2008-10-08 11:53:03 UTC (rev 6869)
@@ -21,9 +21,9 @@
  */
 package org.jboss.starobrno.commands.tx;
 
-import org.jboss.cache.transaction.GlobalTransaction;
 import org.jboss.starobrno.commands.Visitor;
 import org.jboss.starobrno.context.InvocationContext;
+import org.jboss.starobrno.transaction.GlobalTransaction;
 
 /**
  * // TODO: MANIK: Document this

Modified: core/branches/flat/src/main/java/org/jboss/starobrno/context/InvocationContextImpl.java
===================================================================
--- core/branches/flat/src/main/java/org/jboss/starobrno/context/InvocationContextImpl.java	2008-10-08 11:51:17 UTC (rev 6868)
+++ core/branches/flat/src/main/java/org/jboss/starobrno/context/InvocationContextImpl.java	2008-10-08 11:53:03 UTC (rev 6869)
@@ -23,12 +23,12 @@
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
+import org.jboss.cache.config.Option;
+import org.jboss.cache.util.Immutables;
+import org.jboss.starobrno.commands.VisitableCommand;
 import org.jboss.starobrno.mvcc.MVCCEntry;
 import org.jboss.starobrno.transaction.GlobalTransaction;
-import org.jboss.starobrno.commands.VisitableCommand;
-import org.jboss.cache.config.Option;
-import org.jboss.cache.util.Immutables;
-import org.jboss.cache.transaction.TransactionTable;
+import org.jboss.starobrno.transaction.TransactionTable;
 
 import javax.transaction.Transaction;
 import java.util.Collections;

Modified: core/branches/flat/src/main/java/org/jboss/starobrno/context/TransactionContext.java
===================================================================
--- core/branches/flat/src/main/java/org/jboss/starobrno/context/TransactionContext.java	2008-10-08 11:51:17 UTC (rev 6868)
+++ core/branches/flat/src/main/java/org/jboss/starobrno/context/TransactionContext.java	2008-10-08 11:53:03 UTC (rev 6869)
@@ -21,10 +21,9 @@
  */
 package org.jboss.starobrno.context;
 
-import org.jboss.cache.Fqn;
-import org.jboss.cache.commands.WriteCommand;
 import org.jboss.cache.config.Option;
 import org.jboss.cache.interceptors.OrderedSynchronizationHandler;
+import org.jboss.starobrno.commands.WriteCommand;
 
 import javax.transaction.Transaction;
 import java.util.List;
@@ -75,14 +74,14 @@
     * @param fqn fqn that has been removed.
     * @throws NullPointerException if the Fqn is null.
     */
-   void addRemovedNode(Fqn fqn);
+   void addRemovedEntry(Object key);
 
    /**
     * Gets the list of removed nodes.
     *
     * @return list of nodes removed in the current transaction scope.  Note that this method will return an empty list if nothing has been removed.  The list returned is defensively copied.
     */
-   List<Fqn> getRemovedNodes();
+   List<Object> getRemovedEntries();
 
    /**
     * Sets the local transaction to be associated with this transaction context.
@@ -228,12 +227,12 @@
     *
     * @param fqn fqn to add.  Must not be null.
     */
-   void addDummyNodeCreatedByCacheLoader(Fqn fqn);
+   void addDummyEntryCreatedByCacheLoader(Object key);
 
    /**
     * @return a list of uninitialized nodes created by the cache loader, or an empty list.
     */
-   List<Fqn> getDummyNodesCreatedByCacheLoader();
+   List<Object> getDummyEntriesCreatedByCacheLoader();
 
    /**
     * Sets a transaction-scope option override

Modified: core/branches/flat/src/main/java/org/jboss/starobrno/context/TransactionContextImpl.java
===================================================================
--- core/branches/flat/src/main/java/org/jboss/starobrno/context/TransactionContextImpl.java	2008-10-08 11:51:17 UTC (rev 6868)
+++ core/branches/flat/src/main/java/org/jboss/starobrno/context/TransactionContextImpl.java	2008-10-08 11:53:03 UTC (rev 6869)
@@ -21,11 +21,10 @@
  */
 package org.jboss.starobrno.context;
 
-import org.jboss.cache.Fqn;
-import org.jboss.cache.commands.WriteCommand;
 import org.jboss.cache.config.Option;
 import org.jboss.cache.interceptors.OrderedSynchronizationHandler;
 import org.jboss.cache.util.Immutables;
+import org.jboss.starobrno.commands.WriteCommand;
 import org.jboss.starobrno.mvcc.MVCCEntry;
 
 import javax.transaction.RollbackException;
@@ -80,12 +79,12 @@
     * A list of dummy uninitialised nodes created by the cache loader interceptor to load data for a
     * given node in this tx.
     */
-   private List<Fqn> dummyNodesCreatedByCacheLoader;
+   private List<Object> dummyNodesCreatedByCacheLoader;
 
    /**
     * List<Fqn> of nodes that have been removed by the transaction
     */
-   private List<Fqn> removedNodes = null;
+   private List<Object> removedNodes = null;
 
    private final Map<Object, MVCCEntry> lookedUpEntries = new HashMap<Object, MVCCEntry>(8);
 
@@ -195,17 +194,17 @@
    }
 
 
-   public void addRemovedNode(Fqn fqn)
+   public void addRemovedEntry(Object key)
    {
-      if (fqn == null) throw new NullPointerException("Fqn is null!");
-      if (removedNodes == null) removedNodes = new LinkedList<Fqn>();
-      removedNodes.add(fqn);
+      if (key == null) throw new NullPointerException("Key is null!");
+      if (removedNodes == null) removedNodes = new LinkedList<Object>();
+      removedNodes.add(key);
    }
 
-   public List<Fqn> getRemovedNodes()
+   public List<Object> getRemovedEntries()
    {
       if (removedNodes == null) return Collections.emptyList();
-      return new ArrayList<Fqn>(removedNodes);
+      return new ArrayList<Object>(removedNodes);
    }
 
    public void setTransaction(Transaction tx)
@@ -296,14 +295,14 @@
       return sb.toString();
    }
 
-   public void addDummyNodeCreatedByCacheLoader(Fqn fqn)
+   public void addDummyEntryCreatedByCacheLoader(Object key)
    {
       if (dummyNodesCreatedByCacheLoader == null)
-         dummyNodesCreatedByCacheLoader = new LinkedList<Fqn>();
-      dummyNodesCreatedByCacheLoader.add(fqn);
+         dummyNodesCreatedByCacheLoader = new LinkedList<Object>();
+      dummyNodesCreatedByCacheLoader.add(key);
    }
 
-   public List<Fqn> getDummyNodesCreatedByCacheLoader()
+   public List<Object> getDummyEntriesCreatedByCacheLoader()
    {
       if (dummyNodesCreatedByCacheLoader == null) return Collections.emptyList();
       return dummyNodesCreatedByCacheLoader;

Modified: core/branches/flat/src/main/java/org/jboss/starobrno/factories/context/ContextFactory.java
===================================================================
--- core/branches/flat/src/main/java/org/jboss/starobrno/factories/context/ContextFactory.java	2008-10-08 11:51:17 UTC (rev 6868)
+++ core/branches/flat/src/main/java/org/jboss/starobrno/factories/context/ContextFactory.java	2008-10-08 11:53:03 UTC (rev 6869)
@@ -22,7 +22,7 @@
 package org.jboss.starobrno.factories.context;
 
 import org.jboss.starobrno.context.InvocationContext;
-import org.jboss.cache.transaction.TransactionContext;
+import org.jboss.starobrno.context.TransactionContext;
 
 import javax.transaction.RollbackException;
 import javax.transaction.SystemException;

Deleted: core/branches/flat/src/main/java/org/jboss/starobrno/transaction/TransactionContext.java
===================================================================
--- core/branches/flat/src/main/java/org/jboss/starobrno/transaction/TransactionContext.java	2008-10-08 11:51:17 UTC (rev 6868)
+++ core/branches/flat/src/main/java/org/jboss/starobrno/transaction/TransactionContext.java	2008-10-08 11:53:03 UTC (rev 6869)
@@ -1,283 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source.
- * Copyright 2000 - 2008, Red Hat Middleware LLC, and individual contributors
- * as indicated by the @author tags. See the copyright.txt file in the
- * distribution for a full listing of individual contributors.
- *
- * This is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of
- * the License, or (at your option) any later version.
- *
- * This software is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this software; if not, write to the Free
- * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
- */
-package org.jboss.starobrno.transaction;
-
-import org.jboss.cache.Fqn;
-import org.jboss.cache.commands.WriteCommand;
-import org.jboss.cache.config.Option;
-import org.jboss.cache.interceptors.OrderedSynchronizationHandler;
-
-import javax.transaction.Transaction;
-import java.util.List;
-
-/**
- * Captures information pertaining to a specific JTA transaction.
- * <p/>
- * This was a concrete class called TransactionEntry prior to 3.0.
- * <p/>
- *
- * @author Manik Surtani (<a href="mailto:manik at jboss.org">manik at jboss.org</a>)
- * @see org.jboss.cache.InvocationContext
- */
-public interface TransactionContext
-{
-   /**
-    * Adds a modification to the modification list.
-    *
-    * @param command modification
-    */
-   void addModification(WriteCommand command);
-
-   /**
-    * Returns all modifications.  If there are no modifications in this transaction this method will return an empty list.
-    *
-    * @return list of modifications.
-    */
-   List<WriteCommand> getModifications();
-
-   /**
-    * Adds a modification to the local modification list.
-    *
-    * @param command command to add to list.  Should not be null.
-    * @throws NullPointerException if the command to be added is null.
-    */
-   void addLocalModification(WriteCommand command);
-
-   /**
-    * Returns all modifications that have been invoked with the LOCAL cache mode option.  These will also be in the standard modification list.
-    *
-    * @return list of LOCAL modifications, or an empty list.
-    */
-   List<WriteCommand> getLocalModifications();
-
-   /**
-    * Adds the node that has been removed in the scope of the current transaction.
-    *
-    * @param fqn fqn that has been removed.
-    * @throws NullPointerException if the Fqn is null.
-    */
-   void addRemovedNode(Fqn fqn);
-
-   /**
-    * Gets the list of removed nodes.
-    *
-    * @return list of nodes removed in the current transaction scope.  Note that this method will return an empty list if nothing has been removed.  The list returned is defensively copied.
-    */
-   List<Fqn> getRemovedNodes();
-
-   /**
-    * Sets the local transaction to be associated with this transaction context.
-    *
-    * @param tx JTA transaction to associate with.
-    */
-   void setTransaction(Transaction tx);
-
-   /**
-    * Returns a local transaction associated with this context.
-    *
-    * @return a JTA transaction
-    */
-   Transaction getTransaction();
-
-   /**
-    * Adds a lock to the currently maintained collection of locks acquired.
-    * <p/>
-    * Most code could not use this method directly, but use {@link org.jboss.cache.InvocationContext#addLock(Object)} instead,
-    * which would delegate to this method if a transaction is in scope or otherwise use invocation-specific locks.
-    * <p/>
-    * Note that currently (as of 3.0.0) this lock is weakly typed.  This is to allow support for both MVCC (which uses {@link org.jboss.cache.Fqn}s as locks)
-    * as well as legacy Optimistic and Pessimistic Locking schemes (which use {@link org.jboss.cache.lock.NodeLock} as locks).  Once support for
-    * legacy node locking schemes are dropped, this method will be more strongly typed to accept {@link org.jboss.cache.Fqn}.
-    *
-    * @param lock lock to add
-    * @see org.jboss.cache.InvocationContext#addLock(Object)
-    */
-   @SuppressWarnings("unchecked")
-   void addLock(Object lock);
-
-   /**
-    * Removes a lock from the currently maintained collection of locks acquired.
-    * <p/>
-    * Most code could not use this method directly, but use {@link org.jboss.cache.InvocationContext#removeLock(Object)}  instead,
-    * which would delegate to this method if a transaction is in scope or otherwise use invocation-specific locks.
-    * <p/>
-    * Note that currently (as of 3.0.0) this lock is weakly typed.  This is to allow support for both MVCC (which uses {@link org.jboss.cache.Fqn}s as locks)
-    * as well as legacy Optimistic and Pessimistic Locking schemes (which use {@link org.jboss.cache.lock.NodeLock} as locks).  Once support for
-    * legacy node locking schemes are dropped, this method will be more strongly typed to accept {@link org.jboss.cache.Fqn}.
-    *
-    * @param lock lock to remove
-    * @see org.jboss.cache.InvocationContext#removeLock(Object)
-    */
-   @SuppressWarnings("unchecked")
-   void removeLock(Object lock);
-
-   /**
-    * Clears all locks from the currently maintained collection of locks acquired.
-    * <p/>
-    * Most code could not use this method directly, but use {@link org.jboss.cache.InvocationContext#clearLocks()} instead,
-    * which would delegate to this method if a transaction is in scope or otherwise use invocation-specific locks.
-    * <p/>
-    * Note that currently (as of 3.0.0) this lock is weakly typed.  This is to allow support for both MVCC (which uses {@link org.jboss.cache.Fqn}s as locks)
-    * as well as legacy Optimistic and Pessimistic Locking schemes (which use {@link org.jboss.cache.lock.NodeLock} as locks).  Once support for
-    * legacy node locking schemes are dropped, this method will be more strongly typed to accept {@link org.jboss.cache.Fqn}.
-    *
-    * @see org.jboss.cache.InvocationContext#clearLocks()
-    */
-   void clearLocks();
-
-   /**
-    * Adds a List of locks to the currently maintained collection of locks acquired.
-    * <p/>
-    * Most code could not use this method directly, but use {@link org.jboss.cache.InvocationContext#addAllLocks(java.util.List)} instead,
-    * which would delegate to this method if a transaction is in scope or otherwise use invocation-specific locks.
-    * <p/>
-    * Note that currently (as of 3.0.0) this list is unchecked.  This is to allow support for both MVCC (which uses Fqns as locks)
-    * as well as legacy Optimistic and Pessimistic Locking schemes (which use {@link org.jboss.cache.lock.NodeLock} as locks).  Once support for
-    * legacy node locking schemes are dropped, this method will be more strongly typed to accept <tt>List<Fqn></tt>.
-    *
-    * @param newLocks locks to add
-    * @see org.jboss.cache.InvocationContext#addAllLocks(java.util.List)
-    */
-   @SuppressWarnings("unchecked")
-   void addAllLocks(List newLocks);
-
-   /**
-    * Returns an immutable,  defensive copy of the List of locks currently maintained for the transaction.
-    * <p/>
-    * Most code could not use this method directly, but use {@link org.jboss.cache.InvocationContext#getLocks()} instead,
-    * which would delegate to this method if a transaction is in scope or otherwise use invocation-specific locks.
-    * <p/>
-    * Note that currently (as of 3.0.0) this list is unchecked.  This is to allow support for both MVCC (which uses Fqns as locks)
-    * as well as legacy Optimistic and Pessimistic Locking schemes (which use {@link org.jboss.cache.lock.NodeLock} as locks).  Once support for
-    * legacy node locking schemes are dropped, this method will be more strongly typed to return <tt>List<Fqn></tt>.
-    *
-    * @return locks held in current scope.
-    * @see org.jboss.cache.InvocationContext#getLocks()
-    */
-   @SuppressWarnings("unchecked")
-   List getLocks();
-
-   /**
-    * Most code could not use this method directly, but use {@link org.jboss.cache.InvocationContext#hasLock(Object)} ()} instead,
-    * which would delegate to this method if a transaction is in scope or otherwise use invocation-specific locks.
-    *
-    * @param lock lock to test
-    * @return true if the lock being tested is already held in the current scope, false otherwise.
-    */
-   boolean hasLock(Object lock);
-
-   /**
-    * Gets the value of the forceAsyncReplication flag.  Used by ReplicationInterceptor and OptimisticReplicationInterceptor
-    * when dealing with {@link org.jboss.cache.Cache#putForExternalRead(org.jboss.cache.Fqn,Object,Object)} within
-    * a transactional context.
-    *
-    * @return true if the forceAsyncReplication flag is set to true.
-    */
-   boolean isForceAsyncReplication();
-
-   /**
-    * Sets the value of the forceAsyncReplication flag.  Used by ReplicationInterceptor and OptimisticReplicationInterceptor
-    * when dealing with {@link org.jboss.cache.Cache#putForExternalRead(org.jboss.cache.Fqn,Object,Object)} within
-    * a transactional context. Also used by OptimisticReplicationInterceptor when dealing
-    * with {@link org.jboss.cache.config.Option#setForceAsynchronous(boolean)} in a
-    * non-transactional context (i.e. with an implicit transaction).
-    *
-    * @param forceAsyncReplication value of forceAsyncReplication
-    */
-   void setForceAsyncReplication(boolean forceAsyncReplication);
-
-   /**
-    * Gets the value of the forceSyncReplication flag.  Used by ReplicationInterceptor and OptimisticReplicationInterceptor
-    * when dealing with {@link org.jboss.cache.Cache#putForExternalRead(org.jboss.cache.Fqn,Object,Object)} within
-    * a transactional context.
-    *
-    * @return true if the forceAsyncReplication flag is set to true.
-    */
-   boolean isForceSyncReplication();
-
-   /**
-    * Sets the value of the forceSyncReplication flag.  Used by ReplicationInterceptor and OptimisticReplicationInterceptor
-    * when dealing with {@link org.jboss.cache.Cache#putForExternalRead(org.jboss.cache.Fqn,Object,Object)} within
-    * a transactional context.
-    *
-    * @param forceSyncReplication value of forceSyncReplication
-    */
-   void setForceSyncReplication(boolean forceSyncReplication);
-
-   /**
-    * Adds an Fqn to the list of uninitialized nodes created by the cache loader.
-    *
-    * @param fqn fqn to add.  Must not be null.
-    */
-   void addDummyNodeCreatedByCacheLoader(Fqn fqn);
-
-   /**
-    * @return a list of uninitialized nodes created by the cache loader, or an empty list.
-    */
-   List<Fqn> getDummyNodesCreatedByCacheLoader();
-
-   /**
-    * Sets a transaction-scope option override
-    *
-    * @param o option to set
-    */
-   void setOption(Option o);
-
-   /**
-    * Retrieves a transaction scope option override
-    *
-    * @return option
-    */
-   Option getOption();
-
-   /**
-    * @return the ordered sync handler associated with this transaction
-    */
-   OrderedSynchronizationHandler getOrderedSynchronizationHandler();
-
-   /**
-    * Associates an ordered sync handler with this transaction.
-    *
-    * @param orderedSynchronizationHandler to set
-    */
-   void setOrderedSynchronizationHandler(OrderedSynchronizationHandler orderedSynchronizationHandler);
-
-   /**
-    * @return true if modifications were registered.
-    */
-   boolean hasModifications();
-
-   /**
-    * @return true if any modifications have been invoked with cache mode being LOCAL.
-    */
-   boolean hasLocalModifications();
-
-   /**
-    * @return true if either there are modifications or local modifications that are not for replicating.
-    */
-   boolean hasAnyModifications();
-
-   /**
-    * Cleans up internal state, freeing up references.
-    */
-   void reset();
-}
\ No newline at end of file

Added: core/branches/flat/src/main/java/org/jboss/starobrno/transaction/TransactionTable.java
===================================================================
--- core/branches/flat/src/main/java/org/jboss/starobrno/transaction/TransactionTable.java	                        (rev 0)
+++ core/branches/flat/src/main/java/org/jboss/starobrno/transaction/TransactionTable.java	2008-10-08 11:53:03 UTC (rev 6869)
@@ -0,0 +1,427 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2000 - 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.starobrno.transaction;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.jboss.cache.CacheException;
+import org.jboss.cache.InvocationContext;
+import org.jboss.cache.RPCManager;
+import org.jboss.cache.factories.annotations.Inject;
+import org.jboss.cache.factories.annotations.NonVolatile;
+import org.jboss.starobrno.context.TransactionContext;
+import org.jboss.starobrno.factories.context.ContextFactory;
+import org.jgroups.Address;
+
+import javax.transaction.Status;
+import javax.transaction.SystemException;
+import javax.transaction.Transaction;
+import javax.transaction.TransactionManager;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * Maintains the mapping between a local {@link Transaction} and a {@link GlobalTransaction}.
+ * Also stores {@link TransactionContext} instances under a given transaction.
+ *
+ * @author <a href="mailto:bela at jboss.org">Bela Ban</a> Apr 14, 2003
+ * @version $Revision: 6776 $
+ */
+ at NonVolatile
+public class TransactionTable
+{
+   private static final Log log = LogFactory.getLog(TransactionTable.class);
+   private static final boolean trace = log.isTraceEnabled();
+
+   /**
+    * Mapping between local (javax.transaction.Transaction)
+    * and GlobalTransactions.
+    * New: a local TX can have a number of GTXs
+    */
+   protected final Map<Transaction, GlobalTransaction> tx2gtxMap = new ConcurrentHashMap<Transaction, GlobalTransaction>();
+
+   /**
+    * Mappings between GlobalTransactions and modifications.
+    */
+   protected final Map<GlobalTransaction, TransactionContext> gtx2ContextMap = new ConcurrentHashMap<GlobalTransaction, TransactionContext>();
+
+   protected final Map<GlobalTransaction, Transaction> gtx2TxMap = new ConcurrentHashMap<GlobalTransaction, Transaction>();
+
+   private TransactionManager transactionManager = null;
+
+   private RPCManager rpcManager;
+
+   private ContextFactory contextFactory;
+
+   @Inject
+   public void initialize(TransactionManager transactionManager, RPCManager rpcManager, ContextFactory contextFactory)
+   {
+      this.transactionManager = transactionManager;
+      this.rpcManager = rpcManager;
+      this.contextFactory = contextFactory;
+   }
+
+   /**
+    * Returns the number of local transactions.
+    */
+   public int getNumLocalTransactions()
+   {
+      return tx2gtxMap.size();
+   }
+
+   /**
+    * Returns the number of global transactions.
+    */
+   public int getNumGlobalTransactions()
+   {
+      return gtx2ContextMap.size();
+   }
+
+   /**
+    * Returns the global transaction associated with the local transaction.
+    * Returns null if tx is null or it was not found.
+    */
+   public GlobalTransaction get(Transaction tx)
+   {
+      if (tx == null)
+         return null;
+      return tx2gtxMap.get(tx);
+   }
+
+   /**
+    * Returns the local transaction associated with a GlobalTransaction.
+    *
+    * @param gtx The GlobalTransaction
+    * @return Transaction. The local transaction associated with a given
+    *         GlobalTransaction). This will be null if no local transaction is
+    *         associated with a given GTX
+    */
+   public Transaction getLocalTransaction(GlobalTransaction gtx)
+   {
+      if (gtx == null) return null;
+      return gtx2TxMap.get(gtx);
+   }
+
+   /**
+    * If assers exists is true and the coresponding local transaction is null an IllegalStateExcetpion is being thrown.
+    */
+   public Transaction getLocalTransaction(GlobalTransaction gtx, boolean assertExists)
+   {
+      Transaction ltx = getLocalTransaction(gtx);
+      if (!assertExists)
+      {
+         return ltx;
+      }
+      if (ltx != null)
+      {
+         if (log.isDebugEnabled()) log.debug("Found local TX=" + ltx + ", global TX=" + gtx);
+         return ltx;
+      }
+      else
+      {
+         throw new IllegalStateException(" found no local TX for global TX " + gtx);
+      }
+   }
+
+   /**
+    * Associates the global transaction with the local transaction.
+    */
+   public void put(Transaction tx, GlobalTransaction gtx)
+   {
+      if (tx == null)
+      {
+         log.error("key (Transaction) is null");
+         return;
+      }
+      tx2gtxMap.put(tx, gtx);
+      gtx2TxMap.put(gtx, tx);
+   }
+
+   /**
+    * Returns the local transaction entry for the global transaction.
+    * Returns null if tx is null or it was not found.
+    */
+   public TransactionContext get(GlobalTransaction gtx)
+   {
+      return gtx != null ? gtx2ContextMap.get(gtx) : null;
+   }
+
+   /**
+    * Associates the global transaction with a transaction context.
+    */
+   public void put(GlobalTransaction tx, TransactionContext transactionContext)
+   {
+      if (tx == null)
+      {
+         log.error("key (GlobalTransaction) is null");
+         return;
+      }
+      gtx2ContextMap.put(tx, transactionContext);
+   }
+
+   /**
+    * Removes a global transation, returns the old transaction entry.
+    */
+   public TransactionContext remove(GlobalTransaction tx)
+   {
+      if (tx == null) return null;
+      gtx2TxMap.remove(tx);
+      return gtx2ContextMap.remove(tx);
+   }
+
+   /**
+    * Removes a local transation, returns the global transaction entry.
+    */
+   public GlobalTransaction remove(Transaction tx)
+   {
+      if (tx == null)
+         return null;
+      return tx2gtxMap.remove(tx);
+   }
+
+   public void remove(GlobalTransaction gtx, Transaction tx)
+   {
+      gtx2TxMap.remove(gtx);
+      gtx2ContextMap.remove(gtx);
+      tx2gtxMap.remove(tx);
+   }
+
+   /**
+    * Returns summary debug information.
+    */
+   @Override
+   public String toString()
+   {
+      StringBuilder sb = new StringBuilder();
+      sb.append(tx2gtxMap.size()).append(" mappings, ");
+      sb.append(gtx2ContextMap.size()).append(" transactions");
+      return sb.toString();
+   }
+
+   /**
+    * Returns detailed debug information.
+    */
+   public String toString(boolean printDetails)
+   {
+      if (!printDetails)
+         return toString();
+      StringBuilder sb = new StringBuilder();
+      sb.append("LocalTransactions: ").append(tx2gtxMap.size()).append("\n");
+      sb.append("GlobalTransactions: ").append(gtx2ContextMap.size()).append("\n");
+      sb.append("tx2gtxMap:\n");
+      for (Map.Entry<Transaction, GlobalTransaction> entry : tx2gtxMap.entrySet())
+      {
+         sb.append(entry.getKey()).append(": ").append(entry.getValue()).append("\n");
+      }
+      sb.append("gtx2EntryMap:\n");
+      for (Map.Entry<GlobalTransaction, TransactionContext> transactionContextEntry : gtx2ContextMap.entrySet())
+      {
+         sb.append(transactionContextEntry.getKey()).append(": ").append(transactionContextEntry.getValue()).append("\n");
+      }
+      return sb.toString();
+   }
+
+   /**
+    * Returns the transaction associated with the current thread.
+    * If a local transaction exists, but doesn't yet have a mapping to a
+    * GlobalTransaction, a new GlobalTransaction will be created and mapped to
+    * the local transaction.  Note that if a local transaction exists, but is
+    * not ACTIVE or PREPARING, null is returned.
+    *
+    * @return A GlobalTransaction, or null if no (local) transaction was associated with the current thread
+    */
+   public GlobalTransaction getCurrentTransaction()
+   {
+      return getCurrentTransaction(true);
+   }
+
+
+   /**
+    * Returns the transaction associated with the thread; optionally creating
+    * it if is does not exist.
+    */
+   public GlobalTransaction getCurrentTransaction(boolean createIfNotExists)
+   {
+      Transaction tx;
+
+      if ((tx = getLocalTransaction()) == null)
+      {// no transaction is associated with the current thread
+         return null;
+      }
+
+      if (!isValid(tx))
+      {// we got a non-null transaction, but it is not active anymore
+         int status = -1;
+         try
+         {
+            status = tx.getStatus();
+         }
+         catch (SystemException e)
+         {
+         }
+
+         // JBCACHE-982 -- don't complain if COMMITTED
+         if (status != Status.STATUS_COMMITTED)
+         {
+            log.warn("status is " + status + " (not ACTIVE or PREPARING); returning null)");
+         }
+         else
+         {
+            log.trace("status is COMMITTED; returning null");
+         }
+
+         return null;
+      }
+
+      return getCurrentTransaction(tx, createIfNotExists);
+   }
+
+   /**
+    * Returns the transaction associated with the current thread. We get the
+    * initial context and a reference to the TransactionManager to get the
+    * transaction. This method is used by {@link #getCurrentTransaction()}
+    */
+   protected Transaction getLocalTransaction()
+   {
+      if (transactionManager == null)
+      {
+         return null;
+      }
+      try
+      {
+         return transactionManager.getTransaction();
+      }
+      catch (Throwable t)
+      {
+         return null;
+      }
+   }
+
+   /**
+    * Returns true if transaction is ACTIVE, false otherwise
+    */
+   public static boolean isActive(Transaction tx)
+   {
+      if (tx == null) return false;
+      int status;
+      try
+      {
+         status = tx.getStatus();
+         return status == Status.STATUS_ACTIVE;
+      }
+      catch (SystemException e)
+      {
+         return false;
+      }
+   }
+
+   /**
+    * Returns true if transaction is PREPARING, false otherwise
+    */
+   public static boolean isPreparing(Transaction tx)
+   {
+      if (tx == null) return false;
+      int status;
+      try
+      {
+         status = tx.getStatus();
+         return status == Status.STATUS_PREPARING;
+      }
+      catch (SystemException e)
+      {
+         return false;
+      }
+   }
+
+   /**
+    * Return s true of tx's status is ACTIVE or PREPARING
+    *
+    * @param tx
+    * @return true if the tx is active or preparing
+    */
+   public static boolean isValid(Transaction tx)
+   {
+      return isActive(tx) || isPreparing(tx);
+   }
+
+   /**
+    * Tests whether the caller is in a valid transaction.  If not, will throw a CacheException.
+    */
+   public static void assertTransactionValid(InvocationContext ctx)
+   {
+      Transaction tx = ctx.getTransaction();
+      if (!isValid(tx)) try
+      {
+         throw new CacheException("Invalid transaction " + tx + ", status = " + (tx == null ? null : tx.getStatus()));
+      }
+      catch (SystemException e)
+      {
+         throw new CacheException("Exception trying to analyse status of transaction " + tx, e);
+      }
+   }
+
+
+   /**
+    * Returns the global transaction for this local transaction.
+    */
+   public GlobalTransaction getCurrentTransaction(Transaction tx)
+   {
+      return getCurrentTransaction(tx, true);
+   }
+
+   /**
+    * Returns the global transaction for this local transaction.
+    *
+    * @param createIfNotExists if true, if a global transaction is not found; one is created
+    */
+   public GlobalTransaction getCurrentTransaction(Transaction tx, boolean createIfNotExists)
+   {
+      // removed synchronization on txTable because underlying implementation is thread safe
+      // and JTA spec (section 3.4.3 Thread of Control, par 2) says that only one thread may
+      // operate on the transaction at one time so no concern about 2 threads trying to call
+      // this method for the same Transaction instance at the same time
+      //
+      GlobalTransaction gtx = get(tx);
+      if (gtx == null && createIfNotExists)
+      {
+         Address addr = rpcManager.getLocalAddress();
+         gtx = GlobalTransaction.create(addr);
+         put(tx, gtx);
+         TransactionContext transactionContext;
+         try
+         {
+            transactionContext = contextFactory.createTransactionContext(tx);
+         }
+         catch (Exception e)
+         {
+            throw new CacheException("Unable to create a transaction entry!", e);
+         }
+
+         put(gtx, transactionContext);
+         if (trace)
+         {
+            log.trace("created new GTX: " + gtx + ", local TX=" + tx);
+         }
+      }
+      return gtx;
+   }
+}




More information about the jbosscache-commits mailing list