[jboss-cvs] JBossAS SVN: r71287 - in projects/ejb3/branches/cluster-dev/ejb3-cache/src: main/java/org/jboss/ejb3/cache/impl/factory and 6 other directories.

jboss-cvs-commits at lists.jboss.org jboss-cvs-commits at lists.jboss.org
Wed Mar 26 01:00:01 EDT 2008


Author: bstansberry at jboss.com
Date: 2008-03-26 01:00:01 -0400 (Wed, 26 Mar 2008)
New Revision: 71287

Added:
   projects/ejb3/branches/cluster-dev/ejb3-cache/src/main/java/org/jboss/ejb3/cache/spi/BackingCacheLifecycleListener.java
   projects/ejb3/branches/cluster-dev/ejb3-cache/src/main/java/org/jboss/ejb3/cache/spi/GroupCompatibilityChecker.java
   projects/ejb3/branches/cluster-dev/ejb3-cache/src/main/java/org/jboss/ejb3/cache/spi/impl/AbstractBackingCache.java
Removed:
   projects/ejb3/branches/cluster-dev/ejb3-cache/src/test/java/org/jboss/ejb3/test/cache/distributed/SharedObject.java
Modified:
   projects/ejb3/branches/cluster-dev/ejb3-cache/src/main/java/org/jboss/ejb3/cache/impl/backing/GroupAwareBackingCacheImpl.java
   projects/ejb3/branches/cluster-dev/ejb3-cache/src/main/java/org/jboss/ejb3/cache/impl/backing/NonPassivatingBackingCacheImpl.java
   projects/ejb3/branches/cluster-dev/ejb3-cache/src/main/java/org/jboss/ejb3/cache/impl/backing/PassivatingBackingCacheImpl.java
   projects/ejb3/branches/cluster-dev/ejb3-cache/src/main/java/org/jboss/ejb3/cache/impl/backing/SerializationGroupImpl.java
   projects/ejb3/branches/cluster-dev/ejb3-cache/src/main/java/org/jboss/ejb3/cache/impl/backing/SerializationGroupMemberContainer.java
   projects/ejb3/branches/cluster-dev/ejb3-cache/src/main/java/org/jboss/ejb3/cache/impl/backing/SimplePassivatingIntegratedObjectStore.java
   projects/ejb3/branches/cluster-dev/ejb3-cache/src/main/java/org/jboss/ejb3/cache/impl/factory/GroupAwareCacheFactory.java
   projects/ejb3/branches/cluster-dev/ejb3-cache/src/main/java/org/jboss/ejb3/cache/impl/factory/NonPassivatingCacheFactory.java
   projects/ejb3/branches/cluster-dev/ejb3-cache/src/main/java/org/jboss/ejb3/cache/spi/BackingCache.java
   projects/ejb3/branches/cluster-dev/ejb3-cache/src/main/java/org/jboss/ejb3/cache/spi/GroupAwareBackingCache.java
   projects/ejb3/branches/cluster-dev/ejb3-cache/src/main/java/org/jboss/ejb3/cache/spi/IntegratedObjectStore.java
   projects/ejb3/branches/cluster-dev/ejb3-cache/src/main/java/org/jboss/ejb3/cache/spi/PassivatingBackingCache.java
   projects/ejb3/branches/cluster-dev/ejb3-cache/src/main/java/org/jboss/ejb3/cache/spi/PassivatingIntegratedObjectStore.java
   projects/ejb3/branches/cluster-dev/ejb3-cache/src/main/java/org/jboss/ejb3/cache/spi/impl/AbstractPassivatingIntegratedObjectStore.java
   projects/ejb3/branches/cluster-dev/ejb3-cache/src/test/java/org/jboss/ejb3/test/cache/distributed/GroupedPassivatingUnitTestCase.java
   projects/ejb3/branches/cluster-dev/ejb3-cache/src/test/java/org/jboss/ejb3/test/cache/distributed/MockClusterMember.java
   projects/ejb3/branches/cluster-dev/ejb3-cache/src/test/java/org/jboss/ejb3/test/cache/distributed/MockIntegratedObjectStoreSource.java
   projects/ejb3/branches/cluster-dev/ejb3-cache/src/test/java/org/jboss/ejb3/test/cache/distributed/MockJBCIntegratedObjectStore.java
   projects/ejb3/branches/cluster-dev/ejb3-cache/src/test/java/org/jboss/ejb3/test/cache/impl/backing/PassivatingBackingCacheImplUnitTestCase.java
   projects/ejb3/branches/cluster-dev/ejb3-cache/src/test/java/org/jboss/ejb3/test/cache/integrated/Ejb3CacheTestCaseBase.java
   projects/ejb3/branches/cluster-dev/ejb3-cache/src/test/java/org/jboss/ejb3/test/cache/mock/MockEjb3System.java
Log:
[EJBTHREE-1026] Group cache lifecycle and compatibility checking

Modified: projects/ejb3/branches/cluster-dev/ejb3-cache/src/main/java/org/jboss/ejb3/cache/impl/backing/GroupAwareBackingCacheImpl.java
===================================================================
--- projects/ejb3/branches/cluster-dev/ejb3-cache/src/main/java/org/jboss/ejb3/cache/impl/backing/GroupAwareBackingCacheImpl.java	2008-03-26 04:46:40 UTC (rev 71286)
+++ projects/ejb3/branches/cluster-dev/ejb3-cache/src/main/java/org/jboss/ejb3/cache/impl/backing/GroupAwareBackingCacheImpl.java	2008-03-26 05:00:01 UTC (rev 71287)
@@ -40,9 +40,12 @@
    /**
     * Cache that's managing the SerializationGroup
     */
-   private PassivatingBackingCache<C, SerializationGroup<C>> groupCache;
+   private final PassivatingBackingCache<C, SerializationGroup<C>> groupCache;
    
-   private SerializationGroupMemberContainer<C> memberContainer;
+   /**
+    * Container for the group members.
+    */
+   private final SerializationGroupMemberContainer<C> memberContainer;
    
    /**
     * Creates a new GroupAwareCacheImpl.
@@ -54,10 +57,12 @@
                                      PassivatingBackingCache<C, SerializationGroup<C>> groupCache)
    {
       super(memberContainer, memberContainer, memberContainer);
+
       assert groupCache != null : "groupCache is null";
       assert groupCache.isClustered() == memberContainer.isClustered(): "incompatible clustering support between groupCache and passivationManager";
-
+      
       this.groupCache = groupCache;
+      this.memberContainer = memberContainer;
    }
    
    public SerializationGroup<C> createGroup()
@@ -76,10 +81,9 @@
             throw new IllegalStateException("object " + key + " is already associated with passivation group " + entry.getGroup());
          
          // Validate we share a common groupCache with the group
-         if (groupCache != group.getGroupCache())
-            throw new IllegalStateException(obj + " and " + group + " use different group caches");
+         if (!memberContainer.isCompatibleWith(group))
+            throw new IllegalStateException(obj + " and " + group + " are incompatible");         
          
-         
          entry.setGroup(group);
          entry.getGroup().addMember(entry);
       }
@@ -117,6 +121,4 @@
       }
    }
    
-   
-   
 }

Modified: projects/ejb3/branches/cluster-dev/ejb3-cache/src/main/java/org/jboss/ejb3/cache/impl/backing/NonPassivatingBackingCacheImpl.java
===================================================================
--- projects/ejb3/branches/cluster-dev/ejb3-cache/src/main/java/org/jboss/ejb3/cache/impl/backing/NonPassivatingBackingCacheImpl.java	2008-03-26 04:46:40 UTC (rev 71286)
+++ projects/ejb3/branches/cluster-dev/ejb3-cache/src/main/java/org/jboss/ejb3/cache/impl/backing/NonPassivatingBackingCacheImpl.java	2008-03-26 05:00:01 UTC (rev 71287)
@@ -32,8 +32,9 @@
 import org.jboss.ejb3.cache.api.StatefulObjectFactory;
 import org.jboss.ejb3.cache.spi.BackingCache;
 import org.jboss.ejb3.cache.spi.PassivationExpirationProcessor;
+import org.jboss.ejb3.cache.spi.BackingCacheLifecycleListener.LifecycleState;
+import org.jboss.ejb3.cache.spi.impl.AbstractBackingCache;
 import org.jboss.ejb3.cache.spi.impl.PassivationExpirationRunner;
-import org.jboss.logging.Logger;
 
 /**
  * Simple {@link BackingCache} that doesn't handle passivation (although
@@ -46,23 +47,25 @@
  * @version $Revision: $
  */
 public class NonPassivatingBackingCacheImpl<C extends CacheItem> 
