[hibernate-commits] Hibernate SVN: r18005 - in core/trunk/cache-infinispan: src/main/java/org/hibernate/cache/infinispan and 15 other directories.

hibernate-commits at lists.jboss.org hibernate-commits at lists.jboss.org
Wed Nov 18 11:56:15 EST 2009


Author: galder.zamarreno at jboss.com
Date: 2009-11-18 11:56:13 -0500 (Wed, 18 Nov 2009)
New Revision: 18005

Added:
   core/trunk/cache-infinispan/src/main/java/org/hibernate/cache/infinispan/access/PutFromLoadValidator.java
   core/trunk/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/access/
   core/trunk/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/access/PutFromLoadValidatorUnitTestCase.java
   core/trunk/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/collection/CollectionRegionImplTestCase.java
   core/trunk/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/ConcurrentWriteTest.java
   core/trunk/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/SingleNodeTestCase.java
   core/trunk/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/cluster/DualNodeTestCase.java
Removed:
   core/trunk/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/AbstractFunctionalTestCase.java
   core/trunk/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/cluster/AbstractDualNodeTestCase.java
Modified:
   core/trunk/cache-infinispan/pom.xml
   core/trunk/cache-infinispan/src/main/java/org/hibernate/cache/infinispan/InfinispanRegionFactory.java
   core/trunk/cache-infinispan/src/main/java/org/hibernate/cache/infinispan/JndiInfinispanRegionFactory.java
   core/trunk/cache-infinispan/src/main/java/org/hibernate/cache/infinispan/access/TransactionalAccessDelegate.java
   core/trunk/cache-infinispan/src/main/java/org/hibernate/cache/infinispan/collection/CollectionRegionImpl.java
   core/trunk/cache-infinispan/src/main/java/org/hibernate/cache/infinispan/collection/ReadOnlyAccess.java
   core/trunk/cache-infinispan/src/main/java/org/hibernate/cache/infinispan/collection/TransactionalAccess.java
   core/trunk/cache-infinispan/src/main/java/org/hibernate/cache/infinispan/entity/EntityRegionImpl.java
   core/trunk/cache-infinispan/src/main/java/org/hibernate/cache/infinispan/entity/ReadOnlyAccess.java
   core/trunk/cache-infinispan/src/main/java/org/hibernate/cache/infinispan/entity/TransactionalAccess.java
   core/trunk/cache-infinispan/src/main/java/org/hibernate/cache/infinispan/impl/BaseRegion.java
   core/trunk/cache-infinispan/src/main/java/org/hibernate/cache/infinispan/util/CacheHelper.java
   core/trunk/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/entity/AbstractEntityRegionAccessStrategyTestCase.java
   core/trunk/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/entity/AbstractTransactionalAccessTestCase.java
   core/trunk/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/entity/EntityRegionImplTestCase.java
   core/trunk/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/BasicReadOnlyTestCase.java
   core/trunk/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/BasicTransactionalTestCase.java
   core/trunk/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/bulk/BulkOperationsTestCase.java
   core/trunk/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/classloader/ClassLoaderTestDAO.java
   core/trunk/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/classloader/IsolatedClassLoaderTest.java
   core/trunk/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/cluster/ClusterAwareRegionFactory.java
   core/trunk/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/cluster/DualNodeConnectionProviderImpl.java
   core/trunk/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/cluster/DualNodeJtaTransactionImpl.java
   core/trunk/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/cluster/DualNodeJtaTransactionManagerImpl.java
   core/trunk/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/cluster/DualNodeTransactionManagerLookup.java
   core/trunk/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/cluster/EntityCollectionInvalidationTestCase.java
   core/trunk/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/cluster/SessionRefreshTestCase.java
   core/trunk/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/tm/XaTransactionImpl.java
   core/trunk/cache-infinispan/src/test/resources/hibernate.properties
Log:
[HHH-4520] (Infinispan second level cache integration can cache stale collection data) Ported fix. testManyUsers has been disabled while ISPN-277 gets fixed. Finally, Infinispan version has been upgraded to 4.0.0.CR2.

Modified: core/trunk/cache-infinispan/pom.xml
===================================================================
--- core/trunk/cache-infinispan/pom.xml	2009-11-18 16:35:28 UTC (rev 18004)
+++ core/trunk/cache-infinispan/pom.xml	2009-11-18 16:56:13 UTC (rev 18005)
@@ -17,7 +17,7 @@
     <description>Integration of Hibernate with Infinispan</description>
 
     <properties>
-      <version.infinispan>4.0.0-SNAPSHOT</version.infinispan>
+      <version.infinispan>4.0.0.CR2</version.infinispan>
       <version.hsqldb>1.8.0.2</version.hsqldb>
       <version.cglib>2.2</version.cglib>
       <version.javassist>3.4.GA</version.javassist>

Modified: core/trunk/cache-infinispan/src/main/java/org/hibernate/cache/infinispan/InfinispanRegionFactory.java
===================================================================
--- core/trunk/cache-infinispan/src/main/java/org/hibernate/cache/infinispan/InfinispanRegionFactory.java	2009-11-18 16:35:28 UTC (rev 18004)
+++ core/trunk/cache-infinispan/src/main/java/org/hibernate/cache/infinispan/InfinispanRegionFactory.java	2009-11-18 16:56:13 UTC (rev 18005)
@@ -32,8 +32,8 @@
 import org.infinispan.config.Configuration;
 import org.infinispan.manager.CacheManager;
 import org.infinispan.manager.DefaultCacheManager;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import org.infinispan.util.logging.Log;