+   extends AbstractBackingCache<C> 
    implements BackingCache<C, NonPassivatingBackingCacheEntry<C>>, PassivationExpirationProcessor
 {
-   private static final Logger log = Logger.getLogger(NonPassivatingBackingCacheImpl.class);
-   
-   private StatefulObjectFactory<C> factory;
-   private Map<Object, NonPassivatingBackingCacheEntry<C>> cache;
-   private String name;
+   private final StatefulObjectFactory<C> factory;
+   private final Map<Object, NonPassivatingBackingCacheEntry<C>> cache;
+   private final String name;
    private long interval;
    private int expirationTimeSeconds;   
    private PassivationExpirationRunner sessionTimeoutRunner;
    private boolean stopped = true;
    
-   public NonPassivatingBackingCacheImpl(StatefulObjectFactory<C> factory)
+   public NonPassivatingBackingCacheImpl(StatefulObjectFactory<C> factory, String name)
    {
-      assert factory != null;
+      assert factory != null : "factory is null";
+      assert name != null : "name is null";
       
       this.factory = factory;
+      this.name = name;
+      
       this.cache = new ConcurrentHashMap<Object, NonPassivatingBackingCacheEntry<C>>();
    }
    
@@ -120,34 +123,56 @@
 
    public void start()
    {
-      if (interval > 0)
+      notifyLifecycleListeners(LifecycleState.STARTING);
+      try
       {
-         if (sessionTimeoutRunner == null)
+         if (interval > 0)
          {
-            assert name != null : "name has not been set";
-            String timerName = "PassivationExpirationTimer-" + name;
-            sessionTimeoutRunner = new PassivationExpirationRunner(this, timerName, interval);
-         }
-         sessionTimeoutRunner.start();
-      }     
-      
-      stopped = false;
-      
-      log.debug("Started " + name);
+            if (sessionTimeoutRunner == null)
+            {
+               assert name != null : "name has not been set";
+               String timerName = "PassivationExpirationTimer-" + name;
+               sessionTimeoutRunner = new PassivationExpirationRunner(this, timerName, interval);
+            }
+            sessionTimeoutRunner.start();
+         }     
+         
+         stopped = false;
+         
+         notifyLifecycleListeners(LifecycleState.STARTED);
+         
+         log.debug("Started " + name);
+      }
+      catch (RuntimeException e)
+      {
+         notifyLifecycleListeners(LifecycleState.FAILED);
+         throw e;
+      }
    }
 
    public void stop()
    {
-      if (sessionTimeoutRunner != null)
+      notifyLifecycleListeners(LifecycleState.STOPPING);
+      try
       {
-         sessionTimeoutRunner.stop();
-      }      
-      
-      stopped = true;
-      
-      log.debug("Stopped " + name);
-   }
-
+         if (sessionTimeoutRunner != null)
+         {
+            sessionTimeoutRunner.stop();
+         }      
+         
+         stopped = true;
+         
+         notifyLifecycleListeners(LifecycleState.STOPPED);
+         
+         log.debug("Stopped " + name);
+      }
+      catch (RuntimeException e)
+      {
+         notifyLifecycleListeners(LifecycleState.FAILED);
+         throw e;
+      }
+   }  
+   
    public long getInterval()
    {
       return interval;
@@ -163,11 +188,6 @@
       return name;
    }
 
-   public void setName(String name)
-   {
-      this.name = name;
-   }
-
    public int getExpirationTimeSeconds()
    {
       return expirationTimeSeconds;
@@ -211,5 +231,4 @@
       }      
    }
    
-   
 }

Modified: projects/ejb3/branches/cluster-dev/ejb3-cache/src/main/java/org/jboss/ejb3/cache/impl/backing/PassivatingBackingCacheImpl.java
===================================================================
--- projects/ejb3/branches/cluster-dev/ejb3-cache/src/main/java/org/jboss/ejb3/cache/impl/backing/PassivatingBackingCacheImpl.java	2008-03-26 04:46:40 UTC (rev 71286)
+++ projects/ejb3/branches/cluster-dev/ejb3-cache/src/main/java/org/jboss/ejb3/cache/impl/backing/PassivatingBackingCacheImpl.java	2008-03-26 05:00:01 UTC (rev 71287)
@@ -28,9 +28,12 @@
 import org.jboss.ejb3.cache.api.CacheItem;
 import org.jboss.ejb3.cache.api.PassivationManager;
 import org.jboss.ejb3.cache.api.StatefulObjectFactory;
+import org.jboss.ejb3.cache.spi.GroupCompatibilityChecker;
 import org.jboss.ejb3.cache.spi.PassivatingBackingCache;
 import org.jboss.ejb3.cache.spi.PassivatingBackingCacheEntry;
 import org.jboss.ejb3.cache.spi.PassivatingIntegratedObjectStore;
+import org.jboss.ejb3.cache.spi.BackingCacheLifecycleListener.LifecycleState;
+import org.jboss.ejb3.cache.spi.impl.AbstractBackingCache;
 import org.jboss.logging.Logger;
 
 /**
@@ -41,6 +44,7 @@
  * @version $Revision: 65339 $
  */
 public class PassivatingBackingCacheImpl<C extends CacheItem, T extends PassivatingBackingCacheEntry<C>>
+   extends AbstractBackingCache<C>  
    implements PassivatingBackingCache<C, T>
 {
    protected final Logger log = Logger.getLogger(getClass().getName());
@@ -206,11 +210,39 @@
    
    public void start()
    {
-      store.start();
+      notifyLifecycleListeners(LifecycleState.STARTING);
+      try
+      {
+         store.start();
+         
+         notifyLifecycleListeners(LifecycleState.STARTED);
+      }
+      catch (RuntimeException e)
+      {
+         notifyLifecycleListeners(LifecycleState.FAILED);
+         throw e;
+      }
    }
 
    public void stop()
    {
-      store.stop();
+      notifyLifecycleListeners(LifecycleState.STOPPING);
+      try
+      {
+         store.stop();
+         
+         notifyLifecycleListeners(LifecycleState.STOPPED);
+      }
+      catch (RuntimeException e)
+      {
+         notifyLifecycleListeners(LifecycleState.FAILED);
+         throw e;
+      }
    }
+
+   public GroupCompatibilityChecker getCompatibilityChecker()
+   {
+      return store;
+   }
+   
 }

Modified: projects/ejb3/branches/cluster-dev/ejb3-cache/src/main/java/org/jboss/ejb3/cache/impl/backing/SerializationGroupImpl.java
===================================================================
--- projects/ejb3/branches/cluster-dev/ejb3-cache/src/main/java/org/jboss/ejb3/cache/impl/backing/SerializationGroupImpl.java	2008-03-26 04:46:40 UTC (rev 71286)
+++ projects/ejb3/branches/cluster-dev/ejb3-cache/src/main/java/org/jboss/ejb3/cache/impl/backing/SerializationGroupImpl.java	2008-03-26 05:00:01 UTC (rev 71287)
@@ -133,9 +133,6 @@
     * 
     * @throws IllegalStateException if <code>member</code> was previously
     *                               added to the group