+import org.infinispan.util.logging.LogFactory;
 
 /**
  * A {@link RegionFactory} for <a href="http://www.jboss.org/infinispan">Infinispan</a>-backed cache
@@ -44,13 +44,13 @@
  * @since 3.5
  */
 public class InfinispanRegionFactory implements RegionFactory {
-   
-   private static final Logger log = LoggerFactory.getLogger(InfinispanRegionFactory.class);
-   
+
+   private static final Log log = LogFactory.getLog(InfinispanRegionFactory.class);
+
    private static final String PREFIX = "hibernate.cache.infinispan.";
-   
+
    private static final String CONFIG_SUFFIX = ".cfg";
-   
+
    private static final String STRATEGY_SUFFIX = ".eviction.strategy";
 
    private static final String WAKE_UP_INTERVAL_SUFFIX = ".eviction.wake_up_interval";

Modified: core/trunk/cache-infinispan/src/main/java/org/hibernate/cache/infinispan/JndiInfinispanRegionFactory.java
===================================================================
--- core/trunk/cache-infinispan/src/main/java/org/hibernate/cache/infinispan/JndiInfinispanRegionFactory.java	2009-11-18 16:35:28 UTC (rev 18004)
+++ core/trunk/cache-infinispan/src/main/java/org/hibernate/cache/infinispan/JndiInfinispanRegionFactory.java	2009-11-18 16:56:13 UTC (rev 18005)
@@ -32,8 +32,8 @@
 import org.hibernate.util.NamingHelper;
 import org.hibernate.util.PropertiesHelper;
 import org.infinispan.manager.CacheManager;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import org.infinispan.util.logging.Log;
+import org.infinispan.util.logging.LogFactory;
 
 /**
  * A {@link RegionFactory} for <a href="http://www.jboss.org/infinispan">Infinispan</a>-backed cache
@@ -44,7 +44,7 @@
  */
 public class JndiInfinispanRegionFactory extends InfinispanRegionFactory {
 
-   private static final Logger log = LoggerFactory.getLogger(JndiInfinispanRegionFactory.class);
+   private static final Log log = LogFactory.getLog(JndiInfinispanRegionFactory.class);
 
    /**
     * Specifies the JNDI name under which the {@link CacheManager} to use is bound.

Added: core/trunk/cache-infinispan/src/main/java/org/hibernate/cache/infinispan/access/PutFromLoadValidator.java
===================================================================
--- core/trunk/cache-infinispan/src/main/java/org/hibernate/cache/infinispan/access/PutFromLoadValidator.java	                        (rev 0)
+++ core/trunk/cache-infinispan/src/main/java/org/hibernate/cache/infinispan/access/PutFromLoadValidator.java	2009-11-18 16:56:13 UTC (rev 18005)
@@ -0,0 +1,478 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2009, Red Hat, Inc or third-party contributors as
+ * indicated by the @author tags or express copyright attribution
+ * statements applied by the authors.  All third-party contributions are
+ * distributed under license by Red Hat Middleware LLC.
+ *
+ * This copyrighted material is made available to anyone wishing to use, modify,
+ * copy, or redistribute it subject to the terms and conditions of the GNU
+ * Lesser General Public License, as published by the Free Software Foundation.
+ *
+ * This program 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 distribution; if not, write to:
+ * Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA  02110-1301  USA
+ */
+package org.hibernate.cache.infinispan.access;
+
+import java.lang.ref.WeakReference;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+import javax.transaction.SystemException;
+import javax.transaction.Transaction;
+import javax.transaction.TransactionManager;
+
+import org.hibernate.cache.CacheException;
+
+/**
+ * Encapsulates logic to allow a {@link TransactionalAccessDelegate} to determine
+ * whether a {@link TransactionalAccessDelegate#putFromLoad(Object, Object, long, Object, boolean)
+ * call should be allowed to update the cache. A <code>putFromLoad</code> has
+ * the potential to store stale data, since the data may have been removed from the
+ * database and the cache between the time when the data was read from the database 
+ * and the actual call to <code>putFromLoad</code>.
+ *
+ * @author Brian Stansberry
+ * 
+ * @version $Revision: $
+ */
+public class PutFromLoadValidator {
+   /**
+    * Period in ms after a removal during which a call to {@link #isPutValid(Object)} that hasn't
+    * been {@link #registerPendingPut(Object) pre-registered} (aka a "naked put") will return false.
+    */
+   public static final long NAKED_PUT_INVALIDATION_PERIOD = 10 * 1000;
+
+   /** Period after which a pending put is placed in the over-age queue */
+   private static final long PENDING_PUT_OVERAGE_PERIOD = 5 * 1000;
+
+   /** Period before which we stop trying to clean out pending puts */
+   private static final long PENDING_PUT_RECENT_PERIOD = 2 * 1000;
+
+   /**
+    * Period after which a pending put is never expected to come in and should be cleaned
+    */
+   private static final long MAX_PENDING_PUT_DELAY = 2 * 60 * 1000;
+
+   /**
+    * Used to determine whether the owner of a pending put is a thread or a transaction
+    */
+   private final TransactionManager transactionManager;
+
+   private final long nakedPutInvalidationPeriod;
+   private final long pendingPutOveragePeriod;
+   private final long pendingPutRecentPeriod;
+   private final long maxPendingPutDelay;
+
+   /**
+    * Registry of expected, future, isPutValid calls. If a key+owner is registered in this map, it
+    * is not a "naked put" and is allowed to proceed.
+    */
+   private final ConcurrentMap<Object, PendingPutMap> pendingPuts = new ConcurrentHashMap<Object, PendingPutMap>();
+   /**
+    * List of pending puts. Used to ensure we don't leak memory via the pendingPuts map
+    */
+   private final List<WeakReference<PendingPut>> pendingQueue = new LinkedList<WeakReference<PendingPut>>();
+   /**
+    * Separate list of pending puts that haven't been resolved within PENDING_PUT_OVERAGE_PERIOD.
+    * Used to ensure we don't leak memory via the pendingPuts map. Tracked separately from more
+    * recent pending puts for efficiency reasons.
+    */
+   private final List<WeakReference<PendingPut>> overagePendingQueue = new LinkedList<WeakReference<PendingPut>>();
+   /** Lock controlling access to pending put queues */
+   private final Lock pendingLock = new ReentrantLock();
+   private final ConcurrentMap<Object, Long> recentRemovals = new ConcurrentHashMap<Object, Long>();
+   /**
+    * List of recent removals. Used to ensure we don't leak memory via the recentRemovals map
+    */
+   private final List<RecentRemoval> removalsQueue = new LinkedList<RecentRemoval>();
+   /**
+    * The time when the first element in removalsQueue will expire. No reason to do housekeeping on
+    * the queue before this time.
+    */
+   private volatile long earliestRemovalTimestamp;
+   /** Lock controlling access to removalsQueue */
+   private final Lock removalsLock = new ReentrantLock();
+
+   /**
+    * The time of the last call to regionRemoved(), plus NAKED_PUT_INVALIDATION_PERIOD. All naked
+    * puts will be rejected until the current time is greater than this value.
+    */
+   private volatile long invalidationTimestamp;
+
+   /**
+    * Creates a new PutFromLoadValidator.
+    * 
+    * @param transactionManager
+    *           transaction manager to use to associated changes with a transaction; may be
+    *           <code>null</code>
+    */
+   public PutFromLoadValidator(TransactionManager transactionManager) {
+      this(transactionManager, NAKED_PUT_INVALIDATION_PERIOD, PENDING_PUT_OVERAGE_PERIOD,
+               PENDING_PUT_RECENT_PERIOD, MAX_PENDING_PUT_DELAY);
+   }
+
+   /**
+    * Constructor variant for use by unit tests; allows control of various timeouts by the test.
+    */
+   protected PutFromLoadValidator(TransactionManager transactionManager,
+            long nakedPutInvalidationPeriod, long pendingPutOveragePeriod,
+            long pendingPutRecentPeriod, long maxPendingPutDelay) {
+      this.transactionManager = transactionManager;
+      this.nakedPutInvalidationPeriod = nakedPutInvalidationPeriod;
+      this.pendingPutOveragePeriod = pendingPutOveragePeriod;
+      this.pendingPutRecentPeriod = pendingPutRecentPeriod;
+      this.maxPendingPutDelay = maxPendingPutDelay;
+   }
+
+   // ----------------------------------------------------------------- Public
+
+   public boolean isPutValid(Object key) {
+      boolean valid = false;
+      long now = System.currentTimeMillis();
+
+      PendingPutMap pending = pendingPuts.get(key);
+      if (pending != null) {
+         synchronized (pending) {
+            PendingPut toCancel = pending.remove(getOwnerForPut());
+            valid = toCancel != null;
+            if (valid) {
+               toCancel.completed = true;
+               if (pending.size() == 0) {
+                  pendingPuts.remove(key);
+               }
+            }
+         }
+      }
+
+      if (!valid) {
+         if (now > invalidationTimestamp) {
+            Long removedTime = recentRemovals.get(key);
+            if (removedTime == null || now > removedTime.longValue()) {
+               valid = true;
+            }
+         }
+      }
+
+      cleanOutdatedPendingPuts(now, true);
+
+      return valid;
+   }
+
+   public void keyRemoved(Object key) {
+      // Invalidate any pending puts
+      pendingPuts.remove(key);
+
+      // Record when this occurred to invalidate later naked puts
+      RecentRemoval removal = new RecentRemoval(key, this.nakedPutInvalidationPeriod);
+      recentRemovals.put(key, removal.timestamp);
+
+      // Don't let recentRemovals map become a memory leak
+      RecentRemoval toClean = null;
+      boolean attemptClean = removal.timestamp.longValue() > earliestRemovalTimestamp;
+      removalsLock.lock();
+      try {
+         removalsQueue.add(removal);
+
+         if (attemptClean) {
+            if (removalsQueue.size() > 1) { // we have at least one as we
+               // just added it
+               toClean = removalsQueue.remove(0);
+            }
+            earliestRemovalTimestamp = removalsQueue.get(0).timestamp.longValue();
+         }
+      } finally {
+         removalsLock.unlock();
+      }
+
+      if (toClean != null) {
+         Long cleaned = recentRemovals.get(toClean.key);
+         if (cleaned != null && cleaned.equals(toClean.timestamp)) {
+            cleaned = recentRemovals.remove(toClean.key);
+            if (cleaned != null && cleaned.equals(toClean.timestamp) == false) {
+               // Oops; removed the wrong timestamp; restore it
+               recentRemovals.putIfAbsent(toClean.key, cleaned);
+            }
+         }
+      }
+   }
+
+   public void cleared() {
+      invalidationTimestamp = System.currentTimeMillis() + this.nakedPutInvalidationPeriod;
+      pendingLock.lock();
+      try {
+         removalsLock.lock();
+         try {
+            pendingPuts.clear();
+            pendingQueue.clear();
+            overagePendingQueue.clear();
+            recentRemovals.clear();
+            removalsQueue.clear();
+            earliestRemovalTimestamp = invalidationTimestamp;
+
+         } finally {
+            removalsLock.unlock();
+         }
+      } finally {
+         pendingLock.unlock();
+      }
+   }
+
+   /**
+    * Notifies this validator that it is expected that a database read followed by a subsequent
+    * {@link #isPutValid(Object)} call will occur. The intent is this method would be called
+    * following a cache miss wherein it is expected that a database read plus cache put will occur.
+    * Calling this method allows the validator to treat the subsequent <code>isPutValid</code> as if
+    * the database read occurred when this method was invoked. This allows the validator to compare
+    * the timestamp of this call against the timestamp of subsequent removal notifications. A put
+    * that occurs without this call preceding it is "naked"; i.e the validator must assume the put
+    * is not valid if any relevant removal has occurred within
+    * {@link #NAKED_PUT_INVALIDATION_PERIOD} milliseconds.
+    * 
+    * @param key
+    *           key that will be used for subsequent put
+    */
+   public void registerPendingPut(Object key) {
+      PendingPut pendingPut = new PendingPut(key, getOwnerForPut());
+      PendingPutMap pendingForKey = new PendingPutMap();
+      synchronized (pendingForKey) {
+         for (;;) {
+            PendingPutMap existing = pendingPuts.putIfAbsent(key, pendingForKey);
+            if (existing != null && existing != pendingForKey) {
+               synchronized (existing) {
+                  existing.put(pendingPut);
+                  PendingPutMap doublecheck = pendingPuts.putIfAbsent(key, existing);
+                  if (doublecheck == null || doublecheck == existing) {
+                     break;
+                  }
+                  // else we hit a race and need to loop to try again
+               }
+            } else {
+               pendingForKey.put(pendingPut);
+               break;
+            }
+         }
+      }
+
+      // Guard against memory leaks
+      preventOutdatedPendingPuts(pendingPut);
+   }
+
+   // -------------------------------------------------------------- Protected
+
+   /** Only for use by unit tests; may be removed at any time */
+   protected int getPendingPutQueueLength() {
+      pendingLock.lock();
+      try {
+         return pendingQueue.size();
+      } finally {
+         pendingLock.unlock();
+      }
+   }
+
+   /** Only for use by unit tests; may be removed at any time */
+   protected int getOveragePendingPutQueueLength() {
+      pendingLock.lock();
+      try {
+         return overagePendingQueue.size();
+      } finally {
+         pendingLock.unlock();
+      }
+   }
+
+   /** Only for use by unit tests; may be removed at any time */
+   protected int getRemovalQueueLength() {
+      removalsLock.lock();
+      try {
+         return removalsQueue.size();
+      } finally {
+         removalsLock.unlock();
+      }
+   }
+
+   // ---------------------------------------------------------------- Private
+
+   private Object getOwnerForPut() {
+      Transaction tx = null;
+      try {
+         if (transactionManager != null) {
+            tx = transactionManager.getTransaction();
+         }
+      } catch (SystemException se) {
+         throw new CacheException("Could not obtain transaction", se);
+      }
+      return tx == null ? Thread.currentThread() : tx;
+
+   }
+
+   private void preventOutdatedPendingPuts(PendingPut pendingPut) {
+      pendingLock.lock();
+      try {
+         pendingQueue.add(new WeakReference<PendingPut>(pendingPut));
+         cleanOutdatedPendingPuts(pendingPut.timestamp, false);
+      } finally {
+         pendingLock.unlock();
+      }
+   }
+
+   private void cleanOutdatedPendingPuts(long now, boolean lock) {
+
+      PendingPut toClean = null;
+      if (lock) {
+         pendingLock.lock();
+      }
+      try {
+
+         // Clean items out of the basic queue
+
+         long overaged = now - this.pendingPutOveragePeriod;
+         long recent = now - this.pendingPutRecentPeriod;
+
+         int pos = 0;
+         while (pendingQueue.size() > pos) {
+            WeakReference<PendingPut> ref = pendingQueue.get(pos);
+            PendingPut item = ref.get();
+            if (item == null || item.completed) {
+               pendingQueue.remove(pos);
+            } else if (item.timestamp < overaged) {
+               // Potential leak; move to the overaged queued
+               pendingQueue.remove(pos);
+               overagePendingQueue.add(ref);
+            } else if (item.timestamp >= recent) {
+               // Don't waste time on very recent items
+               break;
+            } else if (pos > 2) {
+               // Don't spend too much time getting nowhere
+               break;
+            } else {
+               // Move on to the next item
+               pos++;
+            }
+         }
+
+         // Process the overage queue until we find an item to clean
+         // or an incomplete item that hasn't aged out
+         long mustCleanTime = now - this.maxPendingPutDelay;
+
+         while (overagePendingQueue.size() > 0) {
+            WeakReference<PendingPut> ref = overagePendingQueue.get(0);
+            PendingPut item = ref.get();
+            if (item == null || item.completed) {
+               overagePendingQueue.remove(0);
+            } else {
+               if (item.timestamp < mustCleanTime) {
+                  overagePendingQueue.remove(0);
+                  toClean = item;
+               }
+               break;
+            }
+         }
+      } finally {
+         if (lock) {
+            pendingLock.unlock();
+         }
+      }
+
+      // We've found a pendingPut that never happened; clean it up
+      if (toClean != null) {
+         PendingPutMap map = pendingPuts.get(toClean.key);
+         if (map != null) {
+            synchronized (map) {
+               PendingPut cleaned = map.remove(toClean.owner);
+               if (toClean.equals(cleaned) == false) {
+                  // Oops. Restore it.
+                  map.put(cleaned);
+               } else if (map.size() == 0) {
+                  pendingPuts.remove(toClean.key);
+               }
+            }
+         }
+      }
+
+   }
+
+   /**
+    * Lazy-initialization map for PendingPut. Optimized for the expected usual case where only a
+    * single put is pending for a given key.
+    * 
+    * This class is NOT THREAD SAFE. All operations on it must be performed with the object monitor
+    * held.
+    */
+   private static class PendingPutMap {
+      private PendingPut singlePendingPut;
+      private Map<Object, PendingPut> fullMap;
+
+      public void put(PendingPut pendingPut) {
+         if (singlePendingPut == null) {
+            if (fullMap == null) {
+               // initial put
+               singlePendingPut = pendingPut;
+            } else {
+               fullMap.put(pendingPut.owner, pendingPut);
+            }
+         } else {
+            // 2nd put; need a map
+            fullMap = new HashMap<Object, PendingPut>(4);
+            fullMap.put(singlePendingPut.owner, singlePendingPut);
+            singlePendingPut = null;
+            fullMap.put(pendingPut.owner, pendingPut);
+         }
+      }
+
+      public PendingPut remove(Object ownerForPut) {
+         PendingPut removed = null;
+         if (fullMap == null) {
+            if (singlePendingPut != null && singlePendingPut.owner.equals(ownerForPut)) {
+               removed = singlePendingPut;
+               singlePendingPut = null;
+            }
+         } else {
+            removed = fullMap.remove(ownerForPut);
+         }
+         return removed;
+      }
+
+      public int size() {
+         return fullMap == null ? (singlePendingPut == null ? 0 : 1) : fullMap.size();
+      }
+   }
+
+   private static class PendingPut {
+      private final Object key;
+      private final Object owner;
+      private final long timestamp = System.currentTimeMillis();
+      private volatile boolean completed;
+
+      private PendingPut(Object key, Object owner) {
+         this.key = key;
+         this.owner = owner;
+      }
+
+   }
+
+   private static class RecentRemoval {
+      private final Object key;
+      private final Long timestamp;
+
+      private RecentRemoval(Object key, long nakedPutInvalidationPeriod) {
+         this.key = key;
+         timestamp = Long.valueOf(System.currentTimeMillis() + nakedPutInvalidationPeriod);
+      }
+   }
+
+}

Modified: core/trunk/cache-infinispan/src/main/java/org/hibernate/cache/infinispan/access/TransactionalAccessDelegate.java
===================================================================
--- core/trunk/cache-infinispan/src/main/java/org/hibernate/cache/infinispan/access/TransactionalAccessDelegate.java	2009-11-18 16:35:28 UTC (rev 18004)
+++ core/trunk/cache-infinispan/src/main/java/org/hibernate/cache/infinispan/access/TransactionalAccessDelegate.java	2009-11-18 16:56:13 UTC (rev 18005)
@@ -32,6 +32,8 @@
 import org.hibernate.cache.infinispan.impl.BaseRegion;
 import org.hibernate.cache.infinispan.util.CacheAdapter;
 import org.hibernate.cache.infinispan.util.CacheHelper;
+import org.infinispan.util.logging.Log;
+import org.infinispan.util.logging.LogFactory;
 
 /**
  * Defines the strategy for transactional access to entity or collection data in a Infinispan instance.
@@ -44,31 +46,50 @@
  * @since 3.5
  */
 public class TransactionalAccessDelegate {
-
+   private static final Log log = LogFactory.getLog(TransactionalAccessDelegate.class);
    protected final CacheAdapter cacheAdapter;
    protected final BaseRegion region;
+   protected final PutFromLoadValidator putValidator;
 
-   public TransactionalAccessDelegate(BaseRegion region) {
+   public TransactionalAccessDelegate(BaseRegion region, PutFromLoadValidator validator) {
       this.region = region;
       this.cacheAdapter = region.getCacheAdapter();
+      this.putValidator = validator;
    }
 
    public Object get(Object key, long txTimestamp) throws CacheException {
       if (!region.checkValid()) 
          return null;
-      return cacheAdapter.get(key);
+      Object val = cacheAdapter.get(key);
+      if (val == null)
+         putValidator.registerPendingPut(key);
+      return val;
    }
 
    public boolean putFromLoad(Object key, Object value, long txTimestamp, Object version) throws CacheException {
-      if (!region.checkValid())
+      if (!region.checkValid()) {
          return false;
+      }
+      if (!putValidator.isPutValid(key)) {
+         return false;
+      }
       cacheAdapter.putForExternalRead(key, value);
       return true;
    }
 
    public boolean putFromLoad(Object key, Object value, long txTimestamp, Object version, boolean minimalPutOverride)
             throws CacheException {
-      return putFromLoad(key, value, txTimestamp, version);
+      boolean trace = log.isTraceEnabled();
+      if (!region.checkValid()) {
+         if (trace) log.trace("Region not valid");
+         return false;
+      }
+      if (!putValidator.isPutValid(key)) {
+         if (trace) log.trace("Put {0} not valid", key);
+         return false;
+      }
+      cacheAdapter.putForExternalRead(key, value);
+      return true;
    }
 
    public SoftLock lockItem(Object key, Object version) throws CacheException {
@@ -113,18 +134,22 @@
       // We update whether or not the region is valid. Other nodes
       // may have already restored the region so they need to
       // be informed of the change.
+      putValidator.keyRemoved(key);
       cacheAdapter.remove(key);
    }
 
    public void removeAll() throws CacheException {
+      putValidator.cleared();
       cacheAdapter.clear();
    }
 
    public void evict(Object key) throws CacheException {
+      putValidator.keyRemoved(key);
       cacheAdapter.remove(key);
    }
 
    public void evictAll() throws CacheException {
+      putValidator.cleared();
       Transaction tx = region.suspend();
       try {
          CacheHelper.sendEvictAllNotification(cacheAdapter, region.getAddress());

Modified: core/trunk/cache-infinispan/src/main/java/org/hibernate/cache/infinispan/collection/CollectionRegionImpl.java
===================================================================
--- core/trunk/cache-infinispan/src/main/java/org/hibernate/cache/infinispan/collection/CollectionRegionImpl.java	2009-11-18 16:35:28 UTC (rev 18004)
+++ core/trunk/cache-infinispan/src/main/java/org/hibernate/cache/infinispan/collection/CollectionRegionImpl.java	2009-11-18 16:56:13 UTC (rev 18005)
@@ -7,6 +7,7 @@
 import org.hibernate.cache.CollectionRegion;
 import org.hibernate.cache.access.AccessType;
 import org.hibernate.cache.access.CollectionRegionAccessStrategy;
+import org.hibernate.cache.infinispan.access.PutFromLoadValidator;
 import org.hibernate.cache.infinispan.impl.BaseTransactionalDataRegion;
 import org.hibernate.cache.infinispan.util.CacheAdapter;
 import org.infinispan.notifications.Listener;
@@ -32,4 +33,7 @@
       throw new CacheException("Unsupported access type [" + accessType.getName() + "]");
    }
 
+   public PutFromLoadValidator getPutFromLoadValidator() {
+      return new PutFromLoadValidator(transactionManager);
+   }
 }

Modified: core/trunk/cache-infinispan/src/main/java/org/hibernate/cache/infinispan/collection/ReadOnlyAccess.java
===================================================================
--- core/trunk/cache-infinispan/src/main/java/org/hibernate/cache/infinispan/collection/ReadOnlyAccess.java	2009-11-18 16:35:28 UTC (rev 18004)
+++ core/trunk/cache-infinispan/src/main/java/org/hibernate/cache/infinispan/collection/ReadOnlyAccess.java	2009-11-18 16:56:13 UTC (rev 18005)
@@ -2,8 +2,8 @@
 
 import org.hibernate.cache.CacheException;
 import org.hibernate.cache.access.SoftLock;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import org.infinispan.util.logging.Log;
+import org.infinispan.util.logging.LogFactory;
 
 /**
  * This defines the strategy for transactional access to collection data in a
@@ -17,7 +17,7 @@
  * @since 3.5
  */
 class ReadOnlyAccess extends TransactionalAccess {
-   private static final Logger log = LoggerFactory.getLogger(ReadOnlyAccess.class);
+   private static final Log log = LogFactory.getLog(ReadOnlyAccess.class);
 
    ReadOnlyAccess(CollectionRegionImpl region) {
       super(region);

Modified: core/trunk/cache-infinispan/src/main/java/org/hibernate/cache/infinispan/collection/TransactionalAccess.java
===================================================================
--- core/trunk/cache-infinispan/src/main/java/org/hibernate/cache/infinispan/collection/TransactionalAccess.java	2009-11-18 16:35:28 UTC (rev 18004)
+++ core/trunk/cache-infinispan/src/main/java/org/hibernate/cache/infinispan/collection/TransactionalAccess.java	2009-11-18 16:56:13 UTC (rev 18005)
@@ -21,7 +21,7 @@
 
    TransactionalAccess(CollectionRegionImpl region) {
       this.region = region;
-      this.delegate = new TransactionalAccessDelegate(region);
+      this.delegate = new TransactionalAccessDelegate(region, region.getPutFromLoadValidator());
    }
 
    public void evict(Object key) throws CacheException {

Modified: core/trunk/cache-infinispan/src/main/java/org/hibernate/cache/infinispan/entity/EntityRegionImpl.java
===================================================================
--- core/trunk/cache-infinispan/src/main/java/org/hibernate/cache/infinispan/entity/EntityRegionImpl.java	2009-11-18 16:35:28 UTC (rev 18004)
+++ core/trunk/cache-infinispan/src/main/java/org/hibernate/cache/infinispan/entity/EntityRegionImpl.java	2009-11-18 16:56:13 UTC (rev 18005)
@@ -7,6 +7,7 @@
 import org.hibernate.cache.EntityRegion;
 import org.hibernate.cache.access.AccessType;
 import org.hibernate.cache.access.EntityRegionAccessStrategy;
+import org.hibernate.cache.infinispan.access.PutFromLoadValidator;
 import org.hibernate.cache.infinispan.impl.BaseTransactionalDataRegion;
 import org.hibernate.cache.infinispan.util.CacheAdapter;
 import org.infinispan.notifications.Listener;
@@ -32,4 +33,7 @@
       throw new CacheException("Unsupported access type [" + accessType.getName() + "]");
    }
 
+   public PutFromLoadValidator getPutFromLoadValidator() {
+      return new PutFromLoadValidator(transactionManager);
+   }
 }
\ No newline at end of file

Modified: core/trunk/cache-infinispan/src/main/java/org/hibernate/cache/infinispan/entity/ReadOnlyAccess.java
===================================================================
--- core/trunk/cache-infinispan/src/main/java/org/hibernate/cache/infinispan/entity/ReadOnlyAccess.java	2009-11-18 16:35:28 UTC (rev 18004)
+++ core/trunk/cache-infinispan/src/main/java/org/hibernate/cache/infinispan/entity/ReadOnlyAccess.java	2009-11-18 16:56:13 UTC (rev 18005)
@@ -2,8 +2,8 @@
 
 import org.hibernate.cache.CacheException;
 import org.hibernate.cache.access.SoftLock;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import org.infinispan.util.logging.Log;
+import org.infinispan.util.logging.LogFactory;
 
 /**
  * A specialization of {@link TransactionalAccess} that ensures we never update data. Infinispan
@@ -14,7 +14,7 @@
  * @since 3.5
  */
 class ReadOnlyAccess extends TransactionalAccess {
-   private static final Logger log = LoggerFactory.getLogger(ReadOnlyAccess.class);
+   private static final Log log = LogFactory.getLog(ReadOnlyAccess.class);
 
    ReadOnlyAccess(EntityRegionImpl region) {
       super(region);

Modified: core/trunk/cache-infinispan/src/main/java/org/hibernate/cache/infinispan/entity/TransactionalAccess.java
===================================================================
--- core/trunk/cache-infinispan/src/main/java/org/hibernate/cache/infinispan/entity/TransactionalAccess.java	2009-11-18 16:35:28 UTC (rev 18004)
+++ core/trunk/cache-infinispan/src/main/java/org/hibernate/cache/infinispan/entity/TransactionalAccess.java	2009-11-18 16:56:13 UTC (rev 18005)
@@ -21,7 +21,7 @@
 
    TransactionalAccess(EntityRegionImpl region) {
       this.region = region;
-      this.delegate = new TransactionalAccessDelegate(region);
+      this.delegate = new TransactionalAccessDelegate(region, region.getPutFromLoadValidator());
    }
 
    public void evict(Object key) throws CacheException {

Modified: core/trunk/cache-infinispan/src/main/java/org/hibernate/cache/infinispan/impl/BaseRegion.java
===================================================================
--- core/trunk/cache-infinispan/src/main/java/org/hibernate/cache/infinispan/impl/BaseRegion.java	2009-11-18 16:35:28 UTC (rev 18004)
+++ core/trunk/cache-infinispan/src/main/java/org/hibernate/cache/infinispan/impl/BaseRegion.java	2009-11-18 16:56:13 UTC (rev 18005)
@@ -1,6 +1,7 @@
 package org.hibernate.cache.infinispan.impl;
 
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
@@ -130,11 +131,13 @@
 
    public Map toMap() {
       if (checkValid()) {
-         Map map = cacheAdapter.toMap();
-         Set keys = map.keySet();
-         for (Object key : keys) {
-            if (CacheHelper.isEvictAllNotification(key)) {
-               map.remove(key);
+         // If copying causes issues, provide a lazily loaded Map
+         Map map = new HashMap();
+         Set<Map.Entry> entries = cacheAdapter.toMap().entrySet();
+         for (Map.Entry entry : entries) {
+            Object key = entry.getKey();
+            if (!CacheHelper.isEvictAllNotification(key)) {
+               map.put(key, entry.getValue());
             }
          }
          return map;
@@ -149,7 +152,7 @@
          cacheAdapter.removeListener(this);
       }
    }
-   
+
    public boolean contains(Object key) {
       if (!checkValid())
          return false;
@@ -209,7 +212,19 @@
            resume(tx);
        }
    }
-   
+
+   public Object getOwnerForPut() {
+      Transaction tx = null;
+      try {
+          if (transactionManager != null) {
+              tx = transactionManager.getTransaction();
+          }
+      } catch (SystemException se) {
+          throw new CacheException("Could not obtain transaction", se);
+      }
+      return tx == null ? Thread.currentThread() : tx;
+   }
+
    /**
     * Tell the TransactionManager to suspend any ongoing transaction.
     * 

Modified: core/trunk/cache-infinispan/src/main/java/org/hibernate/cache/infinispan/util/CacheHelper.java
===================================================================
--- core/trunk/cache-infinispan/src/main/java/org/hibernate/cache/infinispan/util/CacheHelper.java	2009-11-18 16:35:28 UTC (rev 18004)
+++ core/trunk/cache-infinispan/src/main/java/org/hibernate/cache/infinispan/util/CacheHelper.java	2009-11-18 16:56:13 UTC (rev 18005)
@@ -29,8 +29,8 @@
 import java.io.ObjectOutput;
 import java.util.Set;
 
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import org.infinispan.util.logging.Log;
+import org.infinispan.util.logging.LogFactory;
 
 /**
  * Helper for dealing with Infinisan cache instances.
@@ -40,7 +40,7 @@
  */
 public class CacheHelper {
 
-   private static final Logger log = LoggerFactory.getLogger(CacheHelper.class);
+   private static final Log log = LogFactory.getLog(CacheHelper.class);
 
    /**
     * Disallow external instantiation of CacheHelper.

Added: core/trunk/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/access/PutFromLoadValidatorUnitTestCase.java
===================================================================
--- core/trunk/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/access/PutFromLoadValidatorUnitTestCase.java	                        (rev 0)
+++ core/trunk/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/access/PutFromLoadValidatorUnitTestCase.java	2009-11-18 16:56:13 UTC (rev 18005)
@@ -0,0 +1,414 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2009, Red Hat, Inc or third-party contributors as
+ * indicated by the @author tags or express copyright attribution
+ * statements applied by the authors.  All third-party contributions are
+ * distributed under license by Red Hat Middleware LLC.
+ *
+ * This copyrighted material is made available to anyone wishing to use, modify,
+ * copy, or redistribute it subject to the terms and conditions of the GNU
+ * Lesser General Public License, as published by the Free Software Foundation.
+ *
+ * This program 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 distribution; if not, write to:
+ * Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA  02110-1301  USA
+ */
+package org.hibernate.test.cache.infinispan.access;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import javax.transaction.Transaction;
+import javax.transaction.TransactionManager;
+
+import org.hibernate.cache.infinispan.access.PutFromLoadValidator;
+import org.hibernate.test.cache.infinispan.functional.cluster.DualNodeJtaTransactionManagerImpl;
+
+import junit.framework.TestCase;
+
+/**
+ * Tests of {@link PutFromLoadValidator}.
+ * 
+ * @author Brian Stansberry
+ * @author Galder Zamarreño
+ * 
+ * @version $Revision: $
+ */
+public class PutFromLoadValidatorUnitTestCase extends TestCase {
+   private Object KEY1 = "KEY1";
+
+   private TransactionManager tm;
+
+   public PutFromLoadValidatorUnitTestCase(String name) {
+      super(name);
+   }
+
+   @Override
+   protected void setUp() throws Exception {
+      super.setUp();
+      tm = DualNodeJtaTransactionManagerImpl.getInstance("test");
+   }
+
+   @Override
+   protected void tearDown() throws Exception {
+      try {
+         super.tearDown();
+      } finally {
+         tm = null;
+         try {
+            DualNodeJtaTransactionManagerImpl.cleanupTransactions();
+         } finally {
+            DualNodeJtaTransactionManagerImpl.cleanupTransactionManagers();
+         }
+      }
+   }
+
+   public void testNakedPut() throws Exception {
+      nakedPutTest(false);
+   }
+
+   public void testNakedPutTransactional() throws Exception {
+      nakedPutTest(true);
+   }
+
+   private void nakedPutTest(boolean transactional) throws Exception {
+      PutFromLoadValidator testee = new PutFromLoadValidator(transactional ? tm : null);
+      if (transactional) {
+         tm.begin();
+      }
+      assertTrue(testee.isPutValid(KEY1));
+   }
+
+   public void testRegisteredPut() throws Exception {
+      registeredPutTest(false);
+   }
+
+   public void testRegisteredPutTransactional() throws Exception {
+      registeredPutTest(true);
+   }
+
+   private void registeredPutTest(boolean transactional) throws Exception {
+      PutFromLoadValidator testee = new PutFromLoadValidator(transactional ? tm : null);
+      if (transactional) {
+         tm.begin();
+      }
+      testee.registerPendingPut(KEY1);
+      assertTrue(testee.isPutValid(KEY1));
+   }
+
+   public void testNakedPutAfterKeyRemoval() throws Exception {
+      nakedPutAfterRemovalTest(false, false);
+   }
+
+   public void testNakedPutAfterKeyRemovalTransactional() throws Exception {
+      nakedPutAfterRemovalTest(true, false);
+   }
+
+   public void testNakedPutAfterRegionRemoval() throws Exception {
+      nakedPutAfterRemovalTest(false, true);
+   }
+
+   public void testNakedPutAfterRegionRemovalTransactional() throws Exception {
+      nakedPutAfterRemovalTest(true, true);
+   }
+
+   private void nakedPutAfterRemovalTest(boolean transactional, boolean removeRegion)
+            throws Exception {
+      PutFromLoadValidator testee = new PutFromLoadValidator(transactional ? tm : null);
+      if (removeRegion) {
+         testee.cleared();
+      } else {
+         testee.keyRemoved(KEY1);
+      }
+      if (transactional) {
+         tm.begin();
+      }
+      assertFalse(testee.isPutValid(KEY1));
+
+   }
+
+   public void testRegisteredPutAfterKeyRemoval() throws Exception {
+      registeredPutAfterRemovalTest(false, false);
+   }
+
+   public void testRegisteredPutAfterKeyRemovalTransactional() throws Exception {
+      registeredPutAfterRemovalTest(true, false);
+   }
+
+   public void testRegisteredPutAfterRegionRemoval() throws Exception {
+      registeredPutAfterRemovalTest(false, true);
+   }
+
+   public void testRegisteredPutAfterRegionRemovalTransactional() throws Exception {
+      registeredPutAfterRemovalTest(true, true);
+   }
+
+   private void registeredPutAfterRemovalTest(boolean transactional, boolean removeRegion)
+            throws Exception {
+      PutFromLoadValidator testee = new PutFromLoadValidator(transactional ? tm : null);
+      if (removeRegion) {
+         testee.cleared();
+      } else {
+         testee.keyRemoved(KEY1);
+      }
+      if (transactional) {
+         tm.begin();
+      }
+      testee.registerPendingPut(KEY1);
+      assertTrue(testee.isPutValid(KEY1));
+   }
+
+   public void testRegisteredPutWithInterveningKeyRemoval() throws Exception {
+      registeredPutWithInterveningRemovalTest(false, false);
+   }
+
+   public void testRegisteredPutWithInterveningKeyRemovalTransactional() throws Exception {
+      registeredPutWithInterveningRemovalTest(true, false);
+   }
+
+   public void testRegisteredPutWithInterveningRegionRemoval() throws Exception {
+      registeredPutWithInterveningRemovalTest(false, true);
+   }
+
+   public void testRegisteredPutWithInterveningRegionRemovalTransactional() throws Exception {
+      registeredPutWithInterveningRemovalTest(true, true);
+   }
+
+   private void registeredPutWithInterveningRemovalTest(boolean transactional, boolean removeRegion)
+            throws Exception {
+      PutFromLoadValidator testee = new PutFromLoadValidator(transactional ? tm : null);
+      if (transactional) {
+         tm.begin();
+      }
+      testee.registerPendingPut(KEY1);
+      if (removeRegion) {
+         testee.cleared();
+      } else {
+         testee.keyRemoved(KEY1);
+      }
+      assertFalse(testee.isPutValid(KEY1));
+   }
+
+   public void testDelayedNakedPutAfterKeyRemoval() throws Exception {
+      delayedNakedPutAfterRemovalTest(false, false);
+   }
+
+   public void testDelayedNakedPutAfterKeyRemovalTransactional() throws Exception {
+      delayedNakedPutAfterRemovalTest(true, false);
+   }
+
+   public void testDelayedNakedPutAfterRegionRemoval() throws Exception {
+      delayedNakedPutAfterRemovalTest(false, true);
+   }
+
+   public void testDelayedNakedPutAfterRegionRemovalTransactional() throws Exception {
+      delayedNakedPutAfterRemovalTest(true, true);
+   }
+
+   private void delayedNakedPutAfterRemovalTest(boolean transactional, boolean removeRegion)
+            throws Exception {
+      PutFromLoadValidator testee = new TestValidator(transactional ? tm : null, 100, 1000, 500,
+               10000);
+      if (removeRegion) {
+         testee.cleared();
+      } else {
+         testee.keyRemoved(KEY1);
+      }
+      if (transactional) {
+         tm.begin();
+      }
+      Thread.sleep(110);
+      assertTrue(testee.isPutValid(KEY1));
+
+   }
+
+   public void testMultipleRegistrations() throws Exception {
+      multipleRegistrationtest(false);
+   }
+
+   public void testMultipleRegistrationsTransactional() throws Exception {
+      multipleRegistrationtest(true);
+   }
+
+   private void multipleRegistrationtest(final boolean transactional) throws Exception {
+      final PutFromLoadValidator testee = new PutFromLoadValidator(transactional ? tm : null);
+
+      final CountDownLatch registeredLatch = new CountDownLatch(3);
+      final CountDownLatch finishedLatch = new CountDownLatch(3);
+      final AtomicInteger success = new AtomicInteger();
+
+      Runnable r = new Runnable() {
+         public void run() {
+            try {
+               if (transactional) {
+                  tm.begin();
+               }
+               testee.registerPendingPut(KEY1);
+               registeredLatch.countDown();
+               registeredLatch.await(5, TimeUnit.SECONDS);
+               if (testee.isPutValid(KEY1)) {
+                  success.incrementAndGet();
+               }
+               finishedLatch.countDown();
+            } catch (Exception e) {
+               e.printStackTrace();
+            }
+         }
+      };
+
+      ExecutorService executor = Executors.newFixedThreadPool(3);
+
+      // Start with a removal so the "isPutValid" calls will fail if
+      // any of the concurrent activity isn't handled properly
+
+      testee.cleared();
+
+      // Do the registration + isPutValid calls
+      executor.execute(r);
+      executor.execute(r);
+      executor.execute(r);
+
+      finishedLatch.await(5, TimeUnit.SECONDS);
+
+      assertEquals("All threads succeeded", 3, success.get());
+   }
+
+   /**
+    * White box test for ensuring key removals get cleaned up.
+    * 
+    * @throws Exception
+    */
+   public void testRemovalCleanup() throws Exception {
+      TestValidator testee = new TestValidator(null, 200, 1000, 500, 10000);
+      testee.keyRemoved("KEY1");
+      testee.keyRemoved("KEY2");
+      Thread.sleep(210);
+      assertEquals(2, testee.getRemovalQueueLength());
+      testee.keyRemoved("KEY1");
+      assertEquals(2, testee.getRemovalQueueLength());
+      testee.keyRemoved("KEY2");
+      assertEquals(2, testee.getRemovalQueueLength());
+   }
+
+   /**
+    * Very much a white box test of the logic for ensuring pending put registrations get cleaned up.
+    * 
+    * @throws Exception
+    */
+   public void testPendingPutCleanup() throws Exception {
+      TestValidator testee = new TestValidator(tm, 5000, 600, 300, 900);
+
+      // Start with a regionRemoval so we can confirm at the end that all
+      // registrations have been cleaned out
+      testee.cleared();
+
+      testee.registerPendingPut("1");
+      testee.registerPendingPut("2");
+      testee.registerPendingPut("3");
+      testee.registerPendingPut("4");
+      testee.registerPendingPut("5");
+      testee.registerPendingPut("6");
+      testee.isPutValid("6");
+      testee.isPutValid("2");
+      // ppq = [1,2(c),3,4,5,6(c)]
+      assertEquals(6, testee.getPendingPutQueueLength());
+      assertEquals(0, testee.getOveragePendingPutQueueLength());
+
+      // Sleep past "pendingPutRecentPeriod"
+      Thread.sleep(310);
+      testee.registerPendingPut("7");
+      // White box -- should have cleaned out 2 (completed) but
+      // not gotten to 6 (also removed)
+      // ppq = [1,3,4,5,6(c),7]
+      assertEquals(0, testee.getOveragePendingPutQueueLength());
+      assertEquals(6, testee.getPendingPutQueueLength());
+
+      // Sleep past "pendingPutOveragePeriod"
+      Thread.sleep(310);
+      testee.registerPendingPut("8");
+      // White box -- should have cleaned out 6 (completed) and
+      // moved 1, 3, 4 and 5 to overage queue
+      // oppq = [1,3,4,5] ppq = [7,8]
+      assertEquals(4, testee.getOveragePendingPutQueueLength());
+      assertEquals(2, testee.getPendingPutQueueLength());
+
+      // Sleep past "maxPendingPutDelay"
+      Thread.sleep(310);
+      testee.isPutValid("3");
+      // White box -- should have cleaned out 1 (overage) and
+      // moved 7 to overage queue
+      // oppq = [3(c),4,5,7] ppq=[8]
+      assertEquals(4, testee.getOveragePendingPutQueueLength());
+      assertEquals(1, testee.getPendingPutQueueLength());
+
+      // Sleep past "maxPendingPutDelay"
+      Thread.sleep(310);
+      tm.begin();
+      testee.registerPendingPut("7");
+      Transaction tx = tm.suspend();
+
+      // White box -- should have cleaned out 3 (completed)
+      // and 4 (overage) and moved 8 to overage queue
+      // We now have 5,7,8 in overage and 7tx in pending
+      // oppq = [5,7,8] ppq=[7tx]
+      assertEquals(3, testee.getOveragePendingPutQueueLength());
+      assertEquals(1, testee.getPendingPutQueueLength());
+
+      // Validate that only expected items can do puts, thus indirectly
+      // proving the others have been cleaned out of pendingPuts map
+      assertFalse(testee.isPutValid("1"));
+      // 5 was overage, so should have been cleaned
+      assertEquals(2, testee.getOveragePendingPutQueueLength());
+      assertFalse(testee.isPutValid("2"));
+      // 7 was overage, so should have been cleaned
+      assertEquals(1, testee.getOveragePendingPutQueueLength());
+      assertFalse(testee.isPutValid("3"));
+      assertFalse(testee.isPutValid("4"));
+      assertFalse(testee.isPutValid("5"));
+      assertFalse(testee.isPutValid("6"));
+      assertFalse(testee.isPutValid("7"));
+      assertTrue(testee.isPutValid("8"));
+      tm.resume(tx);
+      assertTrue(testee.isPutValid("7"));
+   }
+
+   private static class TestValidator extends PutFromLoadValidator {
+
+      protected TestValidator(TransactionManager transactionManager,
+               long nakedPutInvalidationPeriod, long pendingPutOveragePeriod,
+               long pendingPutRecentPeriod, long maxPendingPutDelay) {
+         super(transactionManager, nakedPutInvalidationPeriod, pendingPutOveragePeriod,
+                  pendingPutRecentPeriod, maxPendingPutDelay);
+      }
+
+      @Override
+      public int getOveragePendingPutQueueLength() {
+         // TODO Auto-generated method stub
+         return super.getOveragePendingPutQueueLength();
+      }
+
+      @Override
+      public int getPendingPutQueueLength() {
+         // TODO Auto-generated method stub
+         return super.getPendingPutQueueLength();
+      }
+
+      @Override
+      public int getRemovalQueueLength() {
+         // TODO Auto-generated method stub
+         return super.getRemovalQueueLength();
+      }
+
+   }
+}

Added: core/trunk/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/collection/CollectionRegionImplTestCase.java
===================================================================
--- core/trunk/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/collection/CollectionRegionImplTestCase.java	                        (rev 0)
+++ core/trunk/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/collection/CollectionRegionImplTestCase.java	2009-11-18 16:56:13 UTC (rev 18005)
@@ -0,0 +1,96 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2007, Red Hat Middleware LLC or third-party contributors as
+ * indicated by the @author tags or express copyright attribution
+ * statements applied by the authors.  All third-party contributions are
+ * distributed under license by Red Hat Middleware LLC.
+ *
+ * This copyrighted material is made available to anyone wishing to use, modify,
+ * copy, or redistribute it subject to the terms and conditions of the GNU
+ * Lesser General Public License, as published by the Free Software Foundation.
+ *
+ * This program 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 distribution; if not, write to:
+ * Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA  02110-1301  USA
+ */
+package org.hibernate.test.cache.infinispan.collection;
+
+import java.util.Properties;
+
+import org.hibernate.cache.CacheDataDescription;
+import org.hibernate.cache.CacheException;
+import org.hibernate.cache.CollectionRegion;
+import org.hibernate.cache.Region;
+import org.hibernate.cache.RegionFactory;
+import org.hibernate.cache.access.AccessType;
+import org.hibernate.cache.access.CollectionRegionAccessStrategy;
+import org.hibernate.cache.infinispan.InfinispanRegionFactory;
+import org.hibernate.cache.infinispan.util.CacheAdapter;
+import org.hibernate.cache.infinispan.util.CacheAdapterImpl;
+import org.hibernate.test.cache.infinispan.AbstractEntityCollectionRegionTestCase;
+
+/**
+ * Tests of CollectionRegionImpl.
+ * 
+ * @author Galder Zamarreño
+ */
+public class CollectionRegionImplTestCase extends AbstractEntityCollectionRegionTestCase {
+
+   public CollectionRegionImplTestCase(String name) {
+      super(name);
+   }
+
+   @Override
+   protected void supportedAccessTypeTest(RegionFactory regionFactory, Properties properties) {
+      CollectionRegion region = regionFactory.buildCollectionRegion("test", properties, null);
+      assertNull("Got TRANSACTIONAL", region.buildAccessStrategy(AccessType.TRANSACTIONAL)
+               .lockRegion());
+      try {
+         region.buildAccessStrategy(AccessType.READ_ONLY).lockRegion();
+         fail("Did not get READ_ONLY");
+      } catch (UnsupportedOperationException good) {
+      }
+
+      try {
+         region.buildAccessStrategy(AccessType.NONSTRICT_READ_WRITE);
+         fail("Incorrectly got NONSTRICT_READ_WRITE");
+      } catch (CacheException good) {
+      }
+
+      try {
+         region.buildAccessStrategy(AccessType.READ_WRITE);
+         fail("Incorrectly got READ_WRITE");
+      } catch (CacheException good) {
+      }
+   }
+
+   @Override
+   protected Region createRegion(InfinispanRegionFactory regionFactory, String regionName, Properties properties, CacheDataDescription cdd) {
+      return regionFactory.buildCollectionRegion(regionName, properties, cdd);
+   }
+
+   @Override
+   protected CacheAdapter getInfinispanCache(InfinispanRegionFactory regionFactory) {
+      return CacheAdapterImpl.newInstance(regionFactory.getCacheManager().getCache(InfinispanRegionFactory.DEF_ENTITY_RESOURCE));
+   }
+
+   @Override
+   protected void putInRegion(Region region, Object key, Object value) {
+      CollectionRegionAccessStrategy strategy = ((CollectionRegion) region).buildAccessStrategy(AccessType.TRANSACTIONAL);
+      strategy.putFromLoad(key, value, System.currentTimeMillis(), new Integer(1));
+   }
+
+   @Override
+   protected void removeFromRegion(Region region, Object key) {
+      ((CollectionRegion) region).buildAccessStrategy(AccessType.TRANSACTIONAL).remove(key);
+   }
+
+}

Modified: core/trunk/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/entity/AbstractEntityRegionAccessStrategyTestCase.java
===================================================================
--- core/trunk/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/entity/AbstractEntityRegionAccessStrategyTestCase.java	2009-11-18 16:35:28 UTC (rev 18004)
+++ core/trunk/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/entity/AbstractEntityRegionAccessStrategyTestCase.java	2009-11-18 16:56:13 UTC (rev 18005)
@@ -434,9 +434,7 @@
       final String KEY = KEY_BASE + testCount++;
 
       // Set up initial state
-      localAccessStrategy.get(KEY, System.currentTimeMillis());
       localAccessStrategy.putFromLoad(KEY, VALUE1, System.currentTimeMillis(), new Integer(1));
-      remoteAccessStrategy.get(KEY, System.currentTimeMillis());
       remoteAccessStrategy.putFromLoad(KEY, VALUE1, System.currentTimeMillis(), new Integer(1));
 
       // Let the async put propagate

Modified: core/trunk/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/entity/AbstractTransactionalAccessTestCase.java
===================================================================
--- core/trunk/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/entity/AbstractTransactionalAccessTestCase.java	2009-11-18 16:35:28 UTC (rev 18004)
+++ core/trunk/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/entity/AbstractTransactionalAccessTestCase.java	2009-11-18 16:56:13 UTC (rev 18005)
@@ -52,7 +52,6 @@
 
       final String KEY = KEY_BASE + testCount++;
 
-      localAccessStrategy.get(KEY, System.currentTimeMillis());
       localAccessStrategy.putFromLoad(KEY, VALUE1, System.currentTimeMillis(), new Integer(1));
 
       final CountDownLatch pferLatch = new CountDownLatch(1);

Modified: core/trunk/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/entity/EntityRegionImplTestCase.java
===================================================================
--- core/trunk/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/entity/EntityRegionImplTestCase.java	2009-11-18 16:35:28 UTC (rev 18004)
+++ core/trunk/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/entity/EntityRegionImplTestCase.java	2009-11-18 16:56:13 UTC (rev 18005)
@@ -43,60 +43,53 @@
  * @since 3.5
  */
 public class EntityRegionImplTestCase extends AbstractEntityCollectionRegionTestCase {
-    
-    public EntityRegionImplTestCase(String name) {
-        super(name);
-    } 
-    
-    @Override
-    protected void supportedAccessTypeTest(RegionFactory regionFactory, Properties properties) {
-        
-        EntityRegion region = regionFactory.buildEntityRegion("test", properties, null);
-        
-        assertNull("Got TRANSACTIONAL", region.buildAccessStrategy(AccessType.TRANSACTIONAL).lockRegion());
-        
-        try
-        {
-            region.buildAccessStrategy(AccessType.READ_ONLY).lockRegion();
-            fail("Did not get READ_ONLY");
-        }
-        catch (UnsupportedOperationException good) {}
-        
-        try
-        {
-            region.buildAccessStrategy(AccessType.NONSTRICT_READ_WRITE);
-            fail("Incorrectly got NONSTRICT_READ_WRITE");
-        }
-        catch (CacheException good) {}
-        
-        try
-        {
-            region.buildAccessStrategy(AccessType.READ_WRITE);
-            fail("Incorrectly got READ_WRITE");
-        }
-        catch (CacheException good) {}      
-        
-    }
 
-    @Override
-    protected void putInRegion(Region region, Object key, Object value) {
-        ((EntityRegion) region).buildAccessStrategy(AccessType.TRANSACTIONAL).insert(key, value, new Integer(1));
-    }
+   public EntityRegionImplTestCase(String name) {
+      super(name);
+   }
 
-    @Override
-    protected void removeFromRegion(Region region, Object key) {
-        ((EntityRegion) region).buildAccessStrategy(AccessType.TRANSACTIONAL).remove(key);
-    }
+   @Override
+   protected void supportedAccessTypeTest(RegionFactory regionFactory, Properties properties) {
+      EntityRegion region = regionFactory.buildEntityRegion("test", properties, null);
+      assertNull("Got TRANSACTIONAL", region.buildAccessStrategy(AccessType.TRANSACTIONAL)
+               .lockRegion());
+      try {
+         region.buildAccessStrategy(AccessType.READ_ONLY).lockRegion();
+         fail("Did not get READ_ONLY");
+      } catch (UnsupportedOperationException good) {
+      }
 
+      try {
+         region.buildAccessStrategy(AccessType.NONSTRICT_READ_WRITE);
+         fail("Incorrectly got NONSTRICT_READ_WRITE");
+      } catch (CacheException good) {
+      }
+
+      try {
+         region.buildAccessStrategy(AccessType.READ_WRITE);
+         fail("Incorrectly got READ_WRITE");
+      } catch (CacheException good) {
+      }
+   }
+
    @Override
-   protected Region createRegion(InfinispanRegionFactory regionFactory, String regionName,
-            Properties properties, CacheDataDescription cdd) {
+   protected void putInRegion(Region region, Object key, Object value) {
+      ((EntityRegion) region).buildAccessStrategy(AccessType.TRANSACTIONAL).insert(key, value, new Integer(1));
+   }
+
+   @Override
+   protected void removeFromRegion(Region region, Object key) {
+      ((EntityRegion) region).buildAccessStrategy(AccessType.TRANSACTIONAL).remove(key);
+   }
+
+   @Override
+   protected Region createRegion(InfinispanRegionFactory regionFactory, String regionName, Properties properties, CacheDataDescription cdd) {
       return regionFactory.buildEntityRegion(regionName, properties, cdd);
    }
 
    @Override
    protected CacheAdapter getInfinispanCache(InfinispanRegionFactory regionFactory) {
-      return CacheAdapterImpl.newInstance(regionFactory.getCacheManager().getCache("entity"));
+      return CacheAdapterImpl.newInstance(regionFactory.getCacheManager().getCache(InfinispanRegionFactory.DEF_ENTITY_RESOURCE));
    }
 
 }

Deleted: core/trunk/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/AbstractFunctionalTestCase.java
===================================================================
--- core/trunk/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/AbstractFunctionalTestCase.java	2009-11-18 16:35:28 UTC (rev 18004)
+++ core/trunk/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/AbstractFunctionalTestCase.java	2009-11-18 16:56:13 UTC (rev 18005)
@@ -1,38 +0,0 @@
-package org.hibernate.test.cache.infinispan.functional;
-
-import java.util.Map;
-
-import org.hibernate.junit.functional.FunctionalTestCase;
-import org.hibernate.stat.SecondLevelCacheStatistics;
-import org.hibernate.stat.Statistics;
-
-/**
- * @author Galder Zamarreño
- * @since 3.5
- */
-public abstract class AbstractFunctionalTestCase extends FunctionalTestCase {
-   private final String cacheConcurrencyStrategy;
-
-   public AbstractFunctionalTestCase(String string, String cacheConcurrencyStrategy) {
-      super(string);
-      this.cacheConcurrencyStrategy = cacheConcurrencyStrategy;
-   }
-
-   public String[] getMappings() {
-      return new String[] { "cache/infinispan/functional/Item.hbm.xml" };
-   }
-
-   @Override
-   public String getCacheConcurrencyStrategy() {
-      return cacheConcurrencyStrategy;
-   }
-
-   public void testEmptySecondLevelCacheEntry() throws Exception {
-      getSessions().getCache().evictEntityRegion(Item.class.getName());
-      Statistics stats = getSessions().getStatistics();
-      stats.clear();
-      SecondLevelCacheStatistics statistics = stats.getSecondLevelCacheStatistics(Item.class.getName() + ".items");
-      Map cacheEntries = statistics.getEntries();
-      assertEquals(0, cacheEntries.size());
-  }
-}
\ No newline at end of file

Modified: core/trunk/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/BasicReadOnlyTestCase.java
===================================================================
--- core/trunk/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/BasicReadOnlyTestCase.java	2009-11-18 16:35:28 UTC (rev 18004)
+++ core/trunk/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/BasicReadOnlyTestCase.java	2009-11-18 16:56:13 UTC (rev 18005)
@@ -4,10 +4,15 @@
  * @author Galder Zamarreño
  * @since 3.5
  */
-public class BasicReadOnlyTestCase extends AbstractFunctionalTestCase {
+public class BasicReadOnlyTestCase extends SingleNodeTestCase {
 
    public BasicReadOnlyTestCase(String string) {
-      super(string, "read-only");
+      super(string);
    }
 
+   @Override
+   public String getCacheConcurrencyStrategy() {
+      return "read-only";
+   }
+
 }
\ No newline at end of file

Modified: core/trunk/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/BasicTransactionalTestCase.java
===================================================================
--- core/trunk/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/BasicTransactionalTestCase.java	2009-11-18 16:35:28 UTC (rev 18004)
+++ core/trunk/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/BasicTransactionalTestCase.java	2009-11-18 16:56:13 UTC (rev 18005)
@@ -6,106 +6,154 @@
 import org.hibernate.Session;
 import org.hibernate.Transaction;
 import org.hibernate.cache.entry.CacheEntry;
+import org.hibernate.cfg.Configuration;
 import org.hibernate.stat.SecondLevelCacheStatistics;
 import org.hibernate.stat.Statistics;
+import org.infinispan.util.logging.Log;
+import org.infinispan.util.logging.LogFactory;
 
 /**
  * @author Galder Zamarreño
  * @since 3.5
  */
-public class BasicTransactionalTestCase extends AbstractFunctionalTestCase {
+public class BasicTransactionalTestCase extends SingleNodeTestCase {
+   private static final Log log = LogFactory.getLog(BasicTransactionalTestCase.class);
 
    public BasicTransactionalTestCase(String string) {
-      super(string, "transactional");
+      super(string);
    }
 
-   public void testEntityCache() {
+   @Override
+   public void configure(Configuration cfg) {
+      super.configure(cfg);
+   }
+
+   public void testEntityCache() throws Exception {
       Item item = new Item("chris", "Chris's Item");
+      beginTx();
+      try {
+         Session s = openSession();
+         s.getTransaction().begin();
+         s.persist(item);
+         s.getTransaction().commit();
+         s.close();
+      } catch (Exception e) {
+         setRollbackOnlyTx(e);
+      } finally {
+         commitOrRollbackTx();
+      }
 
-      Session s = openSession();
-      Statistics stats = s.getSessionFactory().getStatistics();
-      s.getTransaction().begin();
-      s.persist(item);
-      s.getTransaction().commit();
-      s.close();
+      beginTx();
+      try {
+         Session s = openSession();
+         Item found = (Item) s.load(Item.class, item.getId());
+         Statistics stats = s.getSessionFactory().getStatistics();
+         log.info(stats.toString());
+         assertEquals(item.getDescription(), found.getDescription());
+         assertEquals(0, stats.getSecondLevelCacheMissCount());
+         assertEquals(1, stats.getSecondLevelCacheHitCount());
+         s.delete(found);
+         s.close();
+      } catch (Exception e) {
+         setRollbackOnlyTx(e);
+      } finally {
+         commitOrRollbackTx();
+      }
+   }
 
-      s = openSession();
-      Item found = (Item) s.load(Item.class, item.getId());
-      System.out.println(stats);
-      assertEquals(item.getDescription(), found.getDescription());
-      assertEquals(0, stats.getSecondLevelCacheMissCount());
-      assertEquals(1, stats.getSecondLevelCacheHitCount());
-      s.delete(found);
-      s.close();
-   }
-   
-   public void testCollectionCache() {
+   public void testCollectionCache() throws Exception {
       Item item = new Item("chris", "Chris's Item");
       Item another = new Item("another", "Owned Item");
       item.addItem(another);
 
-      Session s = openSession();
-      s.getTransaction().begin();
-      s.persist(item);
-      s.persist(another);
-      s.getTransaction().commit();
-      s.close();
+      beginTx();
+      try {
+         Session s = openSession();
+         s.getTransaction().begin();
+         s.persist(item);
+         s.persist(another);
+         s.getTransaction().commit();
+         s.close();
+      } catch (Exception e) {
+         setRollbackOnlyTx(e);
+      } finally {
+         commitOrRollbackTx();
+      }
 
-      s = openSession();
-      Statistics stats = s.getSessionFactory().getStatistics();
-      Item loaded = (Item) s.load(Item.class, item.getId());
-      assertEquals(1, loaded.getItems().size());
-      s.close();
+      beginTx();
+      try {
+         Session s = openSession();
+         Item loaded = (Item) s.load(Item.class, item.getId());
+         assertEquals(1, loaded.getItems().size());
+         s.close();
+      } catch (Exception e) {
+         setRollbackOnlyTx(e);
+      } finally {
+         commitOrRollbackTx();
+      }
 
-      s = openSession();
-      SecondLevelCacheStatistics cStats = stats.getSecondLevelCacheStatistics(Item.class.getName() + ".items");
-      Item loadedWithCachedCollection = (Item) s.load(Item.class, item.getId());
-      stats.logSummary();
-      assertEquals(item.getName(), loadedWithCachedCollection.getName());
-      assertEquals(item.getItems().size(), loadedWithCachedCollection.getItems().size());
-      assertEquals(1, cStats.getHitCount());
-      Map cacheEntries = cStats.getEntries();
-      assertEquals(1, cacheEntries.size());
-      s.close();
+      beginTx();
+      try {
+         Session s = openSession();
+         Statistics stats = s.getSessionFactory().getStatistics();
+         SecondLevelCacheStatistics cStats = stats.getSecondLevelCacheStatistics(Item.class.getName() + ".items");
+         Item loadedWithCachedCollection = (Item) s.load(Item.class, item.getId());
+         stats.logSummary();
+         assertEquals(item.getName(), loadedWithCachedCollection.getName());
+         assertEquals(item.getItems().size(), loadedWithCachedCollection.getItems().size());
+         assertEquals(1, cStats.getHitCount());
+         Map cacheEntries = cStats.getEntries();
+         assertEquals(1, cacheEntries.size());
+         s.close();
+      } catch (Exception e) {
+         setRollbackOnlyTx(e);
+      } finally {
+         commitOrRollbackTx();
+      }
    }
 
-   public void testStaleWritesLeaveCacheConsistent() {
-      Session s = openSession();
-      Transaction txn = s.beginTransaction();
-      VersionedItem item = new VersionedItem();
-      item.setName("steve");
-      item.setDescription("steve's item");
-      s.save(item);
-      txn.commit();
-      s.close();
+   public void testStaleWritesLeaveCacheConsistent() throws Exception {
+      VersionedItem item = null;
+      Transaction txn = null;
+      Session s = null;
+      beginTx();
+      try {
+         s = openSession();
+         txn = s.beginTransaction();
+         item = new VersionedItem();
+         item.setName("steve");
+         item.setDescription("steve's item");
+         s.save(item);
+         txn.commit();
+         s.close();
+      } catch (Exception e) {
+         setRollbackOnlyTx(e);
+      } finally {
+         commitOrRollbackTx();
+      }
 
       Long initialVersion = item.getVersion();
 
       // manually revert the version property
       item.setVersion(new Long(item.getVersion().longValue() - 1));
 
+      beginTx();
       try {
-          s = openSession();
-          txn = s.beginTransaction();
-          s.update(item);
-          txn.commit();
-          s.close();
-          fail("expected stale write to fail");
-      } catch (Throwable expected) {
-          // expected behavior here
-          if (txn != null) {
-              try {
-                  txn.rollback();
-              } catch (Throwable ignore) {
-              }
-          }
+         s = openSession();
+         txn = s.beginTransaction();
+         s.update(item);
+         txn.commit();
+         fail("expected stale write to fail");
+      } catch (Exception e) {
+         setRollbackOnlyTxExpected(e);
       } finally {
-          if (s != null && s.isOpen()) {
-              try {
-                  s.close();
-              } catch (Throwable ignore) {
-              }
-          }
+         commitOrRollbackTx();
+         if (s != null && s.isOpen()) {
+            try {
+               s.close();
+            } catch (Throwable ignore) {
+            }
+         }
       }
 
       // check the version value in the cache...
@@ -116,24 +164,42 @@
       cachedVersionValue = (Long) ((CacheEntry) entry).getVersion();
       assertEquals(initialVersion.longValue(), cachedVersionValue.longValue());
 
-      // cleanup
-      s = openSession();
-      txn = s.beginTransaction();
-      item = (VersionedItem) s.load(VersionedItem.class, item.getId());
-      s.delete(item);
-      txn.commit();
-      s.close();
+      beginTx();
+      try {
+         // cleanup
+         s = openSession();
+         txn = s.beginTransaction();
+         item = (VersionedItem) s.load(VersionedItem.class, item.getId());
+         s.delete(item);
+         txn.commit();
+         s.close();
+      } catch (Exception e) {
+         setRollbackOnlyTx(e);
+      } finally {
+         commitOrRollbackTx();
+      }
   }
 
-   public void testQueryCacheInvalidation() {
-      Session s = openSession();
-      Transaction t = s.beginTransaction();
-      Item i = new Item();
-      i.setName("widget");
-      i.setDescription("A really top-quality, full-featured widget.");
-      s.persist(i);
-      t.commit();
-      s.close();
+   public void testQueryCacheInvalidation() throws Exception {
+      Session s = null;
+      Transaction t = null;
+      Item i = null;
+      
+      beginTx();
+      try {
+         s = openSession();
+         t = s.beginTransaction();
+         i = new Item();
+         i.setName("widget");
+         i.setDescription("A really top-quality, full-featured widget.");
+         s.persist(i);
+         t.commit();
+         s.close();
+      } catch (Exception e) {
+         setRollbackOnlyTx(e);
+      } finally {
+         commitOrRollbackTx();
+      }
 
       SecondLevelCacheStatistics slcs = s.getSessionFactory().getStatistics().getSecondLevelCacheStatistics(Item.class.getName());
 
@@ -141,18 +207,22 @@
       assertEquals(slcs.getElementCountInMemory(), 1);
       assertEquals(slcs.getEntries().size(), 1);
 
-      s = openSession();
-      t = s.beginTransaction();
-      i = (Item) s.get(Item.class, i.getId());
+      beginTx();
+      try {
+         s = openSession();
+         t = s.beginTransaction();
+         i = (Item) s.get(Item.class, i.getId());
+         assertEquals(slcs.getHitCount(), 1);
+         assertEquals(slcs.getMissCount(), 0);
+         i.setDescription("A bog standard item");
+         t.commit();
+         s.close();
+      } catch (Exception e) {
+         setRollbackOnlyTx(e);
+      } finally {
+         commitOrRollbackTx();
+      }
 
-      assertEquals(slcs.getHitCount(), 1);
-      assertEquals(slcs.getMissCount(), 0);
-
-      i.setDescription("A bog standard item");
-
-      t.commit();
-      s.close();
-
       assertEquals(slcs.getPutCount(), 2);
 
       CacheEntry entry = (CacheEntry) slcs.getEntries().get(i.getId());
@@ -160,32 +230,61 @@
       assertTrue(ser[0].equals("widget"));
       assertTrue(ser[1].equals("A bog standard item"));
       
-      // cleanup
-      s = openSession();
-      t = s.beginTransaction();
-      s.delete(i);
-      t.commit();
-      s.close();
+      beginTx();
+      try {
+         // cleanup
+         s = openSession();
+         t = s.beginTransaction();
+         s.delete(i);
+         t.commit();
+         s.close();
+      } catch (Exception e) {
+         setRollbackOnlyTx(e);
+      } finally {
+         commitOrRollbackTx();
+      }
    }
    
-   public void testQueryCache() {
+   public void testQueryCache() throws Exception {
+      Session s = null;
       Item item = new Item("chris", "Chris's Item");
+      
+      beginTx();
+      try {
+         s = openSession();
+         s.getTransaction().begin();
+         s.persist(item);
+         s.getTransaction().commit();
+         s.close();
+      } catch (Exception e) {
+         setRollbackOnlyTx(e);
+      } finally {
+         commitOrRollbackTx();
+      }
 
-      Session s = openSession();
-      s.getTransaction().begin();
-      s.persist(item);
-      s.getTransaction().commit();
-      s.close();
+      beginTx();
+      try {
+         s = openSession();
+         s.createQuery("from Item").setCacheable(true).list();
+         s.close();
+      } catch (Exception e) {
+         setRollbackOnlyTx(e);
+      } finally {
+         commitOrRollbackTx();
+      }
 
-      s = openSession();
-      s.createQuery("from Item").setCacheable(true).list();
-      s.close();
-
-      s = openSession();
-      Statistics stats = s.getSessionFactory().getStatistics();
-      s.createQuery("from Item").setCacheable(true).list();
-      assertEquals(1, stats.getQueryCacheHitCount());
-      s.createQuery("delete from Item").executeUpdate();
-      s.close();
+      beginTx();
+      try {
+         s = openSession();
+         Statistics stats = s.getSessionFactory().getStatistics();
+         s.createQuery("from Item").setCacheable(true).list();
+         assertEquals(1, stats.getQueryCacheHitCount());
+         s.createQuery("delete from Item").executeUpdate();
+         s.close();
+      } catch (Exception e) {
+         setRollbackOnlyTx(e);
+      } finally {
+         commitOrRollbackTx();
+      }
    }
 }

Added: core/trunk/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/ConcurrentWriteTest.java
===================================================================
--- core/trunk/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/ConcurrentWriteTest.java	                        (rev 0)
+++ core/trunk/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/ConcurrentWriteTest.java	2009-11-18 16:56:13 UTC (rev 18005)
@@ -0,0 +1,513 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2009, Red Hat Middleware LLC or third-party contributors as
+ * indicated by the @author tags or express copyright attribution
+ * statements applied by the authors.  All third-party contributions are
+ * distributed under license by Red Hat Middleware LLC.
+ *
+ * This copyrighted material is made available to anyone wishing to use, modify,
+ * copy, or redistribute it subject to the terms and conditions of the GNU
+ * Lesser General Public License, as published by the Free Software Foundation.
+ *
+ * This program 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 distribution; if not, write to:
+ * Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA  02110-1301  USA
+ */
+package org.hibernate.test.cache.infinispan.functional;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Random;
+import java.util.Set;
+import java.util.concurrent.Callable;
+import java.util.concurrent.CyclicBarrier;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+
+import javax.transaction.TransactionManager;
+
+import org.hibernate.FlushMode;
+import org.hibernate.Session;
+import org.hibernate.cache.RegionFactory;
+import org.hibernate.cache.infinispan.InfinispanRegionFactory;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.connection.ConnectionProvider;
+import org.hibernate.stat.SecondLevelCacheStatistics;
+import org.hibernate.test.cache.infinispan.functional.cluster.DualNodeTestCase;
+import org.hibernate.test.cache.infinispan.functional.cluster.DualNodeConnectionProviderImpl;
+import org.hibernate.test.cache.infinispan.functional.cluster.DualNodeJtaTransactionManagerImpl;
+import org.hibernate.test.cache.infinispan.functional.cluster.DualNodeTransactionManagerLookup;
+import org.hibernate.transaction.TransactionManagerLookup;
+import org.infinispan.util.logging.Log;
+import org.infinispan.util.logging.LogFactory;
+
+/**
+ * 
+ * @author nikita_tovstoles at mba.berkeley.edu
+ * @author Galder Zamarreño
+ */
+public class ConcurrentWriteTest extends SingleNodeTestCase {
+   private static final Log log = LogFactory.getLog(ConcurrentWriteTest.class);
+
+   /**
+    * when USER_COUNT==1, tests pass, when >4 tests fail
+    */
+   private static final int USER_COUNT = 5;
+   private static final int ITERATION_COUNT = 150;
+   private static final int THINK_TIME_MILLIS = 10;
+   private static final long LAUNCH_INTERVAL_MILLIS = 10;
+   private static final Random random = new Random();
+
+   /**
+    * kill switch used to stop all users when one fails
+    */
+   private static volatile boolean TERMINATE_ALL_USERS = false;
+
+   /**
+    * collection of IDs of all customers participating in this test
+    */
+   private Set<Integer> customerIDs = new HashSet<Integer>();
+
+   private TransactionManager tm;
+
+   public ConcurrentWriteTest(String x) {
+      super(x);
+   }
+
+   @Override
+   protected TransactionManager getTransactionManager() {
+      return DualNodeJtaTransactionManagerImpl.getInstance(DualNodeTestCase.LOCAL);
+   }
+
+   @Override
+   protected Class<? extends RegionFactory> getCacheRegionFactory() {
+      return InfinispanRegionFactory.class;
+   }
+
+   @Override
+   protected Class<? extends ConnectionProvider> getConnectionProviderClass() {
+       return DualNodeConnectionProviderImpl.class;
+   }
+
+   @Override
+   protected Class<? extends TransactionManagerLookup> getTransactionManagerLookupClass() {
+       return DualNodeTransactionManagerLookup.class;
+   }
+
+   /**
+    * test that DB can be queried
+    * 
+    * @throws java.lang.Exception
+    */
+   public void testPingDb() throws Exception {
+      try {
+         beginTx();
+         getEnvironment().getSessionFactory().getCurrentSession().createQuery("from " + Customer.class.getName()).list();
+      } catch (Exception e) {
+         setRollbackOnlyTx(e);
+//         setRollbackOnly();
+//         fail("failed to query DB; exception=" + e);
+      } finally {
+         commitOrRollbackTx();
+      }
+   }
+
+   @Override
+   protected void prepareTest() throws Exception {
+      super.prepareTest();
+      TERMINATE_ALL_USERS = false;
+   }
+
+   @Override
+   protected void cleanupTest() throws Exception {
+      try {
+         super.cleanupTest();
+      } finally {
+         cleanup();
+         // DualNodeJtaTransactionManagerImpl.cleanupTransactions();
+         // DualNodeJtaTransactionManagerImpl.cleanupTransactionManagers();
+      }
+   }
+
+   @Override
+   public void configure(Configuration cfg) {
+      super.configure(cfg);
+      cfg.setProperty(DualNodeTestCase.NODE_ID_PROP, DualNodeTestCase.LOCAL);
+   }
+
+   @Override
+   protected boolean getUseQueryCache() {
+      return true;
+   }
+
+   public void testSingleUser() throws Exception {
+      // setup
+      Customer customer = createCustomer(0);
+      final Integer customerId = customer.getId();
+      getCustomerIDs().add(customerId);
+
+      assertNull("contact exists despite not being added", getFirstContact(customerId));
+
+      // check that cache was hit
+      SecondLevelCacheStatistics customerSlcs = getEnvironment().getSessionFactory()
+               .getStatistics().getSecondLevelCacheStatistics(Customer.class.getName());
+      assertEquals(customerSlcs.getPutCount(), 1);
+      assertEquals(customerSlcs.getElementCountInMemory(), 1);
+      assertEquals(customerSlcs.getEntries().size(), 1);
+
+      SecondLevelCacheStatistics contactsCollectionSlcs = getEnvironment().getSessionFactory()
+               .getStatistics().getSecondLevelCacheStatistics(Customer.class.getName() + ".contacts");
+      assertEquals(1, contactsCollectionSlcs.getPutCount());
+      assertEquals(1, contactsCollectionSlcs.getElementCountInMemory());
+      assertEquals(1, contactsCollectionSlcs.getEntries().size());
+
+      final Contact contact = addContact(customerId);
+      assertNotNull("contact returned by addContact is null", contact);
+      assertEquals("Customer.contacts cache was not invalidated after addContact", 0,
+               contactsCollectionSlcs.getElementCountInMemory());
+
+      assertNotNull("Contact missing after successful add call", getFirstContact(customerId));
+
+      // read everyone's contacts
+      readEveryonesFirstContact();
+
+      removeContact(customerId);
+      assertNull("contact still exists after successful remove call", getFirstContact(customerId));
+
+   }
+
+//   /**
+//    * TODO: This will fail until ISPN-??? has been fixed.
+//    * 
+//    * @throws Exception
+//    */
+//   public void testManyUsers() throws Throwable {
+//      try {
+//         // setup - create users
+//         for (int i = 0; i < USER_COUNT; i++) {
+//            Customer customer = createCustomer(0);
+//            getCustomerIDs().add(customer.getId());
+//         }
+//         assertEquals("failed to create enough Customers", USER_COUNT, getCustomerIDs().size());
+//
+//         final ExecutorService executor = Executors.newFixedThreadPool(USER_COUNT);
+//
+//         CyclicBarrier barrier = new CyclicBarrier(USER_COUNT + 1);
+//         List<Future<Void>> futures = new ArrayList<Future<Void>>(USER_COUNT);
+//         for (Integer customerId : getCustomerIDs()) {
+//            Future<Void> future = executor.submit(new UserRunner(customerId, barrier));
+//            futures.add(future);
+//            Thread.sleep(LAUNCH_INTERVAL_MILLIS); // rampup
+//         }
+////         barrier.await(); // wait for all threads to be ready
+//         barrier.await(45, TimeUnit.SECONDS); // wait for all threads to finish
+//         log.info("All threads finished, let's shutdown the executor and check whether any exceptions were reported");
+//         for (Future<Void> future : futures) future.get();
+//         log.info("All future gets checked");
+//      } catch (Throwable t) {
+//         log.error("Error running test", t);
+//         throw t;
+//      }
+//   }
+
+   public void cleanup() throws Exception {
+      getCustomerIDs().clear();
+      String deleteContactHQL = "delete from Contact";
+      String deleteCustomerHQL = "delete from Customer";
+      beginTx();
+      try {
+         Session session = getEnvironment().getSessionFactory().getCurrentSession();
+         session.createQuery(deleteContactHQL).setFlushMode(FlushMode.AUTO).executeUpdate();
+         session.createQuery(deleteCustomerHQL).setFlushMode(FlushMode.AUTO).executeUpdate();
+      } catch (Exception e) {
+         setRollbackOnlyTx(e);
+      } finally {
+         commitOrRollbackTx();
+      }
+   }
+
+   private Customer createCustomer(int nameSuffix) throws Exception {
+      Customer customer = null;
+      beginTx();
+      try {
+         customer = new Customer();
+         customer.setName("customer_" + nameSuffix);
+         customer.setContacts(new HashSet<Contact>());
+         getEnvironment().getSessionFactory().getCurrentSession().persist(customer);
+      } catch (Exception e) {
+         setRollbackOnlyTx(e);
+      } finally {
+         commitOrRollbackTx();
+      }
+      return customer;
+   }
+
+   /**
+    * read first contact of every Customer participating in this test. this forces concurrent cache
+    * writes of Customer.contacts Collection cache node
+    * 
+    * @return who cares
+    * @throws java.lang.Exception
+    */
+   private void readEveryonesFirstContact() throws Exception {
+      beginTx();
+      try {
+         for (Integer customerId : getCustomerIDs()) {
+            if (TERMINATE_ALL_USERS) {
+               setRollbackOnlyTx();
+               return;
+            }
+            Customer customer = (Customer) getEnvironment().getSessionFactory().getCurrentSession().load(Customer.class, customerId);
+            Set<Contact> contacts = customer.getContacts();
+            if (!contacts.isEmpty()) {
+               contacts.iterator().next();
+            }
+         }
+      } catch (Exception e) {
+         setRollbackOnlyTx(e);
+      } finally {
+         commitOrRollbackTx();
+      }
+   }
+
+   /**
+    * -load existing Customer -get customer's contacts; return 1st one
+    * 
+    * @param customerId
+    * @return first Contact or null if customer has none
+    */
+   private Contact getFirstContact(Integer customerId) throws Exception {
+      assert customerId != null;
+      Contact firstContact = null;
+      beginTx();
+      try {
+         final Customer customer = (Customer) getEnvironment().getSessionFactory()
+                  .getCurrentSession().load(Customer.class, customerId);
+         Set<Contact> contacts = customer.getContacts();
+         firstContact = contacts.isEmpty() ? null : contacts.iterator().next();
+         if (TERMINATE_ALL_USERS)
+            setRollbackOnlyTx();
+      } catch (Exception e) {
+         setRollbackOnlyTx(e);
+      } finally {
+         commitOrRollbackTx();
+      }
+      return firstContact;
+   }
+
+   /**
+    * -load existing Customer -create a new Contact and add to customer's contacts
+    * 
+    * @param customerId
+    * @return added Contact
+    */
+   private Contact addContact(Integer customerId) throws Exception {
+      assert customerId != null;
+      Contact contact = null;
+      beginTx();
+      try {
+         final Customer customer = (Customer) getEnvironment().getSessionFactory()
+                  .getCurrentSession().load(Customer.class, customerId);
+         contact = new Contact();
+         contact.setName("contact name");
+         contact.setTlf("wtf is tlf?");
+         contact.setCustomer(customer);
+         customer.getContacts().add(contact);
+         // assuming contact is persisted via cascade from customer
+         if (TERMINATE_ALL_USERS)
+            setRollbackOnlyTx();
+      } catch (Exception e) {
+         setRollbackOnlyTx(e);
+      } finally {
+         commitOrRollbackTx();
+      }
+      return contact;
+   }
+
+   /**
+    * remove existing 'contact' from customer's list of contacts
+    * 
+    * @param contact
+    *           contact to remove from customer's contacts
+    * @param customerId
+    * @throws IllegalStateException
+    *            if customer does not own a contact
+    */
+   private void removeContact(Integer customerId) throws Exception {
+      assert customerId != null;
+
+      beginTx();
+      try {
+         Customer customer = (Customer) getEnvironment().getSessionFactory().getCurrentSession()
+                  .load(Customer.class, customerId);
+         Set<Contact> contacts = customer.getContacts();
+         if (contacts.size() != 1) {
+            throw new IllegalStateException("can't remove contact: customer id=" + customerId
+                     + " expected exactly 1 contact, " + "actual count=" + contacts.size());
+         }
+
+         Contact contact = contacts.iterator().next();
+         contacts.remove(contact);
+         contact.setCustomer(null);
+
+         // explicitly delete Contact because hbm has no 'DELETE_ORPHAN' cascade?
+         // getEnvironment().getSessionFactory().getCurrentSession().delete(contact); //appears to
+         // not be needed
+
+         // assuming contact is persisted via cascade from customer
+
+         if (TERMINATE_ALL_USERS)
+            setRollbackOnlyTx();
+      } catch (Exception e) {
+         setRollbackOnlyTx(e);
+      } finally {
+         commitOrRollbackTx();
+      }
+   }
+
+   /**
+    * @return the customerIDs
+    */
+   public Set<Integer> getCustomerIDs() {
+      return customerIDs;
+   }
+
+   private String statusOfRunnersToString(Set<UserRunner> runners) {
+      assert runners != null;
+
+      StringBuilder sb = new StringBuilder("TEST CONFIG [userCount=" + USER_COUNT
+               + ", iterationsPerUser=" + ITERATION_COUNT + ", thinkTimeMillis="
+               + THINK_TIME_MILLIS + "] " + " STATE of UserRunners: ");
+
+      for (UserRunner r : runners) {
+         sb.append(r.toString() + System.getProperty("line.separator"));
+      }
+      return sb.toString();
+   }
+
+   class UserRunner implements Callable<Void> {
+      private final CyclicBarrier barrier;
+      final private Integer customerId;
+      private int completedIterations = 0;
+      private Throwable causeOfFailure;
+
+      public UserRunner(Integer cId, CyclicBarrier barrier) {
+         assert cId != null;
+         this.customerId = cId;
+         this.barrier = barrier;
+      }
+
+      private boolean contactExists() throws Exception {
+         return getFirstContact(customerId) != null;
+      }
+
+      public Void call() throws Exception {
+         // name this thread for easier log tracing
+         Thread.currentThread().setName("UserRunnerThread-" + getCustomerId());
+         log.info("Wait for all executions paths to be ready to perform calls");
+         try {
+//            barrier.await();
+            for (int i = 0; i < ITERATION_COUNT && !TERMINATE_ALL_USERS; i++) {
+               if (contactExists())
+                  throw new IllegalStateException("contact already exists before add, customerId=" + customerId);
+               addContact(customerId);
+               thinkRandomTime();
+               if (!contactExists())
+                  throw new IllegalStateException("contact missing after successful add, customerId=" + customerId);
+               thinkRandomTime();
+               // read everyone's contacts
+               readEveryonesFirstContact();
+               thinkRandomTime();
+               removeContact(customerId);
+               if (contactExists())
+                  throw new IllegalStateException("contact still exists after successful remove call, customerId=" + customerId);
+               thinkRandomTime();
+               ++completedIterations;
+               if (log.isTraceEnabled()) log.trace("Iteration completed {0}", completedIterations);
+            }
+         } catch (Throwable t) {
+            TERMINATE_ALL_USERS = true;
+            log.error("Error", t);
+            throw new Exception(t);
+            // rollback current transaction if any
+            // really should not happen since above methods all follow begin-commit-rollback pattern
+            // try {
+            // if
+            // (DualNodeJtaTransactionManagerImpl.getInstance(DualNodeTestUtil.LOCAL).getTransaction()
+            // != null) {
+            // DualNodeJtaTransactionManagerImpl.getInstance(DualNodeTestUtil.LOCAL).rollback();
+            // }
+            // } catch (SystemException ex) {
+            // throw new RuntimeException("failed to rollback tx", ex);
+            // }
+         } finally {
+            log.info("Wait for all execution paths to finish");
+            barrier.await();
+         }
+         return null;
+      }
+
+      public boolean isSuccess() {
+         return ITERATION_COUNT == getCompletedIterations();
+      }
+
+      public int getCompletedIterations() {
+         return completedIterations;
+      }
+
+      public Throwable getCauseOfFailure() {
+         return causeOfFailure;
+      }
+
+      public Integer getCustomerId() {
+         return customerId;
+      }
+
+      @Override
+      public String toString() {
+         return super.toString() + "[customerId=" + getCustomerId() + " iterationsCompleted="
+                  + getCompletedIterations() + " completedAll=" + isSuccess() + " causeOfFailure="
+                  + (this.causeOfFailure != null ? getStackTrace(causeOfFailure) : "") + "] ";
+      }
+   }
+
+   public static String getStackTrace(Throwable throwable) {
+      StringWriter sw = new StringWriter();
+      PrintWriter pw = new PrintWriter(sw, true);
+      throwable.printStackTrace(pw);
+      return sw.getBuffer().toString();
+   }
+
+   /**
+    * sleep between 0 and THINK_TIME_MILLIS.
+    * 
+    * @throws RuntimeException
+    *            if sleep is interrupted or TERMINATE_ALL_USERS flag was set to true i n the
+    *            meantime
+    */
+   private void thinkRandomTime() {
+      try {
+         Thread.sleep(random.nextInt(THINK_TIME_MILLIS));
+      } catch (InterruptedException ex) {
+         throw new RuntimeException("sleep interrupted", ex);
+      }
+
+      if (TERMINATE_ALL_USERS) {
+         throw new RuntimeException("told to terminate (because a UserRunner had failed)");
+      }
+   }
+
+}

Copied: core/trunk/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/SingleNodeTestCase.java (from rev 17976, core/trunk/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/AbstractFunctionalTestCase.java)
===================================================================
--- core/trunk/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/SingleNodeTestCase.java	                        (rev 0)
+++ core/trunk/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/SingleNodeTestCase.java	2009-11-18 16:56:13 UTC (rev 18005)
@@ -0,0 +1,121 @@
+package org.hibernate.test.cache.infinispan.functional;
+
+import java.util.Map;
+
+import javax.transaction.Status;
+import javax.transaction.TransactionManager;
+
+import org.hibernate.cache.RegionFactory;
+import org.hibernate.cache.infinispan.InfinispanRegionFactory;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.cfg.Environment;
+import org.hibernate.connection.ConnectionProvider;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.stat.SecondLevelCacheStatistics;
+import org.hibernate.stat.Statistics;
+import org.hibernate.transaction.CMTTransactionFactory;
+import org.hibernate.transaction.TransactionFactory;
+import org.hibernate.transaction.TransactionManagerLookup;
+import org.infinispan.util.logging.Log;
+import org.infinispan.util.logging.LogFactory;
+
+/**
+ * @author Galder Zamarreño
+ * @since 3.5
+ */
+public abstract class SingleNodeTestCase extends FunctionalTestCase {
+   private static final Log log = LogFactory.getLog(SingleNodeTestCase.class);
+   private final TransactionManager tm;
+
+   public SingleNodeTestCase(String string) {
+      super(string);
+      tm = getTransactionManager();
+   }
+
+   protected TransactionManager getTransactionManager() {
+      try {
+         return getTransactionManagerLookupClass().newInstance().getTransactionManager(null);
+      } catch (Exception e) {
+         log.error("Error", e);
+         throw new RuntimeException(e);
+      }
+   }
+
+   
+   public String[] getMappings() {
+      return new String[] { 
+               "cache/infinispan/functional/Item.hbm.xml", 
+               "cache/infinispan/functional/Customer.hbm.xml", 
+               "cache/infinispan/functional/Contact.hbm.xml"};
+   }
+
+   @Override
+   public String getCacheConcurrencyStrategy() {
+      return "transactional";
+   }
+
+   protected Class<? extends RegionFactory> getCacheRegionFactory() {
+      return InfinispanRegionFactory.class;
+   }
+
+   protected Class<? extends TransactionFactory> getTransactionFactoryClass() {
+      return CMTTransactionFactory.class;
+   }
+
+   protected Class<? extends ConnectionProvider> getConnectionProviderClass() {
+      return org.hibernate.test.cache.infinispan.tm.XaConnectionProvider.class;
+   }
+
+   protected Class<? extends TransactionManagerLookup> getTransactionManagerLookupClass() {
+      return org.hibernate.test.cache.infinispan.tm.XaTransactionManagerLookup.class;
+   }
+
+   protected boolean getUseQueryCache() {
+      return true;
+   }
+
+   public void configure(Configuration cfg) {
+      super.configure(cfg);
+      cfg.setProperty(Environment.USE_SECOND_LEVEL_CACHE, "true");
+      cfg.setProperty(Environment.GENERATE_STATISTICS, "true");
+      cfg.setProperty(Environment.USE_QUERY_CACHE, String.valueOf(getUseQueryCache()));
+      cfg.setProperty(Environment.CACHE_REGION_FACTORY, getCacheRegionFactory().getName());
+      cfg.setProperty(Environment.CONNECTION_PROVIDER, getConnectionProviderClass().getName());
+      cfg.setProperty(Environment.TRANSACTION_MANAGER_STRATEGY, getTransactionManagerLookupClass().getName());
+      cfg.setProperty(Environment.TRANSACTION_STRATEGY, getTransactionFactoryClass().getName());
+   }
+
+   public void testEmptySecondLevelCacheEntry() throws Exception {
+      getSessions().getCache().evictEntityRegion(Item.class.getName());
+      Statistics stats = getSessions().getStatistics();
+      stats.clear();
+      SecondLevelCacheStatistics statistics = stats.getSecondLevelCacheStatistics(Item.class.getName() + ".items");
+      Map cacheEntries = statistics.getEntries();
+      assertEquals(0, cacheEntries.size());
+   }
+
+   protected void beginTx() throws Exception {
+      tm.begin();
+   }
+
+   protected void setRollbackOnlyTx() throws Exception {
+      tm.setRollbackOnly();
+   }
+
+   protected void setRollbackOnlyTx(Exception e) throws Exception {
+      log.error("Error", e);
+      tm.setRollbackOnly();
+      throw e;
+   }
+
+   protected void setRollbackOnlyTxExpected(Exception e) throws Exception {
+      log.debug("Expected behaivour", e);
+      tm.setRollbackOnly();
+   }
+
+   protected void commitOrRollbackTx() throws Exception {
+      if (tm.getStatus() == Status.STATUS_ACTIVE) tm.commit();
+      else tm.rollback();
+   }
+   
+}
\ No newline at end of file

Modified: core/trunk/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/bulk/BulkOperationsTestCase.java
===================================================================
--- core/trunk/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/bulk/BulkOperationsTestCase.java	2009-11-18 16:35:28 UTC (rev 18004)
+++ core/trunk/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/bulk/BulkOperationsTestCase.java	2009-11-18 16:56:13 UTC (rev 18005)
@@ -25,20 +25,25 @@
 import java.util.List;
 import java.util.Set;
 
+import javax.transaction.Status;
 import javax.transaction.TransactionManager;
 
 import org.hibernate.FlushMode;
+import org.hibernate.cache.RegionFactory;
+import org.hibernate.cache.infinispan.InfinispanRegionFactory;
 import org.hibernate.cfg.Configuration;
 import org.hibernate.cfg.Environment;
 import org.hibernate.classic.Session;
+import org.hibernate.connection.ConnectionProvider;
 import org.hibernate.junit.functional.FunctionalTestCase;
 import org.hibernate.stat.SecondLevelCacheStatistics;
 import org.hibernate.test.cache.infinispan.functional.Contact;
 import org.hibernate.test.cache.infinispan.functional.Customer;
 import org.hibernate.transaction.CMTTransactionFactory;
+import org.hibernate.transaction.TransactionFactory;
 import org.hibernate.transaction.TransactionManagerLookup;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import org.infinispan.util.logging.Log;
+import org.infinispan.util.logging.LogFactory;
 
 /**
  * BulkOperationsTestCase.
@@ -47,9 +52,8 @@
  * @since 3.5
  */
 public class BulkOperationsTestCase extends FunctionalTestCase {
+   private static final Log log = LogFactory.getLog(BulkOperationsTestCase.class);
 
-   private static final Logger log = LoggerFactory.getLogger(BulkOperationsTestCase.class);
-
    private TransactionManager tm;
 
    public BulkOperationsTestCase(String string) {
@@ -66,11 +70,15 @@
       return "transactional";
    }
 
-   protected Class getTransactionFactoryClass() {
+   protected Class<? extends RegionFactory> getCacheRegionFactory() {
+      return InfinispanRegionFactory.class;
+   }
+
+   protected Class<? extends TransactionFactory> getTransactionFactoryClass() {
       return CMTTransactionFactory.class;
    }
 
-   protected Class getConnectionProviderClass() {
+   protected Class<? extends ConnectionProvider> getConnectionProviderClass() {
       return org.hibernate.test.cache.infinispan.tm.XaConnectionProvider.class;
    }
 
@@ -80,20 +88,17 @@
 
    public void configure(Configuration cfg) {
       super.configure(cfg);
-
       cfg.setProperty(Environment.USE_SECOND_LEVEL_CACHE, "true");
       cfg.setProperty(Environment.GENERATE_STATISTICS, "true");
       cfg.setProperty(Environment.USE_QUERY_CACHE, "false");
+      cfg.setProperty(Environment.CACHE_REGION_FACTORY, getCacheRegionFactory().getName());
       cfg.setProperty(Environment.CONNECTION_PROVIDER, getConnectionProviderClass().getName());
-      cfg.setProperty(Environment.TRANSACTION_MANAGER_STRATEGY, getTransactionManagerLookupClass()
-               .getName());
-
-      Class transactionFactory = getTransactionFactoryClass();
-      cfg.setProperty(Environment.TRANSACTION_STRATEGY, transactionFactory.getName());
+      cfg.setProperty(Environment.TRANSACTION_MANAGER_STRATEGY, getTransactionManagerLookupClass().getName());
+      cfg.setProperty(Environment.TRANSACTION_STRATEGY, getTransactionFactoryClass().getName());
    }
 
    public void testBulkOperations() throws Throwable {
-      System.out.println("*** testBulkOperations()");
+      log.info("*** testBulkOperations()");
       boolean cleanedUp = false;
       try {
          tm = getTransactionManagerLookupClass().newInstance().getTransactionManager(null);
@@ -166,13 +171,14 @@
       log.debug("Create 10 contacts");
       tm.begin();
       try {
-         for (int i = 0; i < 10; i++)
-            createCustomer(i);
-         tm.commit();
+         for (int i = 0; i < 10; i++) createCustomer(i);
       } catch (Exception e) {
          log.error("Unable to create customer", e);
-         tm.rollback();
+         tm.setRollbackOnly();
          throw e;
+      } finally {
+         if (tm.getStatus() == Status.STATUS_ACTIVE) tm.commit();
+         else tm.rollback();
       }
    }
 
@@ -183,19 +189,25 @@
 
       tm.begin();
       try {
-
          Session session = getSessions().getCurrentSession();
          int rowsAffected = session.createQuery(deleteHQL).setFlushMode(FlushMode.AUTO)
                   .setParameter("cName", "Red Hat").executeUpdate();
          tm.commit();
          return rowsAffected;
       } catch (Exception e) {
-         try {
-            tm.rollback();
-         } catch (Exception ee) {
-            // ignored
+         log.error("Unable to delete contac", e);
+         tm.setRollbackOnly();
+         throw e;
+      } finally {
+         if (tm.getStatus() == Status.STATUS_ACTIVE) {
+            tm.commit();
+         } else {
+            try {
+               tm.rollback();
+            } catch (Exception ee) {
+               // ignored
+            }
          }
-         throw e;
       }
    }
 
@@ -210,11 +222,14 @@
          Session session = getSessions().getCurrentSession();
          List results = session.createQuery(selectHQL).setFlushMode(FlushMode.AUTO).setParameter(
                   "cName", customerName).list();
-         tm.commit();
          return results;
       } catch (Exception e) {
-         tm.rollback();
+         log.error("Unable to get contacts by customer", e);
+         tm.setRollbackOnly();
          throw e;
+      } finally {
+         if (tm.getStatus() == Status.STATUS_ACTIVE) tm.commit();
+         else tm.rollback();
       }
    }
 
@@ -224,15 +239,17 @@
 
       tm.begin();
       try {
-
          Session session = getSessions().getCurrentSession();
          List results = session.createQuery(selectHQL).setFlushMode(FlushMode.AUTO).setParameter(
                   "cTLF", tlf).list();
-         tm.commit();
          return results;
       } catch (Exception e) {
-         tm.rollback();
+         log.error("Unable to get contacts", e);
+         tm.setRollbackOnly();
          throw e;
+      } finally {
+         if (tm.getStatus() == Status.STATUS_ACTIVE) tm.commit();
+         else tm.rollback();
       }
    }
 
@@ -243,11 +260,14 @@
          Session session = getSessions().getCurrentSession();
          int rowsAffected = session.createQuery(updateHQL).setFlushMode(FlushMode.AUTO)
                   .setParameter("cNewTLF", newTLF).setParameter("cName", name).executeUpdate();
-         tm.commit();
          return rowsAffected;
       } catch (Exception e) {
-         tm.rollback();
+         log.error("Unable to update contacts", e);
+         tm.setRollbackOnly();
          throw e;
+      } finally {
+         if (tm.getStatus() == Status.STATUS_ACTIVE) tm.commit();
+         else tm.rollback();
       }
    }
 
@@ -262,25 +282,30 @@
          list.get(0).setTlf(newTLF);
          int rowsAffected = session.createQuery(updateHQL).setFlushMode(FlushMode.AUTO)
                   .setParameter("cNewTLF", newTLF).setParameter("cName", name).executeUpdate();
-         tm.commit();
          return rowsAffected;
       } catch (Exception e) {
-         tm.rollback();
+         log.error("Unable to update contacts with one manual", e);
+         tm.setRollbackOnly();
          throw e;
+      } finally {
+         if (tm.getStatus() == Status.STATUS_ACTIVE) tm.commit();
+         else tm.rollback();
       }
    }
 
    public Contact getContact(Integer id) throws Exception {
       tm.begin();
       try {
-
          Session session = getSessions().getCurrentSession();
          Contact contact = (Contact) session.get(Contact.class, id);
-         tm.commit();
          return contact;
       } catch (Exception e) {
-         tm.rollback();
+         log.error("Unable to get contact", e);
+         tm.setRollbackOnly();
          throw e;
+      } finally {
+         if (tm.getStatus() == Status.STATUS_ACTIVE) tm.commit();
+         else tm.rollback();
       }
    }
 
@@ -292,15 +317,21 @@
          Session session = getSessions().getCurrentSession();
          session.createQuery(deleteContactHQL).setFlushMode(FlushMode.AUTO).executeUpdate();
          session.createQuery(deleteCustomerHQL).setFlushMode(FlushMode.AUTO).executeUpdate();
-         tm.commit();
       } catch (Exception e) {
-         if (!ignore) {
-            try {
-               tm.rollback();
-            } catch (Exception ee) {
-               // ignored
+         log.error("Unable to get contact", e);
+         tm.setRollbackOnly();
+         throw e;
+      } finally {
+         if (tm.getStatus() == Status.STATUS_ACTIVE) {
+            tm.commit();
+         } else {
+            if (!ignore) {
+               try {
+                  tm.rollback();
+               } catch (Exception ee) {
+                  // ignored
+               }
             }
-            throw e;
          }
       }
    }

Modified: core/trunk/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/classloader/ClassLoaderTestDAO.java
===================================================================
--- core/trunk/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/classloader/ClassLoaderTestDAO.java	2009-11-18 16:35:28 UTC (rev 18004)
+++ core/trunk/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/classloader/ClassLoaderTestDAO.java	2009-11-18 16:56:13 UTC (rev 18005)
@@ -30,8 +30,8 @@
 import org.hibernate.Query;
 import org.hibernate.Session;
 import org.hibernate.SessionFactory;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import org.infinispan.util.logging.Log;
+import org.infinispan.util.logging.LogFactory;
 
 /**
  * Comment
@@ -39,7 +39,7 @@
  * @author Brian Stansberry
  */
 public class ClassLoaderTestDAO {
-   private static final Logger log = LoggerFactory.getLogger(ClassLoaderTestDAO.class);
+   private static final Log log = LogFactory.getLog(ClassLoaderTestDAO.class);
 
    private SessionFactory sessionFactory;
    private TransactionManager tm;

Modified: core/trunk/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/classloader/IsolatedClassLoaderTest.java
===================================================================
--- core/trunk/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/classloader/IsolatedClassLoaderTest.java	2009-11-18 16:35:28 UTC (rev 18004)
+++ core/trunk/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/classloader/IsolatedClassLoaderTest.java	2009-11-18 16:56:13 UTC (rev 18005)
@@ -30,7 +30,7 @@
 import org.hibernate.cache.StandardQueryCache;
 import org.hibernate.cache.infinispan.InfinispanRegionFactory;
 import org.hibernate.cfg.Configuration;
-import org.hibernate.test.cache.infinispan.functional.cluster.AbstractDualNodeTestCase;
+import org.hibernate.test.cache.infinispan.functional.cluster.DualNodeTestCase;
 import org.hibernate.test.cache.infinispan.functional.cluster.ClusterAwareRegionFactory;
 import org.hibernate.test.cache.infinispan.functional.cluster.DualNodeJtaTransactionManagerImpl;
 import org.infinispan.Cache;
@@ -51,7 +51,7 @@
  * @author Galder Zamarreño
  * @since 3.5
  */
-public class IsolatedClassLoaderTest extends AbstractDualNodeTestCase {
+public class IsolatedClassLoaderTest extends DualNodeTestCase {
 
    public static final String OUR_PACKAGE = IsolatedClassLoaderTest.class.getPackage().getName();
 
@@ -119,11 +119,11 @@
    public void testIsolatedSetup() throws Exception {
       // Bind a listener to the "local" cache
       // Our region factory makes its CacheManager available to us
-      CacheManager localManager = ClusterAwareRegionFactory.getCacheManager(AbstractDualNodeTestCase.LOCAL);
+      CacheManager localManager = ClusterAwareRegionFactory.getCacheManager(DualNodeTestCase.LOCAL);
       Cache localReplicatedCache = localManager.getCache("replicated-entity");
 
       // Bind a listener to the "remote" cache
-      CacheManager remoteManager = ClusterAwareRegionFactory.getCacheManager(AbstractDualNodeTestCase.REMOTE);
+      CacheManager remoteManager = ClusterAwareRegionFactory.getCacheManager(DualNodeTestCase.REMOTE);
       Cache remoteReplicatedCache = remoteManager.getCache("replicated-entity");
 
       ClassLoader cl = Thread.currentThread().getContextClassLoader();
@@ -163,20 +163,20 @@
    protected void queryTest(boolean useNamedRegion) throws Exception {
       // Bind a listener to the "local" cache
       // Our region factory makes its CacheManager available to us
-      CacheManager localManager = ClusterAwareRegionFactory.getCacheManager(AbstractDualNodeTestCase.LOCAL);
+      CacheManager localManager = ClusterAwareRegionFactory.getCacheManager(DualNodeTestCase.LOCAL);
       localQueryCache = localManager.getCache("replicated-query");
       localQueryListener = new CacheAccessListener();
       localQueryCache.addListener(localQueryListener);
 
-      TransactionManager localTM = DualNodeJtaTransactionManagerImpl.getInstance(AbstractDualNodeTestCase.LOCAL);
+      TransactionManager localTM = DualNodeJtaTransactionManagerImpl.getInstance(DualNodeTestCase.LOCAL);
 
       // Bind a listener to the "remote" cache
-      CacheManager remoteManager = ClusterAwareRegionFactory.getCacheManager(AbstractDualNodeTestCase.REMOTE);
+      CacheManager remoteManager = ClusterAwareRegionFactory.getCacheManager(DualNodeTestCase.REMOTE);
       remoteQueryCache = remoteManager.getCache("replicated-query");
       remoteQueryListener = new CacheAccessListener();
       remoteQueryCache.addListener(remoteQueryListener);
 
-      TransactionManager remoteTM = DualNodeJtaTransactionManagerImpl.getInstance(AbstractDualNodeTestCase.REMOTE);
+      TransactionManager remoteTM = DualNodeJtaTransactionManagerImpl.getInstance(DualNodeTestCase.REMOTE);
 
       SessionFactory localFactory = getEnvironment().getSessionFactory();
       SessionFactory remoteFactory = getSecondNodeEnvironment().getSessionFactory();

Deleted: core/trunk/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/cluster/AbstractDualNodeTestCase.java
===================================================================
--- core/trunk/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/cluster/AbstractDualNodeTestCase.java	2009-11-18 16:35:28 UTC (rev 18004)
+++ core/trunk/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/cluster/AbstractDualNodeTestCase.java	2009-11-18 16:56:13 UTC (rev 18005)
@@ -1,241 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source.
- * Copyright 2009, Red Hat, Inc. and/or it's affiliates, 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.hibernate.test.cache.infinispan.functional.cluster;
-
-import java.util.Set;
-
-import org.hibernate.Session;
-import org.hibernate.cache.infinispan.util.CacheHelper;
-import org.hibernate.cfg.Configuration;
-import org.hibernate.cfg.Environment;
-import org.hibernate.cfg.Mappings;
-import org.hibernate.dialect.Dialect;
-import org.hibernate.engine.SessionFactoryImplementor;
-import org.hibernate.junit.functional.ExecutionEnvironment;
-import org.hibernate.junit.functional.FunctionalTestCase;
-import org.hibernate.transaction.CMTTransactionFactory;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * AbstractDualNodeTestCase.
- * 
- * @author Galder Zamarreño
- * @since 3.5
- */
-public abstract class AbstractDualNodeTestCase extends FunctionalTestCase {
-   
-   private static final Logger log = LoggerFactory.getLogger(AbstractDualNodeTestCase.class);
-   public static final String NODE_ID_PROP = "hibernate.test.cluster.node.id";
-   public static final String LOCAL = "local";
-   public static final String REMOTE = "remote";
-   private ExecutionEnvironment secondNodeEnvironment;
-   private Session secondNodeSession;
-
-   public AbstractDualNodeTestCase(String string) {
-      super(string);
-   }
-   
-   public String[] getMappings() {
-      return new String[] { "cache/infinispan/functional/Contact.hbm.xml", "cache/infinispan/functional/Customer.hbm.xml" };
-   }
-   
-   @Override
-   public String getCacheConcurrencyStrategy() {
-      return "transactional";
-   }
-   
-   protected Class getCacheRegionFactory() {
-      return ClusterAwareRegionFactory.class;
-   }
-
-   @Override
-   public void configure(Configuration cfg) {
-      standardConfigure(cfg);
-      configureFirstNode(cfg);
-   }
-
-   @Override
-   protected void prepareTest() throws Exception {
-      log.info("Building second node locally managed execution env");
-      secondNodeEnvironment = new ExecutionEnvironment(new SecondNodeSettings());
-      secondNodeEnvironment.initialize();
-      super.prepareTest();
-   }
-   
-   @Override
-   protected void runTest() throws Throwable {
-      try {
-          super.runTest();
-      } finally {
-         if ( secondNodeSession != null && secondNodeSession.isOpen() ) {
-             if ( secondNodeSession.isConnected() ) {
-                secondNodeSession.connection().rollback();
-             }
-             secondNodeSession.close();
-             secondNodeSession = null;
-             fail( "unclosed session" );
-         } else {
-            secondNodeSession = null;
-         }
-         
-      }
-   }
-
-   @Override
-   protected void cleanupTest() throws Exception {
-      try {
-          super.cleanupTest();
-      
-          log.info( "Destroying second node locally managed execution env" );
-          secondNodeEnvironment.complete();
-          secondNodeEnvironment = null;
-      } finally {
-         cleanupTransactionManagement();
-      }
-   }
-   
-   protected void cleanupTransactionManagement() {
-      DualNodeJtaTransactionManagerImpl.cleanupTransactions();
-      DualNodeJtaTransactionManagerImpl.cleanupTransactionManagers();
-   }
-
-   public ExecutionEnvironment getSecondNodeEnvironment() {
-      return secondNodeEnvironment;
-   }
-
-   protected Class getConnectionProviderClass() {
-      return DualNodeConnectionProviderImpl.class;
-   }
-
-   protected Class getTransactionManagerLookupClass() {
-      return DualNodeTransactionManagerLookup.class;
-   }
-
-   protected Class getTransactionFactoryClass() {
-      return CMTTransactionFactory.class;
-   }
-
-   /**
-    * Apply any node-specific configurations to our first node.
-    * 
-    * @param the
-    *           Configuration to update.
-    */
-   protected void configureFirstNode(Configuration cfg) {
-      cfg.setProperty(NODE_ID_PROP, LOCAL);
-   }
-
-   /**
-    * Apply any node-specific configurations to our second node.
-    * 
-    * @param the
-    *           Configuration to update.
-    */
-   protected void configureSecondNode(Configuration cfg) {
-      cfg.setProperty(NODE_ID_PROP, REMOTE);
-   }
-   
-   protected void sleep(long ms) {
-      try {
-          Thread.sleep(ms);
-      }
-      catch (InterruptedException e) {
-          log.warn("Interrupted during sleep", e);
-      }
-  }
-
-   protected void standardConfigure(Configuration cfg) {
-      super.configure(cfg);
-
-      cfg.setProperty(Environment.CONNECTION_PROVIDER, getConnectionProviderClass().getName());
-      cfg.setProperty(Environment.TRANSACTION_MANAGER_STRATEGY, getTransactionManagerLookupClass().getName());
-      cfg.setProperty(Environment.TRANSACTION_STRATEGY, getTransactionFactoryClass().getName());
-      cfg.setProperty(Environment.CACHE_REGION_FACTORY, getCacheRegionFactory().getName());
-   }
-
-   /**
-    * Settings impl that delegates most calls to the DualNodeTestCase itself, but overrides the
-    * configure method to allow separate cache settings for the second node.
-    */
-   public class SecondNodeSettings implements ExecutionEnvironment.Settings {
-      private final AbstractDualNodeTestCase delegate;
-
-      public SecondNodeSettings() {
-         this.delegate = AbstractDualNodeTestCase.this;
-      }
-
-      /**
-       * This is the important one -- we extend the delegate's work by adding second-node specific
-       * settings
-       */
-      public void configure(Configuration arg0) {
-         delegate.standardConfigure(arg0);
-         configureSecondNode(arg0);
-      }
-
-      /**
-       * Disable creating of schemas; we let the primary session factory do that to our shared
-       * database.
-       */
-      public boolean createSchema() {
-         return false;
-      }
-
-      /**
-       * Disable creating of schemas; we let the primary session factory do that to our shared
-       * database.
-       */
-      public boolean recreateSchemaAfterFailure() {
-         return false;
-      }
-
-      public void afterConfigurationBuilt(Mappings arg0, Dialect arg1) {
-         delegate.afterConfigurationBuilt(arg0, arg1);
-      }
-
-      public void afterSessionFactoryBuilt(SessionFactoryImplementor arg0) {
-         delegate.afterSessionFactoryBuilt(arg0);
-      }
-
-      public boolean appliesTo(Dialect arg0) {
-         return delegate.appliesTo(arg0);
-      }
-
-      public String getBaseForMappings() {
-         return delegate.getBaseForMappings();
-      }
-
-      public String getCacheConcurrencyStrategy() {
-         return delegate.getCacheConcurrencyStrategy();
-      }
-
-      public String[] getMappings() {
-         return delegate.getMappings();
-      }
-
-      public boolean overrideCacheStrategy() {
-         return delegate.overrideCacheStrategy();
-      }
-   }
-
-}

Modified: core/trunk/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/cluster/ClusterAwareRegionFactory.java
===================================================================
--- core/trunk/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/cluster/ClusterAwareRegionFactory.java	2009-11-18 16:35:28 UTC (rev 18004)
+++ core/trunk/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/cluster/ClusterAwareRegionFactory.java	2009-11-18 16:56:13 UTC (rev 18005)
@@ -34,8 +34,8 @@
 import org.hibernate.cache.infinispan.InfinispanRegionFactory;
 import org.hibernate.cfg.Settings;
 import org.infinispan.manager.CacheManager;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import org.infinispan.util.logging.Log;
+import org.infinispan.util.logging.LogFactory;
 
 /**
  * ClusterAwareRegionFactory.
@@ -45,7 +45,7 @@
  */
 public class ClusterAwareRegionFactory implements RegionFactory {
    
-   private static final Logger log = LoggerFactory.getLogger(ClusterAwareRegionFactory.class);
+   private static final Log log = LogFactory.getLog(ClusterAwareRegionFactory.class);
    private static final Hashtable<String, CacheManager> cacheManagers = new Hashtable<String, CacheManager>();
 
    private final InfinispanRegionFactory delegate = new InfinispanRegionFactory();
@@ -75,7 +75,7 @@
    }
 
    public void start(Settings settings, Properties properties) throws CacheException {
-      cacheManagerName = properties.getProperty(AbstractDualNodeTestCase.NODE_ID_PROP);
+      cacheManagerName = properties.getProperty(DualNodeTestCase.NODE_ID_PROP);
       
       CacheManager existing = getCacheManager(cacheManagerName);
       locallyAdded = (existing == null);

Modified: core/trunk/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/cluster/DualNodeConnectionProviderImpl.java
===================================================================
--- core/trunk/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/cluster/DualNodeConnectionProviderImpl.java	2009-11-18 16:35:28 UTC (rev 18004)
+++ core/trunk/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/cluster/DualNodeConnectionProviderImpl.java	2009-11-18 16:56:13 UTC (rev 18005)
@@ -47,9 +47,9 @@
    }
 
    public void configure(Properties props) throws HibernateException {
-      nodeId = props.getProperty(AbstractDualNodeTestCase.NODE_ID_PROP);
+      nodeId = props.getProperty(DualNodeTestCase.NODE_ID_PROP);
       if (nodeId == null)
-         throw new HibernateException(AbstractDualNodeTestCase.NODE_ID_PROP + " not configured");
+         throw new HibernateException(DualNodeTestCase.NODE_ID_PROP + " not configured");
    }
 
    public Connection getConnection() throws SQLException {

Modified: core/trunk/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/cluster/DualNodeJtaTransactionImpl.java
===================================================================
--- core/trunk/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/cluster/DualNodeJtaTransactionImpl.java	2009-11-18 16:35:28 UTC (rev 18004)
+++ core/trunk/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/cluster/DualNodeJtaTransactionImpl.java	2009-11-18 16:56:13 UTC (rev 18005)
@@ -42,8 +42,8 @@
 import javax.transaction.xa.XAResource;
 import javax.transaction.xa.Xid;
 
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import org.infinispan.util.logging.Log;
+import org.infinispan.util.logging.LogFactory;
 
 /**
  * SimpleJtaTransactionImpl variant that works with DualNodeTransactionManagerImpl.
@@ -51,7 +51,7 @@
  * @author Brian Stansberry
  */
 public class DualNodeJtaTransactionImpl implements Transaction {
-   private static final Logger log = LoggerFactory.getLogger(DualNodeJtaTransactionImpl.class);
+   private static final Log log = LogFactory.getLog(DualNodeJtaTransactionImpl.class);
 
    private int status;
    private LinkedList synchronizations;

Modified: core/trunk/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/cluster/DualNodeJtaTransactionManagerImpl.java
===================================================================
--- core/trunk/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/cluster/DualNodeJtaTransactionManagerImpl.java	2009-11-18 16:35:28 UTC (rev 18004)
+++ core/trunk/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/cluster/DualNodeJtaTransactionManagerImpl.java	2009-11-18 16:56:13 UTC (rev 18005)
@@ -35,8 +35,8 @@
 import javax.transaction.Transaction;
 import javax.transaction.TransactionManager;
 
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import org.infinispan.util.logging.Log;
+import org.infinispan.util.logging.LogFactory;
 
 /**
  * Variant of SimpleJtaTransactionManagerImpl that doesn't use a VM-singleton, but rather a set of
@@ -46,7 +46,7 @@
  */
 public class DualNodeJtaTransactionManagerImpl implements TransactionManager {
 
-   private static final Logger log = LoggerFactory.getLogger(DualNodeJtaTransactionManagerImpl.class);
+   private static final Log log = LogFactory.getLog(DualNodeJtaTransactionManagerImpl.class);
 
    private static final Hashtable INSTANCES = new Hashtable();
 

Copied: core/trunk/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/cluster/DualNodeTestCase.java (from rev 17976, core/trunk/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/cluster/AbstractDualNodeTestCase.java)
===================================================================
--- core/trunk/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/cluster/DualNodeTestCase.java	                        (rev 0)
+++ core/trunk/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/cluster/DualNodeTestCase.java	2009-11-18 16:56:13 UTC (rev 18005)
@@ -0,0 +1,243 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2009, Red Hat, Inc. and/or it's affiliates, 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.hibernate.test.cache.infinispan.functional.cluster;
+
+import org.hibernate.Session;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.cfg.Environment;
+import org.hibernate.cfg.Mappings;
+import org.hibernate.dialect.Dialect;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.junit.functional.ExecutionEnvironment;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.transaction.CMTTransactionFactory;
+import org.infinispan.util.logging.Log;
+import org.infinispan.util.logging.LogFactory;
+
+/**
+ * AbstractDualNodeTestCase.
+ * 
+ * @author Galder Zamarreño
+ * @since 3.5
+ */
+public abstract class DualNodeTestCase extends FunctionalTestCase {
+   
+   private static final Log log = LogFactory.getLog(DualNodeTestCase.class);
+   public static final String NODE_ID_PROP = "hibernate.test.cluster.node.id";
+   public static final String LOCAL = "local";
+   public static final String REMOTE = "remote";
+   private ExecutionEnvironment secondNodeEnvironment;
+   private Session secondNodeSession;
+
+   public DualNodeTestCase(String string) {
+      super(string);
+   }
+   
+   public String[] getMappings() {
+      return new String[] { "cache/infinispan/functional/Contact.hbm.xml", "cache/infinispan/functional/Customer.hbm.xml" };
+   }
+   
+   @Override
+   public String getCacheConcurrencyStrategy() {
+      return "transactional";
+   }
+   
+   protected Class getCacheRegionFactory() {
+      return ClusterAwareRegionFactory.class;
+   }
+
+   @Override
+   public void configure(Configuration cfg) {
+      standardConfigure(cfg);
+      configureFirstNode(cfg);
+   }
+
+   @Override
+   protected void prepareTest() throws Exception {
+      log.info("Building second node locally managed execution env");
+      secondNodeEnvironment = new ExecutionEnvironment(new SecondNodeSettings());
+      secondNodeEnvironment.initialize();
+      super.prepareTest();
+   }
+   
+   @Override
+   protected void runTest() throws Throwable {
+      try {
+          super.runTest();
+      } finally {
+         if ( secondNodeSession != null && secondNodeSession.isOpen() ) {
+             if ( secondNodeSession.isConnected() ) {
+                secondNodeSession.connection().rollback();
+             }
+             secondNodeSession.close();
+             secondNodeSession = null;
+             fail( "unclosed session" );
+         } else {
+            secondNodeSession = null;
+         }
+         
+      }
+   }
+
+   @Override
+   protected void cleanupTest() throws Exception {
+      try {
+          super.cleanupTest();
+      
+          log.info( "Destroying second node locally managed execution env" );
+          secondNodeEnvironment.complete();
+          secondNodeEnvironment = null;
+      } finally {
+         cleanupTransactionManagement();
+      }
+   }
+   
+   protected void cleanupTransactionManagement() {
+      DualNodeJtaTransactionManagerImpl.cleanupTransactions();
+      DualNodeJtaTransactionManagerImpl.cleanupTransactionManagers();
+   }
+
+   public ExecutionEnvironment getSecondNodeEnvironment() {
+      return secondNodeEnvironment;
+   }
+
+   protected Class getConnectionProviderClass() {
+      return DualNodeConnectionProviderImpl.class;
+   }
+
+   protected Class getTransactionManagerLookupClass() {
+      return DualNodeTransactionManagerLookup.class;
+   }
+
+   protected Class getTransactionFactoryClass() {
+      return CMTTransactionFactory.class;
+   }
+
+   /**
+    * Apply any node-specific configurations to our first node.
+    * 
+    * @param the
+    *           Configuration to update.
+    */
+   protected void configureFirstNode(Configuration cfg) {
+      cfg.setProperty(NODE_ID_PROP, LOCAL);
+   }
+
+   /**
+    * Apply any node-specific configurations to our second node.
+    * 
+    * @param the
+    *           Configuration to update.
+    */
+   protected void configureSecondNode(Configuration cfg) {
+      cfg.setProperty(NODE_ID_PROP, REMOTE);
+   }
+   
+   protected void sleep(long ms) {
+      try {
+          Thread.sleep(ms);
+      }
+      catch (InterruptedException e) {
+          log.warn("Interrupted during sleep", e);
+      }
+  }
+
+   protected boolean getUseQueryCache() {
+      return true;
+   }
+
+   protected void standardConfigure(Configuration cfg) {
+      super.configure(cfg);
+
+      cfg.setProperty(Environment.CONNECTION_PROVIDER, getConnectionProviderClass().getName());
+      cfg.setProperty(Environment.TRANSACTION_MANAGER_STRATEGY, getTransactionManagerLookupClass().getName());
+      cfg.setProperty(Environment.TRANSACTION_STRATEGY, getTransactionFactoryClass().getName());
+      cfg.setProperty(Environment.CACHE_REGION_FACTORY, getCacheRegionFactory().getName());
+      cfg.setProperty(Environment.USE_QUERY_CACHE, String.valueOf(getUseQueryCache()));
+   }
+
+   /**
+    * Settings impl that delegates most calls to the DualNodeTestCase itself, but overrides the
+    * configure method to allow separate cache settings for the second node.
+    */
+   public class SecondNodeSettings implements ExecutionEnvironment.Settings {
+      private final DualNodeTestCase delegate;
+
+      public SecondNodeSettings() {
+         this.delegate = DualNodeTestCase.this;
+      }
+
+      /**
+       * This is the important one -- we extend the delegate's work by adding second-node specific
+       * settings
+       */
+      public void configure(Configuration arg0) {
+         delegate.standardConfigure(arg0);
+         configureSecondNode(arg0);
+      }
+
+      /**
+       * Disable creating of schemas; we let the primary session factory do that to our shared
+       * database.
+       */
+      public boolean createSchema() {
+         return false;
+      }
+
+      /**
+       * Disable creating of schemas; we let the primary session factory do that to our shared
+       * database.
+       */
+      public boolean recreateSchemaAfterFailure() {
+         return false;
+      }
+
+      public void afterConfigurationBuilt(Mappings arg0, Dialect arg1) {
+         delegate.afterConfigurationBuilt(arg0, arg1);
+      }
+
+      public void afterSessionFactoryBuilt(SessionFactoryImplementor arg0) {
+         delegate.afterSessionFactoryBuilt(arg0);
+      }
+
+      public boolean appliesTo(Dialect arg0) {
+         return delegate.appliesTo(arg0);
+      }
+
+      public String getBaseForMappings() {
+         return delegate.getBaseForMappings();
+      }
+
+      public String getCacheConcurrencyStrategy() {
+         return delegate.getCacheConcurrencyStrategy();
+      }
+
+      public String[] getMappings() {
+         return delegate.getMappings();
+      }
+
+      public boolean overrideCacheStrategy() {
+         return delegate.overrideCacheStrategy();
+      }
+   }
+
+}

Modified: core/trunk/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/cluster/DualNodeTransactionManagerLookup.java
===================================================================
--- core/trunk/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/cluster/DualNodeTransactionManagerLookup.java	2009-11-18 16:35:28 UTC (rev 18004)
+++ core/trunk/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/cluster/DualNodeTransactionManagerLookup.java	2009-11-18 16:56:13 UTC (rev 18005)
@@ -39,9 +39,9 @@
 public class DualNodeTransactionManagerLookup implements TransactionManagerLookup {
 
    public TransactionManager getTransactionManager(Properties props) throws HibernateException {
-      String nodeId = props.getProperty(AbstractDualNodeTestCase.NODE_ID_PROP);
+      String nodeId = props.getProperty(DualNodeTestCase.NODE_ID_PROP);
       if (nodeId == null)
-         throw new HibernateException(AbstractDualNodeTestCase.NODE_ID_PROP + " not configured");
+         throw new HibernateException(DualNodeTestCase.NODE_ID_PROP + " not configured");
       return DualNodeJtaTransactionManagerImpl.getInstance(nodeId);
    }
 

Modified: core/trunk/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/cluster/EntityCollectionInvalidationTestCase.java
===================================================================
--- core/trunk/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/cluster/EntityCollectionInvalidationTestCase.java	2009-11-18 16:35:28 UTC (rev 18004)
+++ core/trunk/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/cluster/EntityCollectionInvalidationTestCase.java	2009-11-18 16:56:13 UTC (rev 18005)
@@ -39,8 +39,8 @@
 import org.infinispan.notifications.cachelistener.annotation.CacheEntryVisited;
 import org.infinispan.notifications.cachelistener.event.CacheEntryVisitedEvent;
 import org.jboss.util.collection.ConcurrentSet;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import org.infinispan.util.logging.Log;
+import org.infinispan.util.logging.LogFactory;
 
 /**
  * EntityCollectionInvalidationTestCase.
@@ -48,8 +48,8 @@
  * @author Galder Zamarreño
  * @since 3.5
  */
-public class EntityCollectionInvalidationTestCase extends AbstractDualNodeTestCase {
-   private static final Logger log = LoggerFactory.getLogger(EntityCollectionInvalidationTestCase.class);
+public class EntityCollectionInvalidationTestCase extends DualNodeTestCase {
+   private static final Log log = LogFactory.getLog(EntityCollectionInvalidationTestCase.class);
    private static final long SLEEP_TIME = 50l;
    private static final Integer CUSTOMER_ID = new Integer(1);
    static int test = 0;
@@ -67,7 +67,7 @@
 
       // Bind a listener to the "local" cache
       // Our region factory makes its CacheManager available to us
-      CacheManager localManager = ClusterAwareRegionFactory.getCacheManager(AbstractDualNodeTestCase.LOCAL);
+      CacheManager localManager = ClusterAwareRegionFactory.getCacheManager(DualNodeTestCase.LOCAL);
       // Cache localCache = localManager.getCache("entity");
       Cache localCustomerCache = localManager.getCache(Customer.class.getName());
       Cache localContactCache = localManager.getCache(Contact.class.getName());
@@ -76,10 +76,10 @@
       localCustomerCache.addListener(localListener);
       localContactCache.addListener(localListener);
       localCollectionCache.addListener(localListener);
-      TransactionManager localTM = DualNodeJtaTransactionManagerImpl.getInstance(AbstractDualNodeTestCase.LOCAL);
+      TransactionManager localTM = DualNodeJtaTransactionManagerImpl.getInstance(DualNodeTestCase.LOCAL);
 
       // Bind a listener to the "remote" cache
-      CacheManager remoteManager = ClusterAwareRegionFactory.getCacheManager(AbstractDualNodeTestCase.REMOTE);
+      CacheManager remoteManager = ClusterAwareRegionFactory.getCacheManager(DualNodeTestCase.REMOTE);
       Cache remoteCustomerCache = remoteManager.getCache(Customer.class.getName());
       Cache remoteContactCache = remoteManager.getCache(Contact.class.getName());
       Cache remoteCollectionCache = remoteManager.getCache(Customer.class.getName() + ".contacts");
@@ -87,7 +87,7 @@
       remoteCustomerCache.addListener(remoteListener);
       remoteContactCache.addListener(remoteListener);
       remoteCollectionCache.addListener(remoteListener);
-      TransactionManager remoteTM = DualNodeJtaTransactionManagerImpl.getInstance(AbstractDualNodeTestCase.REMOTE);
+      TransactionManager remoteTM = DualNodeJtaTransactionManagerImpl.getInstance(DualNodeTestCase.REMOTE);
 
       SessionFactory localFactory = getEnvironment().getSessionFactory();
       SessionFactory remoteFactory = getSecondNodeEnvironment().getSessionFactory();
@@ -319,7 +319,7 @@
 
    @Listener
    public static class MyListener {
-      private static final Logger log = LoggerFactory.getLogger(MyListener.class);
+      private static final Log log = LogFactory.getLog(MyListener.class);
       private Set<String> visited = new ConcurrentSet<String>();
       private final String name;
       

Modified: core/trunk/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/cluster/SessionRefreshTestCase.java
===================================================================
--- core/trunk/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/cluster/SessionRefreshTestCase.java	2009-11-18 16:35:28 UTC (rev 18004)
+++ core/trunk/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/cluster/SessionRefreshTestCase.java	2009-11-18 16:56:13 UTC (rev 18005)
@@ -41,7 +41,7 @@
  * @author Galder Zamarreño
  * @since 3.5
  */
-public class SessionRefreshTestCase extends AbstractDualNodeTestCase {
+public class SessionRefreshTestCase extends DualNodeTestCase {
 
    public static final String OUR_PACKAGE = SessionRefreshTestCase.class.getPackage().getName();
    
@@ -90,41 +90,41 @@
 
    public void testRefreshAfterExternalChange() throws Exception {
       // First session factory uses a cache
-      CacheManager localManager = ClusterAwareRegionFactory.getCacheManager(AbstractDualNodeTestCase.LOCAL);
+      CacheManager localManager = ClusterAwareRegionFactory.getCacheManager(DualNodeTestCase.LOCAL);
       localCache = localManager.getCache(Account.class.getName());
-      TransactionManager localTM = DualNodeJtaTransactionManagerImpl.getInstance(AbstractDualNodeTestCase.LOCAL);
+      TransactionManager localTM = DualNodeJtaTransactionManagerImpl.getInstance(DualNodeTestCase.LOCAL);
       SessionFactory localFactory = getEnvironment().getSessionFactory();
 
       // Second session factory doesn't; just needs a transaction manager
-      TransactionManager remoteTM = DualNodeJtaTransactionManagerImpl.getInstance(AbstractDualNodeTestCase.REMOTE);
+      TransactionManager remoteTM = DualNodeJtaTransactionManagerImpl.getInstance(DualNodeTestCase.REMOTE);
       SessionFactory remoteFactory = getSecondNodeEnvironment().getSessionFactory();
 
       ClassLoaderTestDAO dao0 = new ClassLoaderTestDAO(localFactory, localTM);
       ClassLoaderTestDAO dao1 = new ClassLoaderTestDAO(remoteFactory, remoteTM);
 
       Integer id = new Integer(1);
-      dao0.createAccount(dao0.getSmith(), id, new Integer(5), AbstractDualNodeTestCase.LOCAL);
+      dao0.createAccount(dao0.getSmith(), id, new Integer(5), DualNodeTestCase.LOCAL);
 
       // Basic sanity check
       Account acct1 = dao1.getAccount(id);
       assertNotNull(acct1);
-      assertEquals(AbstractDualNodeTestCase.LOCAL, acct1.getBranch());
+      assertEquals(DualNodeTestCase.LOCAL, acct1.getBranch());
 
       // This dao's session factory isn't caching, so cache won't see this change
-      dao1.updateAccountBranch(id, AbstractDualNodeTestCase.REMOTE);
+      dao1.updateAccountBranch(id, DualNodeTestCase.REMOTE);
 
       // dao1's session doesn't touch the cache,
       // so reading from dao0 should show a stale value from the cache
       // (we check to confirm the cache is used)
       Account acct0 = dao0.getAccount(id);
       assertNotNull(acct0);
-      assertEquals(AbstractDualNodeTestCase.LOCAL, acct0.getBranch());
+      assertEquals(DualNodeTestCase.LOCAL, acct0.getBranch());
       log.debug("Contents when re-reading from local: " + TestingUtil.printCache(localCache));
 
       // Now call session.refresh and confirm we get the correct value
       acct0 = dao0.getAccountWithRefresh(id);
       assertNotNull(acct0);
-      assertEquals(AbstractDualNodeTestCase.REMOTE, acct0.getBranch());
+      assertEquals(DualNodeTestCase.REMOTE, acct0.getBranch());
       log.debug("Contents after refreshing in remote: " + TestingUtil.printCache(localCache));
 
       // Double check with a brand new session, in case the other session
@@ -132,7 +132,7 @@
       ClassLoaderTestDAO dao0A = new ClassLoaderTestDAO(localFactory, localTM);
       Account acct0A = dao0A.getAccount(id);
       assertNotNull(acct0A);
-      assertEquals(AbstractDualNodeTestCase.REMOTE, acct0A.getBranch());
+      assertEquals(DualNodeTestCase.REMOTE, acct0A.getBranch());
       log.debug("Contents after creating a new session: " + TestingUtil.printCache(localCache));
    }
 }

Modified: core/trunk/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/tm/XaTransactionImpl.java
===================================================================
--- core/trunk/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/tm/XaTransactionImpl.java	2009-11-18 16:35:28 UTC (rev 18004)
+++ core/trunk/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/tm/XaTransactionImpl.java	2009-11-18 16:56:13 UTC (rev 18005)
@@ -40,8 +40,8 @@
 import javax.transaction.xa.XAResource;
 import javax.transaction.xa.Xid;
 
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import org.infinispan.util.logging.Log;
+import org.infinispan.util.logging.LogFactory;
 
 /**
  * XaResourceCapableTransactionImpl.
@@ -50,7 +50,7 @@
  * @since 3.5
  */
 public class XaTransactionImpl implements Transaction {
-   private static final Logger log = LoggerFactory.getLogger(XaTransactionImpl.class);
+   private static final Log log = LogFactory.getLog(XaTransactionImpl.class);
    private int status;
    private LinkedList synchronizations;
    private Connection connection; // the only resource we care about is jdbc connection

Modified: core/trunk/cache-infinispan/src/test/resources/hibernate.properties
===================================================================
--- core/trunk/cache-infinispan/src/test/resources/hibernate.properties	2009-11-18 16:35:28 UTC (rev 18004)
+++ core/trunk/cache-infinispan/src/test/resources/hibernate.properties	2009-11-18 16:56:13 UTC (rev 18005)
@@ -34,7 +34,3 @@
 hibernate.max_fetch_depth 5
 
 hibernate.generate_statistics true
-
-hibernate.cache.use_second_level_cache true
-hibernate.cache.use_query_cache true
-hibernate.cache.region.factory_class org.hibernate.cache.infinispan.InfinispanRegionFactory
\ No newline at end of file



More information about the hibernate-commits mailing list