-    * @throws IllegalArgumentException if the 
-    *   {@link SerializationGroupMember#isClustered() member's support for clustering}
-    *   does not match {@link #isClustered() our own}.
     */
    public void addMember(SerializationGroupMember<T> member)
    {

Modified: projects/ejb3/branches/cluster-dev/ejb3-cache/src/main/java/org/jboss/ejb3/cache/impl/backing/SerializationGroupMemberContainer.java
===================================================================
--- projects/ejb3/branches/cluster-dev/ejb3-cache/src/main/java/org/jboss/ejb3/cache/impl/backing/SerializationGroupMemberContainer.java	2008-03-26 04:46:40 UTC (rev 71286)
+++ projects/ejb3/branches/cluster-dev/ejb3-cache/src/main/java/org/jboss/ejb3/cache/impl/backing/SerializationGroupMemberContainer.java	2008-03-26 05:00:01 UTC (rev 71287)
@@ -28,6 +28,7 @@
 import org.jboss.ejb3.cache.api.PassivationManager;
 import org.jboss.ejb3.cache.api.StatefulObjectFactory;
 import org.jboss.ejb3.cache.spi.GroupAwareBackingCache;
+import org.jboss.ejb3.cache.spi.GroupCompatibilityChecker;
 import org.jboss.ejb3.cache.spi.PassivatingBackingCache;
 import org.jboss.ejb3.cache.spi.PassivatingIntegratedObjectStore;
 import org.jboss.ejb3.cache.spi.SerializationGroup;
@@ -347,5 +348,21 @@
    public void processPassivationExpiration()
    {         
       store.processPassivationExpiration();
-   }      
+   }   
+   
+   public boolean isCompatibleWith(SerializationGroup<C> group)
+   {
+      PassivatingBackingCache<C, SerializationGroup<C>> otherCache = group.getGroupCache();
+      if (otherCache != null)
+         return store.isCompatibleWith(otherCache.getCompatibilityChecker());
+      else
+         return false;
+   }
+
+   public boolean isCompatibleWith(GroupCompatibilityChecker other)
+   {
+      return store.isCompatibleWith(other);
+   }
+   
+   
 }

Modified: projects/ejb3/branches/cluster-dev/ejb3-cache/src/main/java/org/jboss/ejb3/cache/impl/backing/SimplePassivatingIntegratedObjectStore.java
===================================================================
--- projects/ejb3/branches/cluster-dev/ejb3-cache/src/main/java/org/jboss/ejb3/cache/impl/backing/SimplePassivatingIntegratedObjectStore.java	2008-03-26 04:46:40 UTC (rev 71286)
+++ projects/ejb3/branches/cluster-dev/ejb3-cache/src/main/java/org/jboss/ejb3/cache/impl/backing/SimplePassivatingIntegratedObjectStore.java	2008-03-26 05:00:01 UTC (rev 71287)
@@ -30,6 +30,7 @@
 
 import org.jboss.ejb3.annotation.CacheConfig;
 import org.jboss.ejb3.cache.api.CacheItem;
+import org.jboss.ejb3.cache.spi.GroupCompatibilityChecker;
 import org.jboss.ejb3.cache.spi.ObjectStore;
 import org.jboss.ejb3.cache.spi.PassivatingBackingCacheEntry;
 import org.jboss.ejb3.cache.spi.PassivatingIntegratedObjectStore;
@@ -130,20 +131,30 @@
       return entry;
    } 
 
-   public void start()
+   protected void internalStart()
    {
       store.start();
       
-      super.start();
+      super.internalStart();
    }
 
-   public void stop()
+   protected void internalStop()
    {      
       store.stop();
       
-      super.stop();
+      super.internalStop();
    }
 
+   @SuppressWarnings("unchecked")
+   public boolean isCompatibleWith(GroupCompatibilityChecker other)
+   {
+      if (other instanceof PassivatingIntegratedObjectStore)
+      {
+         return ((PassivatingIntegratedObjectStore) other).isClustered() == false;
+      }
+      return false;
+   }
+
    // -------------------------------  AbstractPassivatingIntegratedObjectStore
 
    @Override

Modified: projects/ejb3/branches/cluster-dev/ejb3-cache/src/main/java/org/jboss/ejb3/cache/impl/factory/GroupAwareCacheFactory.java
===================================================================
--- projects/ejb3/branches/cluster-dev/ejb3-cache/src/main/java/org/jboss/ejb3/cache/impl/factory/GroupAwareCacheFactory.java	2008-03-26 04:46:40 UTC (rev 71286)
+++ projects/ejb3/branches/cluster-dev/ejb3-cache/src/main/java/org/jboss/ejb3/cache/impl/factory/GroupAwareCacheFactory.java	2008-03-26 05:00:01 UTC (rev 71287)
@@ -36,6 +36,7 @@
 import org.jboss.ejb3.cache.impl.backing.PassivatingBackingCacheImpl;
 import org.jboss.ejb3.cache.impl.backing.SerializationGroupContainer;
 import org.jboss.ejb3.cache.impl.backing.SerializationGroupMemberContainer;
+import org.jboss.ejb3.cache.spi.BackingCacheLifecycleListener;
 import org.jboss.ejb3.cache.spi.GroupAwareBackingCache;
 import org.jboss.ejb3.cache.spi.IntegratedObjectStoreSource;
 import org.jboss.ejb3.cache.spi.PassivatingBackingCache;
@@ -56,7 +57,7 @@
 public class GroupAwareCacheFactory<T extends CacheItem> 
    extends AbstractStatefulCacheFactory<T>
 {
-   private final Map<String, PassivatingBackingCache<T, SerializationGroup<T>>> groupCaches;
+   private final Map<String, GroupCacheTracker> groupCaches;
    private final IntegratedObjectStoreSource<T> storeSource;
    
    /**
@@ -68,26 +69,44 @@
       assert storeSource != null : "storeSource is null";
       
       this.storeSource = storeSource;
-      this.groupCaches = new HashMap<String, PassivatingBackingCache<T, SerializationGroup<T>>>();
+      this.groupCaches = new HashMap<String, GroupCacheTracker>();
    }
 
    // --------------------------------------------------- StatefulCacheFactory
    
    public Cache<T> createCache(String containerName, 
                                StatefulObjectFactory<T> factory, 
-                               PassivationManager<T> passivationManager, CacheConfig cacheConfig)
+                               PassivationManager<T> passivationManager, 
+                               CacheConfig cacheConfig)
    {
+      // Figure out our cache's name
       String configName = getCacheConfigName(cacheConfig);
       
-      PassivatingBackingCache<T, SerializationGroup<T>> groupCache = groupCaches.get(configName);
-      if (groupCache == null)
+      // Create/find the cache for SerializationGroup that the container
+      // may be associated with
+      PassivatingBackingCache<T, SerializationGroup<T>> groupCache = null;
+      GroupMemberCacheLifecycleListener listener = null;
+      
+      synchronized (groupCaches)
       {
-         groupCache = createGroupCache(containerName, configName, cacheConfig);
-         groupCaches.put(configName, groupCache);
+         GroupCacheTracker tracker = groupCaches.get(configName);
+         if (tracker == null)
+         {
+            groupCache = createGroupCache(containerName, configName, cacheConfig);
+            listener = new GroupMemberCacheLifecycleListener(configName);
+            groupCaches.put(configName, new GroupCacheTracker(groupCache, listener));
+         }
+         else
+         {
+            groupCache = tracker.groupCache;
+            listener = tracker.listener;
+         }
       }
       
+      // Create the store for SerializationGroupMembers from the container
       PassivatingIntegratedObjectStore<T, SerializationGroupMember<T>> store = 
-         storeSource.createIntegratedObjectStore(containerName, configName, cacheConfig, getTransactionManager(), getSynchronizationCoordinator());
+         storeSource.createIntegratedObjectStore(containerName, configName, cacheConfig, 
+                                                 getTransactionManager(), getSynchronizationCoordinator());
       
       // Make sure passivation/expiration occurs periodically
       if (store.getInterval() < 1)
@@ -105,12 +124,16 @@
       }
       // else the store is configured to manage processing itself
       
+      // Set up the backing cache with the store and group cache
       SerializationGroupMemberContainer<T> memberContainer = 
-         new SerializationGroupMemberContainer<T>(factory, passivationManager, store, groupCache);
-      
+         new SerializationGroupMemberContainer<T>(factory, passivationManager, store, groupCache);      
       GroupAwareBackingCache<T, SerializationGroupMember<T>> backingCache =
          new GroupAwareBackingCacheImpl<T>(memberContainer, groupCache);
       
+      // Listen for backing cache lifecycle changes so we know when to start/stop groupCache
+      backingCache.addLifecycleListener(listener);
+      
+      // Finally, the front-end cache
       return new GroupAwareTransactionalCache<T, SerializationGroupMember<T>>(backingCache, getTransactionManager(), getSynchronizationCoordinator(), getStrictGroups());
    }
 
@@ -120,7 +143,9 @@
       StatefulObjectFactory<SerializationGroup<T>> factory = container;
       PassivationManager<SerializationGroup<T>> passivationManager = container;
       PassivatingIntegratedObjectStore<T, SerializationGroup<T>> store = 
-         storeSource.createGroupIntegratedObjectStore(name, configName, cacheConfig, getTransactionManager(), getSynchronizationCoordinator());
+         storeSource.createGroupIntegratedObjectStore(name, configName, cacheConfig, 
+                                                      getTransactionManager(), 
+                                                      getSynchronizationCoordinator());
     
       // The group cache store should not passivate/expire -- that's a 
       // function of the caches for the members
@@ -131,8 +156,101 @@
       
       container.setGroupCache(groupCache);
       
-      groupCache.start();
-      
       return groupCache;
    }
+   
+   private void groupMemberCacheStarting(String cacheConfigName)
+   {
+      synchronized (groupCaches)
+      {
+         GroupCacheTracker tracker = groupCaches.get(cacheConfigName);
+         if (tracker == null)
+            throw new IllegalStateException("unknown cacheConfigName " + cacheConfigName);
+         
+         if (tracker.incrementLiveMemberCount() == 1)
+         {
+            // First group member cache is about to start; we need to
+            // start the groupCache
+            tracker.groupCache.start();
+         }
+      }
+   }
+   
+   private void groupMemberCacheStopped(String cacheConfigName)
+   {
+      synchronized (groupCaches)
+      {
+         GroupCacheTracker tracker = groupCaches.get(cacheConfigName);
+         if (tracker == null)
+            throw new IllegalStateException("unknown cacheConfigName " + cacheConfigName);
+         
+         if (tracker.decrementLiveMemberCount() == 0)
+         {
+            // All group member caches have stopped; we need to
+            // stop the groupCache
+            tracker.groupCache.stop();
+         }
+      }
+   }
+   
+   private class GroupCacheTracker
+   {
+      private final PassivatingBackingCache<T, SerializationGroup<T>> groupCache;
+      private final GroupMemberCacheLifecycleListener listener;
+      private int liveMemberCount;
+      
+      private GroupCacheTracker(PassivatingBackingCache<T, SerializationGroup<T>> groupCache,
+                                GroupMemberCacheLifecycleListener listener)
+      {
+         assert groupCache != null : "groupCache is null";
+         assert listener != null : "listener is null";
+         
+         this.groupCache = groupCache;
+         this.listener = listener;
+      }
+      
+      private int incrementLiveMemberCount()
+      {
+         return ++liveMemberCount;
+      }
+      
+      private int decrementLiveMemberCount()
+      {
+         return --liveMemberCount;
+      }
+   }
+   
+   /**
+    * Listens for lifecycle changes on group member caches so we
+    * know when to start/stop the group cache.
+    *
+    */
+   private class GroupMemberCacheLifecycleListener
+      implements BackingCacheLifecycleListener
+   {
+      private final String cacheConfigName;
+      
+      private GroupMemberCacheLifecycleListener(String cacheConfigName)
+      {
+         assert cacheConfigName != null : "cacheConfigName is null";
+         
+         this.cacheConfigName = cacheConfigName;
+      }
+
+      public void lifecycleChange(LifecycleState newState)
+      {
+         switch(newState)
+         {
+            case STARTING:
+               groupMemberCacheStarting(cacheConfigName);
+               break;
+            case STOPPED:
+               groupMemberCacheStopped(cacheConfigName);
+               break;
+            default:
+               break;
+         }         
+      }
+      
+   } 
 }

Modified: projects/ejb3/branches/cluster-dev/ejb3-cache/src/main/java/org/jboss/ejb3/cache/impl/factory/NonPassivatingCacheFactory.java
===================================================================
--- projects/ejb3/branches/cluster-dev/ejb3-cache/src/main/java/org/jboss/ejb3/cache/impl/factory/NonPassivatingCacheFactory.java	2008-03-26 04:46:40 UTC (rev 71286)
+++ projects/ejb3/branches/cluster-dev/ejb3-cache/src/main/java/org/jboss/ejb3/cache/impl/factory/NonPassivatingCacheFactory.java	2008-03-26 05:00:01 UTC (rev 71287)
@@ -48,9 +48,9 @@
                                PassivationManager<T> passivationManager,
                                CacheConfig config)
    {
-      NonPassivatingBackingCacheImpl<T> backingCache = new NonPassivatingBackingCacheImpl<T>(factory);
-      backingCache.setName(containerName);
-      
+      NonPassivatingBackingCacheImpl<T> backingCache = 
+         new NonPassivatingBackingCacheImpl<T>(factory, containerName);
+     
       // Make sure passivation/expiration occurs periodically
       if (getPassivationExpirationCoordinator() != null)
       {

Modified: projects/ejb3/branches/cluster-dev/ejb3-cache/src/main/java/org/jboss/ejb3/cache/spi/BackingCache.java
===================================================================
--- projects/ejb3/branches/cluster-dev/ejb3-cache/src/main/java/org/jboss/ejb3/cache/spi/BackingCache.java	2008-03-26 04:46:40 UTC (rev 71286)
+++ projects/ejb3/branches/cluster-dev/ejb3-cache/src/main/java/org/jboss/ejb3/cache/spi/BackingCache.java	2008-03-26 05:00:01 UTC (rev 71287)
@@ -131,4 +131,18 @@
     *         otherwise
     */
    boolean isClustered();
+   
+   /**
+    * Registers a listener for callbacks when the cache starts and stops.
+    * 
+    * @param listener the listener. Cannot be <code>null</code>.
+    */
+   void addLifecycleListener(BackingCacheLifecycleListener listener);
+   
+   /**
+    * Removes a registered lifecycle listener.
+    * 
+    * @param listener the listener. Cannot be <code>null</code>.
+    */
+   void removeLifecycleListener(BackingCacheLifecycleListener listener);
 }

Added: projects/ejb3/branches/cluster-dev/ejb3-cache/src/main/java/org/jboss/ejb3/cache/spi/BackingCacheLifecycleListener.java
===================================================================
--- projects/ejb3/branches/cluster-dev/ejb3-cache/src/main/java/org/jboss/ejb3/cache/spi/BackingCacheLifecycleListener.java	                        (rev 0)
+++ projects/ejb3/branches/cluster-dev/ejb3-cache/src/main/java/org/jboss/ejb3/cache/spi/BackingCacheLifecycleListener.java	2008-03-26 05:00:01 UTC (rev 71287)
@@ -0,0 +1,53 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 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.ejb3.cache.spi;
+
+/**
+ * Object that receives notifications as a {@link BackingCache} starts and stops.
+ * 
+ * @author Brian Stansberry
+ */
+public interface BackingCacheLifecycleListener
+{
+   public enum LifecycleState 
+   { 
+      /** The cache is starting */
+      STARTING, 
+      /** The cache has started */
+      STARTED, 
+      /** The cache is stopping */
+      STOPPING, 
+      /** The cache has stopped */
+      STOPPED, 
+      /** A failure has occurred in start() or stop() */
+      FAILED 
+   };
+   
+   /**
+    * Notifies the listener that the {@link BackingCache} has entered a new 
+    * lifecycle state.
+    * 
+    * @param newState  the new state. Cannot be <code>null</code>.
+    */
+   void lifecycleChange(LifecycleState newState);
+}

Modified: projects/ejb3/branches/cluster-dev/ejb3-cache/src/main/java/org/jboss/ejb3/cache/spi/GroupAwareBackingCache.java
===================================================================
--- projects/ejb3/branches/cluster-dev/ejb3-cache/src/main/java/org/jboss/ejb3/cache/spi/GroupAwareBackingCache.java	2008-03-26 04:46:40 UTC (rev 71286)
+++ projects/ejb3/branches/cluster-dev/ejb3-cache/src/main/java/org/jboss/ejb3/cache/spi/GroupAwareBackingCache.java	2008-03-26 05:00:01 UTC (rev 71287)
@@ -57,17 +57,6 @@
    
    /**
     * Callback from the group informing the cache it needs to invoke
-    * pre-passivation callbacks on the member.
-    * 
-    * @param member the group member
-    * 
-    * @throws IllegalStateException if the member is 
-    *                               {@link BackingCacheEntry#isInUse() in-use}.
-    */
-//   void prePassivate(T member);
-   
-   /**
-    * Callback from the group informing the cache it needs to invoke
     * pre-replication callbacks on the member.
     * 
     * @param member the group member

Added: projects/ejb3/branches/cluster-dev/ejb3-cache/src/main/java/org/jboss/ejb3/cache/spi/GroupCompatibilityChecker.java
===================================================================
--- projects/ejb3/branches/cluster-dev/ejb3-cache/src/main/java/org/jboss/ejb3/cache/spi/GroupCompatibilityChecker.java	                        (rev 0)
+++ projects/ejb3/branches/cluster-dev/ejb3-cache/src/main/java/org/jboss/ejb3/cache/spi/GroupCompatibilityChecker.java	2008-03-26 05:00:01 UTC (rev 71287)
@@ -0,0 +1,43 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 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.ejb3.cache.spi;
+
+/**
+ * An object that can check whether it can work compatibly with another
+ * in the management of {@link SerializationGroup}s.
+ * 
+ * @author Brian Stansberry
+ */
+public interface GroupCompatibilityChecker
+{
+   /**
+    * Gets whether this object can work compatibly with another
+    * in the management of {@link SerializationGroup}s.
+    * 
+    * @param other the other checker. May be <code>null</code>.
+    * 
+    * @return <code>true</code> if this object is compatible with 
+    *         <code>other</code>, <code>false</code> otherwise
+    */
+   boolean isCompatibleWith(GroupCompatibilityChecker other);
+}

Modified: projects/ejb3/branches/cluster-dev/ejb3-cache/src/main/java/org/jboss/ejb3/cache/spi/IntegratedObjectStore.java
===================================================================
--- projects/ejb3/branches/cluster-dev/ejb3-cache/src/main/java/org/jboss/ejb3/cache/spi/IntegratedObjectStore.java	2008-03-26 04:46:40 UTC (rev 71286)
+++ projects/ejb3/branches/cluster-dev/ejb3-cache/src/main/java/org/jboss/ejb3/cache/spi/IntegratedObjectStore.java	2008-03-26 05:00:01 UTC (rev 71287)
@@ -70,7 +70,7 @@
     *                               It is not a requirement that the store throw
     *                               this exception in this case, but it is
     *                               permissible. This basically puts the onus on
-    *                               callers to ensure {@link #insert(Cacheable)}
+    *                               callers to ensure {@link #insert(T)}
     *                               is invoked before the first replication.
     */
    void update(T entry, boolean modified);

Modified: projects/ejb3/branches/cluster-dev/ejb3-cache/src/main/java/org/jboss/ejb3/cache/spi/PassivatingBackingCache.java
===================================================================
--- projects/ejb3/branches/cluster-dev/ejb3-cache/src/main/java/org/jboss/ejb3/cache/spi/PassivatingBackingCache.java	2008-03-26 04:46:40 UTC (rev 71286)
+++ projects/ejb3/branches/cluster-dev/ejb3-cache/src/main/java/org/jboss/ejb3/cache/spi/PassivatingBackingCache.java	2008-03-26 05:00:01 UTC (rev 71287)
@@ -51,4 +51,11 @@
     *                            is in use. 
     */
    void passivate(Object key);
+   
+   /**
+    * Gets any {@link GroupCompatibilityChecker} this cache is using.
+    * 
+    * @return the checker, or <code>null</code> if this cache is not using one.
+    */
+   GroupCompatibilityChecker getCompatibilityChecker();
 }

Modified: projects/ejb3/branches/cluster-dev/ejb3-cache/src/main/java/org/jboss/ejb3/cache/spi/PassivatingIntegratedObjectStore.java
===================================================================
--- projects/ejb3/branches/cluster-dev/ejb3-cache/src/main/java/org/jboss/ejb3/cache/spi/PassivatingIntegratedObjectStore.java	2008-03-26 04:46:40 UTC (rev 71286)
+++ projects/ejb3/branches/cluster-dev/ejb3-cache/src/main/java/org/jboss/ejb3/cache/spi/PassivatingIntegratedObjectStore.java	2008-03-26 05:00:01 UTC (rev 71287)
@@ -34,7 +34,7 @@
  * @version $Revision$
  */
 public interface PassivatingIntegratedObjectStore<C extends CacheItem, T extends PassivatingBackingCacheEntry<C>>
-   extends IntegratedObjectStore<T>, PassivationExpirationProcessor
+   extends IntegratedObjectStore<T>, PassivationExpirationProcessor, GroupCompatibilityChecker
 {
    /**
     * Gets how often, in seconds, this object should process 
@@ -68,12 +68,4 @@
     * @param cache
     */
    void setPassivatingCache(PassivatingBackingCache<C, T> cache);
-   
-   // TODO determine what the standard configurations are
-   
-//   int getPassivationTimeout();
-//   void setPassivationTimeout(int timeout);
-//   
-//   int getRemovalTimeout();   
-//   void setRemovalTimeout(int timeout);
 }

Added: projects/ejb3/branches/cluster-dev/ejb3-cache/src/main/java/org/jboss/ejb3/cache/spi/impl/AbstractBackingCache.java
===================================================================
--- projects/ejb3/branches/cluster-dev/ejb3-cache/src/main/java/org/jboss/ejb3/cache/spi/impl/AbstractBackingCache.java	                        (rev 0)
+++ projects/ejb3/branches/cluster-dev/ejb3-cache/src/main/java/org/jboss/ejb3/cache/spi/impl/AbstractBackingCache.java	2008-03-26 05:00:01 UTC (rev 71287)
@@ -0,0 +1,95 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2007, 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.ejb3.cache.spi.impl;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.jboss.ejb3.cache.api.CacheItem;
+import org.jboss.ejb3.cache.spi.BackingCache;
+import org.jboss.ejb3.cache.spi.BackingCacheLifecycleListener;
+import org.jboss.ejb3.cache.spi.BackingCacheLifecycleListener.LifecycleState;
+import org.jboss.logging.Logger;
+
+/**
+ * Abstract superclass of {@link BackingCache} implementations.
+ * Basically provides support for working with 
+ * {@link BackingCacheLifecycleListener}s.
+ * 
+ * @author Brian Stansberry
+ *
+ * @param <C> the type of item being managed by the cache
+ */
+public abstract class AbstractBackingCache<C extends CacheItem>
+{
+   protected Logger log = Logger.getLogger(getClass().getName());
+   
+   private final Set<BackingCacheLifecycleListener> listeners;
+
+   protected AbstractBackingCache()
+   {
+      this.listeners = new HashSet<BackingCacheLifecycleListener>();
+   }
+
+   public void addLifecycleListener(BackingCacheLifecycleListener listener)
+   {
+      assert listener != null : "listener is null";
+      
+      synchronized (listeners)
+      {
+         listeners.add(listener);
+      }      
+   }
+
+   public void removeLifecycleListener(BackingCacheLifecycleListener listener)
+   {  
+      synchronized (listeners)
+      {
+         listeners.remove(listener);
+      } 
+   }
+
+   protected void notifyLifecycleListeners(LifecycleState newState)
+   {
+      RuntimeException re = null;
+      synchronized (listeners)
+      {
+         for (BackingCacheLifecycleListener listener : listeners)
+         {
+            try
+            {
+               listener.lifecycleChange(newState);
+            }
+            catch (RuntimeException e)
+            {
+               log.error("Listener " + listener + " threw Exception during notification of " + newState, e);
+               if (re != null)
+                  re = e;
+            }
+         }
+      }
+      
+      if (re != null)
+         throw re;
+   }
+
+}
\ No newline at end of file

Modified: projects/ejb3/branches/cluster-dev/ejb3-cache/src/main/java/org/jboss/ejb3/cache/spi/impl/AbstractPassivatingIntegratedObjectStore.java
===================================================================
--- projects/ejb3/branches/cluster-dev/ejb3-cache/src/main/java/org/jboss/ejb3/cache/spi/impl/AbstractPassivatingIntegratedObjectStore.java	2008-03-26 04:46:40 UTC (rev 71286)
+++ projects/ejb3/branches/cluster-dev/ejb3-cache/src/main/java/org/jboss/ejb3/cache/spi/impl/AbstractPassivatingIntegratedObjectStore.java	2008-03-26 05:00:01 UTC (rev 71287)
@@ -118,6 +118,15 @@
    // --------------------------------------------------  IntegratedObjectStore
 
    public void start()
+   {    
+      internalStart();
+      
+      stopped = false;
+      
+      log.debug("Started " + name);
+   }
+   
+   protected void internalStart()
    {
       if (!forGroups && interval > 0)
       {
@@ -129,24 +138,25 @@
             sessionTimeoutRunner = new PassivationExpirationRunner(this, timerName, interval);
          }
          sessionTimeoutRunner.start();
-      }     
-      
-      stopped = false;
-      
-      log.debug("Started " + name);
+      }
    }
 
    public void stop()
-   {      
-      if (sessionTimeoutRunner != null)
-      {
-         sessionTimeoutRunner.stop();
-      }      
+   {     
+      internalStop();
       
       stopped = true;
       
       log.debug("Stopped " + name);
    }
+   
+   protected void internalStop()
+   {     
+      if (sessionTimeoutRunner != null)
+      {
+         sessionTimeoutRunner.stop();
+      }
+   }
 
    // ---------------------------------------  PassivatingIntegratedObjectStore
 

Modified: projects/ejb3/branches/cluster-dev/ejb3-cache/src/test/java/org/jboss/ejb3/test/cache/distributed/GroupedPassivatingUnitTestCase.java
===================================================================
--- projects/ejb3/branches/cluster-dev/ejb3-cache/src/test/java/org/jboss/ejb3/test/cache/distributed/GroupedPassivatingUnitTestCase.java	2008-03-26 04:46:40 UTC (rev 71286)
+++ projects/ejb3/branches/cluster-dev/ejb3-cache/src/test/java/org/jboss/ejb3/test/cache/distributed/GroupedPassivatingUnitTestCase.java	2008-03-26 05:00:01 UTC (rev 71287)
@@ -21,8 +21,7 @@
  */
 package org.jboss.ejb3.test.cache.distributed;
 
-import junit.framework.TestCase;
-
+import org.jboss.ejb3.test.cache.integrated.Ejb3CacheTestCaseBase;
 import org.jboss.ejb3.test.cache.mock.CacheType;
 import org.jboss.ejb3.test.cache.mock.MockBeanContainer;
 import org.jboss.ejb3.test.cache.mock.MockBeanContext;
@@ -38,22 +37,10 @@
  * @author Brian Stansberry
  * @version $Revision: 65920 $
  */
-public class GroupedPassivatingUnitTestCase extends TestCase
+public class GroupedPassivatingUnitTestCase extends Ejb3CacheTestCaseBase
 {
    private static final Logger log = Logger.getLogger(GroupedPassivatingUnitTestCase.class);
    
-   private static void sleep(long micros)
-   {
-      try
-      {
-         Thread.sleep(micros);
-      }
-      catch (InterruptedException e)
-      {
-         // ignore
-      }
-   }
-   
    public void testSimpleGroupPassivation() throws Exception
    {      
       log.info("====== testSimpleGroupPassivation() ======");
@@ -66,7 +53,7 @@
       MockBeanContainer container1 = node0.deployBeanContainer("MockBeanContainer1", null, CacheType.DISTRIBUTED, cacheConfig, sharedXPC.getName());
       MockBeanContainer container2 = node0.deployBeanContainer("MockBeanContainer2", "MockBeanContainer1", CacheType.DISTRIBUTED, cacheConfig, sharedXPC.getName());
       
-      cluster.getNode0().setTCCL();
+      node0.setTCCL();
       try
       {
          Object key1 = container1.getCache().create(null, null);
@@ -120,7 +107,7 @@
          }
          finally
          {
-            cluster.getNode0().restoreTCCL();
+            node0.restoreTCCL();
          }
       }
    }
@@ -144,6 +131,7 @@
       Object key2 = null;
       MockEntity entityA = null;
       
+      // Use the TCCL to focus on the 1st node
       cluster.getNode0().setTCCL();
       try
       {

Modified: projects/ejb3/branches/cluster-dev/ejb3-cache/src/test/java/org/jboss/ejb3/test/cache/distributed/MockClusterMember.java
===================================================================
--- projects/ejb3/branches/cluster-dev/ejb3-cache/src/test/java/org/jboss/ejb3/test/cache/distributed/MockClusterMember.java	2008-03-26 04:46:40 UTC (rev 71286)
+++ projects/ejb3/branches/cluster-dev/ejb3-cache/src/test/java/org/jboss/ejb3/test/cache/distributed/MockClusterMember.java	2008-03-26 05:00:01 UTC (rev 71287)
@@ -62,8 +62,8 @@
       ClassLoader tccl = Thread.currentThread().getContextClassLoader();
       localClassLoader = new ClassLoader(tccl) {};
       
-      // Kluge. Rebuild the distributed factory, as the superclass
-      // didn't have the maps available when it did it
+      // Kluge. Build the distributed factory, as the superclass
+      // didn't have the maps available when it tried
       for (CacheType type : availableTypes)
       {
          if (type == CacheType.DISTRIBUTED)
@@ -110,8 +110,13 @@
    @Override
    protected IntegratedObjectStoreSource<MockBeanContext> getDistributedStoreSource()
    {
-      return new MockIntegratedObjectStoreSource<MockBeanContext>(localDistributedCacheMember, 
-                                                                  remoteDistributedCacheMember);
+      if (localDistributedCacheMember != null && remoteDistributedCacheMember != null)
+      {
+         return new MockIntegratedObjectStoreSource<MockBeanContext>(localDistributedCacheMember, 
+                                                                     remoteDistributedCacheMember);
+      }
+      else
+         return null;
    }
 
    @Override

Modified: projects/ejb3/branches/cluster-dev/ejb3-cache/src/test/java/org/jboss/ejb3/test/cache/distributed/MockIntegratedObjectStoreSource.java
===================================================================
--- projects/ejb3/branches/cluster-dev/ejb3-cache/src/test/java/org/jboss/ejb3/test/cache/distributed/MockIntegratedObjectStoreSource.java	2008-03-26 04:46:40 UTC (rev 71286)
+++ projects/ejb3/branches/cluster-dev/ejb3-cache/src/test/java/org/jboss/ejb3/test/cache/distributed/MockIntegratedObjectStoreSource.java	2008-03-26 05:00:01 UTC (rev 71287)
@@ -52,13 +52,13 @@
          String cacheConfigName, CacheConfig cacheConfig, TransactionManager transactionManager, SynchronizationCoordinator synchronizationCoordinator)
    {
       String keyBase = "GroupCache-" + containerName;
-      return new MockJBCIntegratedObjectStore<T, SerializationGroup<T>>(localMap, remoteMap, cacheConfig, keyBase, keyBase);
+      return new MockJBCIntegratedObjectStore<T, SerializationGroup<T>>(localMap, remoteMap, cacheConfig, keyBase, keyBase, true);
    }
 
    public PassivatingIntegratedObjectStore<T, SerializationGroupMember<T>>  createIntegratedObjectStore(String containerName, String cacheConfigName,
          CacheConfig cacheConfig, TransactionManager transactionManager, SynchronizationCoordinator synchronizationCoordinator)
    {
-      return new MockJBCIntegratedObjectStore<T, SerializationGroupMember<T>>(localMap, remoteMap, cacheConfig, containerName, containerName);
+      return new MockJBCIntegratedObjectStore<T, SerializationGroupMember<T>>(localMap, remoteMap, cacheConfig, containerName, containerName, false);
    }
 
 }

Modified: projects/ejb3/branches/cluster-dev/ejb3-cache/src/test/java/org/jboss/ejb3/test/cache/distributed/MockJBCIntegratedObjectStore.java
===================================================================
--- projects/ejb3/branches/cluster-dev/ejb3-cache/src/test/java/org/jboss/ejb3/test/cache/distributed/MockJBCIntegratedObjectStore.java	2008-03-26 04:46:40 UTC (rev 71286)
+++ projects/ejb3/branches/cluster-dev/ejb3-cache/src/test/java/org/jboss/ejb3/test/cache/distributed/MockJBCIntegratedObjectStore.java	2008-03-26 05:00:01 UTC (rev 71287)
@@ -25,22 +25,20 @@
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.ObjectOutputStream;
+import java.util.Arrays;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.Map;
 import java.util.Set;
-import java.util.SortedSet;
-import java.util.TreeSet;
 
 import org.jboss.ejb3.annotation.CacheConfig;
 import org.jboss.ejb3.cache.api.CacheItem;
+import org.jboss.ejb3.cache.spi.GroupCompatibilityChecker;
 import org.jboss.ejb3.cache.spi.IntegratedObjectStore;
-import org.jboss.ejb3.cache.spi.PassivatingBackingCache;
 import org.jboss.ejb3.cache.spi.PassivatingBackingCacheEntry;
-import org.jboss.ejb3.cache.spi.PassivatingIntegratedObjectStore;
+import org.jboss.ejb3.cache.spi.impl.AbstractPassivatingIntegratedObjectStore;
 import org.jboss.ejb3.cache.spi.impl.CacheableTimestamp;
-import org.jboss.ejb3.cache.spi.impl.PassivationExpirationRunner;
 import org.jboss.logging.Logger;
 
 /**
@@ -51,7 +49,8 @@
  * @version $Revision$
  */
 public class MockJBCIntegratedObjectStore<C extends CacheItem, T extends PassivatingBackingCacheEntry<C>> 
-     implements PassivatingIntegratedObjectStore<C, T>
+     extends AbstractPassivatingIntegratedObjectStore<C, T, Object>
+
 {
    private static final Logger log = Logger.getLogger(MockJBCIntegratedObjectStore.class);
 
@@ -85,34 +84,20 @@
    /** A mock transaction manager */
    private final ThreadLocal<Boolean> tm = new ThreadLocal<Boolean>();
    
-   /**
-    * Support callbacks when our MockEvictionRunner decides to
-    * evict an entry.
-    */
-   private PassivatingBackingCache<C, T> owningCache;   
-   private int interval;
-   private long idleTimeSeconds;
-   private long expirationTimeSeconds;
-   private int maxSize;
-   private PassivationExpirationRunner sessionTimeoutRunner;
-   private final String name;
-   private boolean stopped = true;
-   
    public MockJBCIntegratedObjectStore(UnmarshallingMap localCache, 
                                        UnmarshallingMap remoteCache,
                                        CacheConfig cacheConfig,
                                        Object keyBase,
-                                       String name)
+                                       String name,
+                                       boolean forGroups)
    {      
+      super(cacheConfig, name, forGroups);
+      
       this.localJBC = localCache;
       this.remoteJBC = remoteCache;
       this.keyBase = keyBase;
       inMemory = new HashSet<Object>();
       timestamps = new HashMap<Object, Long>();
-      this.idleTimeSeconds = cacheConfig.idleTimeoutSeconds();
-      this.expirationTimeSeconds = cacheConfig.removalTimeoutSeconds();
-      this.maxSize = cacheConfig.maxSize();
-      this.name = name;
    }
 
    // --------------------------------------------------  IntegratedObjectStore
@@ -166,9 +151,21 @@
       return unmarshall(key, putInCache(key, null));
    }
    
+   @SuppressWarnings("unchecked")
+   public boolean isCompatibleWith(GroupCompatibilityChecker other)
+   {
+      if (other instanceof MockJBCIntegratedObjectStore)
+      {
+         MockJBCIntegratedObjectStore jbc2 = (MockJBCIntegratedObjectStore) other;
+         return this.localJBC == jbc2.localJBC
+                 && this.remoteJBC == jbc2.remoteJBC;
+      }
+      return false;
+   }
    
-   // ------------------------------------------------------------ Transaction
    
+   // ------------------------------------------------------------ Transaction
+
    public void startTransaction()
    {
       if (tm.get() != null)
@@ -264,188 +261,118 @@
 
    // ---------------------------------------  PassivatingIntegratedObjectStore
    
-   public int getInterval()
-   {
-      return interval;
-   }
+     
+//   public void runExpiration()
+//   {
+//      if (expirationTimeSeconds > 0)
+//      {
+//         long now = System.currentTimeMillis();
+//         long minRemovalUse = now - (expirationTimeSeconds * 1000);                     
+//         for (CacheableTimestamp<Object> ts : getAllEntries())
+//         {
+//            try
+//            {
+//               if (minRemovalUse >= ts.getLastUsed())
+//               {
+//                  remove(ts.getId());
+//               }
+//            }
+//            catch (IllegalStateException ise)
+//            {
+//               // Not so great; we're assuming it's 'cause item's in use
+//               log.trace("skipping in-use entry " + ts.getId(), ise);
+//            }
+//         }    
+//      }      
+//   }
 
-   public void setInterval(int seconds)
-   {
-      this.interval = seconds;      
-   }
-   
-   public void runExpiration()
-   {
-      if (expirationTimeSeconds > 0)
-      {
-         long now = System.currentTimeMillis();
-         long minRemovalUse = now - (expirationTimeSeconds * 1000);                     
-         for (CacheableTimestamp ts : getAllEntries())
-         {
-            try
-            {
-               if (minRemovalUse >= ts.getLastUsed())
-               {
-                  remove(ts.getId());
-               }
-            }
-            catch (IllegalStateException ise)
-            {
-               // Not so great; we're assuming it's 'cause item's in use
-               log.trace("skipping in-use entry " + ts.getId(), ise);
-            }
-         }    
-      }      
-   }
+//   public void runPassivation()
+//   {
+//      if (maxSize > 0 || idleTimeSeconds > 0)
+//      {
+//         long now = System.currentTimeMillis();
+//         long minPassUse = (idleTimeSeconds > 0 ? now - (idleTimeSeconds * 1000) : 0);
+//         
+//         SortedSet<CacheableTimestamp<Object>> timestamps = getInMemoryEntries();
+//         int overCount = (maxSize > 0 ? timestamps.size() - maxSize : 0);
+//         for (CacheableTimestamp<Object> ts : timestamps)
+//         {
+//            try
+//            {
+//               if (overCount > 0 || minPassUse >= ts.getLastUsed())
+//               {
+//                  log.trace("attempting to passivate " + ts.getId());
+//                  owningCache.passivate(ts.getId());
+//                  overCount--;
+//               }
+//               else
+//               {
+//                  break;
+//               }
+//            }
+//            catch (IllegalStateException ise)
+//            {
+//               // Not so great; we're assuming it's 'cause item's in use
+//               log.trace("skipping in-use entry " + ts.getId(), ise);
+//            }
+//         }
+//      }
+//      
+//   }
 
-   public void runPassivation()
+   @Override
+   public int getInMemoryCount()
    {
-      if (maxSize > 0 || idleTimeSeconds > 0)
-      {
-         long now = System.currentTimeMillis();
-         long minPassUse = (idleTimeSeconds > 0 ? now - (idleTimeSeconds * 1000) : 0);
-         
-         SortedSet<CacheableTimestamp> timestamps = getInMemoryEntries();
-         int overCount = (maxSize > 0 ? timestamps.size() - maxSize : 0);
-         for (CacheableTimestamp ts : timestamps)
-         {
-            try
-            {
-               if (overCount > 0 || minPassUse >= ts.getLastUsed())
-               {
-                  log.trace("attempting to passivate " + ts.getId());
-                  owningCache.passivate(ts.getId());
-                  overCount--;
-               }
-               else
-               {
-                  break;
-               }
-            }
-            catch (IllegalStateException ise)
-            {
-               // Not so great; we're assuming it's 'cause item's in use
-               log.trace("skipping in-use entry " + ts.getId(), ise);
-            }
-         }
-      }
-      
+      return inMemory.size();
    }
 
-   public void setPassivatingCache(PassivatingBackingCache<C, T> cache)
+   @Override
+   public int getPassivatedCount()
    {
-      this.owningCache = cache;      
+      return timestamps.size() - getInMemoryCount();
    }
 
-   public void start()
+   @Override
+   protected void processExpiration(Object key)
    {
-      if (interval > 0)
-      {
-         if (sessionTimeoutRunner == null)
-         {
-            assert name != null : "name has not been set";
-            assert owningCache != null;
-            String timerName = "PassivationExpirationTimer-" + name;
-            sessionTimeoutRunner = new PassivationExpirationRunner(this, timerName, interval);
-         }
-         sessionTimeoutRunner.start();
-      }      
-      
-      stopped = false;
-      
-      log.debug("Started " + name);
+      remove(key);      
    }
 
-   public void stop()
+   @Override
+   protected void processPassivation(Object key)
    {
-      if (sessionTimeoutRunner != null)
-      {
-         sessionTimeoutRunner.stop();
-      }          
-      
-      stopped = true;
-      
-      log.debug("Stopped " + name);
+      getPassivatingCache().passivate(key);      
    }
-   
-   public long getIdleTimeSeconds()
-   {
-      return idleTimeSeconds;
-   }
 
-   public void setIdleTimeSeconds(long idleTimeSeconds)
-   {
-      this.idleTimeSeconds = idleTimeSeconds;
+   @Override
+   protected CacheableTimestamp<Object>[] getInMemoryEntries()
+   {     
+      return getTimestampArray(false);
    }
 
-   public long getExpirationTimeSeconds()
-   {
-      return expirationTimeSeconds;
+   @Override
+   protected CacheableTimestamp<Object>[] getAllEntries()
+   {     
+      return getTimestampArray(null);
    }
-   
-   public void setExpirationTimeSeconds(long timeout)
-   {
-      this.expirationTimeSeconds = timeout;
-   } 
 
-   private SortedSet<CacheableTimestamp> getInMemoryEntries()
-   {      
-      return getTimestampSet(false);
-   }
-
-   private SortedSet<CacheableTimestamp> getPassivatedEntries()
+   @SuppressWarnings("unchecked")
+   private CacheableTimestamp<Object>[] getTimestampArray(Boolean passivated)
    {     
-      return getTimestampSet(true);
-   }
-   
-   private SortedSet<CacheableTimestamp> getAllEntries()
-   {
-      return getTimestampSet(null);
-   }
-   
-   private SortedSet<CacheableTimestamp> getTimestampSet(Boolean passivated)
-   {      
-      SortedSet<CacheableTimestamp> set = new TreeSet<CacheableTimestamp>();
+      Set<CacheableTimestamp<Object>> set = new HashSet<CacheableTimestamp<Object>>();
       for (Map.Entry<Object, Long> entry : timestamps.entrySet())
       {
          if (passivated == null || passivated.booleanValue() != inMemory.contains(entry.getKey()))
          {
-            set.add(new CacheableTimestamp(entry.getKey(), entry.getValue().longValue()));
+            set.add(new CacheableTimestamp<Object>(entry.getKey(), entry.getValue()));
          }
       }
-      return set;
-      
+      CacheableTimestamp<Object>[] array = new CacheableTimestamp[set.size()];
+      array = set.toArray(array);
+      Arrays.sort(array);
+      return array;
    }
    
-   public boolean isPassivationExpirationSelfManaged()
-   {
-      return interval > 0;
-   }
-   
-   public void processPassivationExpiration()
-   {
-      try
-      {
-         runPassivation();               
-      }
-      catch (Exception e)
-      {
-         log.error("Caught exception processing passivations", e);
-      }
-      
-      if (!stopped)
-      {
-         try
-         {
-            runExpiration();               
-         }
-         catch (Exception e)
-         {
-            log.error("Caught exception processing expirations", e);
-         }               
-      }
-   }
-   
    private ScopedKey getScopedKey(Object unscoped)
    {
       return new ScopedKey(unscoped, keyBase);

Deleted: projects/ejb3/branches/cluster-dev/ejb3-cache/src/test/java/org/jboss/ejb3/test/cache/distributed/SharedObject.java
===================================================================
--- projects/ejb3/branches/cluster-dev/ejb3-cache/src/test/java/org/jboss/ejb3/test/cache/distributed/SharedObject.java	2008-03-26 04:46:40 UTC (rev 71286)
+++ projects/ejb3/branches/cluster-dev/ejb3-cache/src/test/java/org/jboss/ejb3/test/cache/distributed/SharedObject.java	2008-03-26 05:00:01 UTC (rev 71287)
@@ -1,36 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source.
- * Copyright 2006, Red Hat Middleware LLC, and individual contributors
- * as indicated by the @author tags. See the copyright.txt file in the
- * distribution for a full listing of individual contributors.
- *
- * This is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of
- * the License, or (at your option) any later version.
- *
- * This software is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this software; if not, write to the Free
- * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
- */
-
-package org.jboss.ejb3.test.cache.distributed;
-
-import java.io.Serializable;
-
-/**
- * A SharedObject.
- * 
- * @author Brian Stansberry
- * @version $Revision$
- */
-public class SharedObject implements Serializable
-{
-   private static final long serialVersionUID = 1L;
-}

Modified: projects/ejb3/branches/cluster-dev/ejb3-cache/src/test/java/org/jboss/ejb3/test/cache/impl/backing/PassivatingBackingCacheImplUnitTestCase.java
===================================================================
--- projects/ejb3/branches/cluster-dev/ejb3-cache/src/test/java/org/jboss/ejb3/test/cache/impl/backing/PassivatingBackingCacheImplUnitTestCase.java	2008-03-26 04:46:40 UTC (rev 71286)
+++ projects/ejb3/branches/cluster-dev/ejb3-cache/src/test/java/org/jboss/ejb3/test/cache/impl/backing/PassivatingBackingCacheImplUnitTestCase.java	2008-03-26 05:00:01 UTC (rev 71287)
@@ -23,11 +23,10 @@
 
 import java.util.HashMap;
 
-import junit.framework.TestCase;
-
 import org.jboss.ejb3.cache.impl.TransactionalCache;
 import org.jboss.ejb3.cache.impl.backing.PassivatingBackingCacheImpl;
 import org.jboss.ejb3.cache.impl.backing.SerializationGroupMemberImpl;
+import org.jboss.ejb3.test.cache.integrated.Ejb3CacheTestCaseBase;
 import org.jboss.ejb3.test.cache.mock.CacheType;
 import org.jboss.ejb3.test.cache.mock.MockBeanContainer;
 import org.jboss.ejb3.test.cache.mock.MockBeanContext;
@@ -40,9 +39,11 @@
  * Comment
  *
  * @author <a href="mailto:carlo.dewolf at jboss.com">Carlo de Wolf</a>
+ * @author Brian Stansberry
+ * 
  * @version $Revision: 65339 $
  */
-public class PassivatingBackingCacheImplUnitTestCase extends TestCase
+public class PassivatingBackingCacheImplUnitTestCase extends Ejb3CacheTestCaseBase
 {   
    private static final Logger log = Logger.getLogger(PassivatingBackingCacheImplUnitTestCase.class);
    

Modified: projects/ejb3/branches/cluster-dev/ejb3-cache/src/test/java/org/jboss/ejb3/test/cache/integrated/Ejb3CacheTestCaseBase.java
===================================================================
--- projects/ejb3/branches/cluster-dev/ejb3-cache/src/test/java/org/jboss/ejb3/test/cache/integrated/Ejb3CacheTestCaseBase.java	2008-03-26 04:46:40 UTC (rev 71286)
+++ projects/ejb3/branches/cluster-dev/ejb3-cache/src/test/java/org/jboss/ejb3/test/cache/integrated/Ejb3CacheTestCaseBase.java	2008-03-26 05:00:01 UTC (rev 71287)
@@ -35,12 +35,11 @@
 {
 
    /**
-    * Create a new Ejb3CacheTestCaseBase.
-    * 
+    * Create a new Ejb3CacheTestCaseBase. 
     */
    public Ejb3CacheTestCaseBase()
    {
-      // TODO Auto-generated constructor stub
+      super();
    }
 
    /**

Modified: projects/ejb3/branches/cluster-dev/ejb3-cache/src/test/java/org/jboss/ejb3/test/cache/mock/MockEjb3System.java
===================================================================
--- projects/ejb3/branches/cluster-dev/ejb3-cache/src/test/java/org/jboss/ejb3/test/cache/mock/MockEjb3System.java	2008-03-26 04:46:40 UTC (rev 71286)
+++ projects/ejb3/branches/cluster-dev/ejb3-cache/src/test/java/org/jboss/ejb3/test/cache/mock/MockEjb3System.java	2008-03-26 05:00:01 UTC (rev 71287)
@@ -75,7 +75,9 @@
             new HashMap<String, StatefulCacheFactory<MockBeanContext>>();
          for (CacheType type : availableTypes)
          {
-            factories.put(type.mapKey(), buildCacheFactory(type));
+            StatefulCacheFactory<MockBeanContext> factory = buildCacheFactory(type);
+            if (factory != null)
+               factories.put(type.mapKey(), factory);
          }
          cacheFactoryRegistry.setFactories(factories);
       }
@@ -154,12 +156,14 @@
             throw new IllegalArgumentException("Unknown type " + type);
       }
       
-      factory.setTransactionManager(tm);
-      factory.setPassivationExpirationCoordinator(coordinator);
-      // Process passivation/expiration as quickly as possible so tests run fast
-      factory.setDefaultPassivationExpirationInterval(1);
-      factory.start();
-      
+      if (factory != null)
+      {
+         factory.setTransactionManager(tm);
+         factory.setPassivationExpirationCoordinator(coordinator);
+         // Process passivation/expiration as quickly as possible so tests run fast
+         factory.setDefaultPassivationExpirationInterval(1);
+         factory.start();
+      }
       return factory;
    }
    
@@ -177,7 +181,8 @@
    
    private AbstractStatefulCacheFactory<MockBeanContext> buildDistributedCacheFactory()
    {
-     return new GroupAwareCacheFactory<MockBeanContext>(getDistributedStoreSource());
+     IntegratedObjectStoreSource<MockBeanContext> storeSource = getDistributedStoreSource();
+     return storeSource == null ? null : new GroupAwareCacheFactory<MockBeanContext>(storeSource);
    }
    
    protected IntegratedObjectStoreSource<MockBeanContext> getDistributedStoreSource()




More information about the jboss-cvs-commits mailing list