[hibernate-commits] Hibernate SVN: r17355 - in core/branches/INFINISPAN/cache-infinispan/src: main/java/org/hibernate/cache/infinispan/collection and 13 other directories.

hibernate-commits at lists.jboss.org hibernate-commits at lists.jboss.org
Tue Aug 18 15:48:57 EDT 2009


Author: galder.zamarreno at jboss.com
Date: 2009-08-18 15:48:57 -0400 (Tue, 18 Aug 2009)
New Revision: 17355

Added:
   core/branches/INFINISPAN/cache-infinispan/src/main/java/org/hibernate/cache/infinispan/timestamp/TimestampTypeOverrides.java
   core/branches/INFINISPAN/cache-infinispan/src/main/java/org/hibernate/cache/infinispan/tm/
   core/branches/INFINISPAN/cache-infinispan/src/main/java/org/hibernate/cache/infinispan/tm/HibernateTransactionManagerLookup.java
   core/branches/INFINISPAN/cache-infinispan/src/main/java/org/hibernate/cache/infinispan/util/
   core/branches/INFINISPAN/cache-infinispan/src/main/java/org/hibernate/cache/infinispan/util/CacheHelper.java
   core/branches/INFINISPAN/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/AbstractGeneralDataRegionTestCase.java
   core/branches/INFINISPAN/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/AbstractNonFunctionalTestCase.java
   core/branches/INFINISPAN/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/AbstractRegionImplTestCase.java
   core/branches/INFINISPAN/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/AbstractFunctionalTestCase.java
   core/branches/INFINISPAN/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/query/QueryRegionImplTestCase.java
   core/branches/INFINISPAN/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/tm/
   core/branches/INFINISPAN/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/tm/XaConnectionProvider.java
   core/branches/INFINISPAN/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/tm/XaTransactionImpl.java
   core/branches/INFINISPAN/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/tm/XaTransactionManagerImpl.java
   core/branches/INFINISPAN/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/tm/XaTransactionManagerLookup.java
   core/branches/INFINISPAN/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/util/
   core/branches/INFINISPAN/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/util/BatchModeTransactionManagerLookup.java
   core/branches/INFINISPAN/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/util/CacheTestSupport.java
   core/branches/INFINISPAN/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/util/CacheTestUtil.java
Removed:
   core/branches/INFINISPAN/cache-infinispan/src/main/java/org/hibernate/cache/infinispan/InfinispanConfiguration.java
   core/branches/INFINISPAN/cache-infinispan/src/main/java/org/hibernate/cache/infinispan/TimestampTypeOverrides.java
   core/branches/INFINISPAN/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/AbstractInfinispanTestCase.java
   core/branches/INFINISPAN/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/util/
Modified:
   core/branches/INFINISPAN/cache-infinispan/src/main/java/org/hibernate/cache/infinispan/InfinispanRegionFactory.java
   core/branches/INFINISPAN/cache-infinispan/src/main/java/org/hibernate/cache/infinispan/collection/InfinispanCollectionRegion.java
   core/branches/INFINISPAN/cache-infinispan/src/main/java/org/hibernate/cache/infinispan/entity/InfinispanEntityRegion.java
   core/branches/INFINISPAN/cache-infinispan/src/main/java/org/hibernate/cache/infinispan/impl/BaseGeneralDataRegion.java
   core/branches/INFINISPAN/cache-infinispan/src/main/java/org/hibernate/cache/infinispan/impl/BaseRegion.java
   core/branches/INFINISPAN/cache-infinispan/src/main/java/org/hibernate/cache/infinispan/impl/BaseTransactionalDataRegion.java
   core/branches/INFINISPAN/cache-infinispan/src/main/java/org/hibernate/cache/infinispan/query/InfinispanQueryResultsRegion.java
   core/branches/INFINISPAN/cache-infinispan/src/main/java/org/hibernate/cache/infinispan/timestamp/InfinispanTimestampsRegion.java
   core/branches/INFINISPAN/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/InfinispanRegionFactoryTestCase.java
   core/branches/INFINISPAN/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/BasicReadOnlyTestCase.java
   core/branches/INFINISPAN/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/BasicTransactionalTestCase.java
   core/branches/INFINISPAN/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/bulk/BulkOperationsTestCase.java
   core/branches/INFINISPAN/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/cluster/DualNodeJtaTransactionImpl.java
   core/branches/INFINISPAN/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/cluster/EntityCollectionInvalidationTestCase.java
Log:
[ISPN-6] Infinispan now uses Hibernate's transaction manager.

Deleted: core/branches/INFINISPAN/cache-infinispan/src/main/java/org/hibernate/cache/infinispan/InfinispanConfiguration.java
===================================================================
--- core/branches/INFINISPAN/cache-infinispan/src/main/java/org/hibernate/cache/infinispan/InfinispanConfiguration.java	2009-08-18 17:23:57 UTC (rev 17354)
+++ core/branches/INFINISPAN/cache-infinispan/src/main/java/org/hibernate/cache/infinispan/InfinispanConfiguration.java	2009-08-18 19:48:57 UTC (rev 17355)
@@ -1,39 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source.
- * Copyright 2009, Red Hat Middleware LLC, and individual contributors
- * as indicated by the @author tags. See the copyright.txt file in the
- * distribution for a full listing of individual contributors.
- *
- * This is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of
- * the License, or (at your option) any later version.
- *
- * This software is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this software; if not, write to the Free
- * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
- */
-package org.hibernate.cache.infinispan;
-
-import org.infinispan.config.Configuration;
-
-/**
- * InfinispanConfiguration.
- * 
- * @author Galder Zamarreño
- * @since 4.0
- */
-public class InfinispanConfiguration {
-   
-   private final Configuration configuration;
-   
-   public InfinispanConfiguration(Configuration configuration) {
-      this.configuration = configuration; 
-   }
-}

Modified: core/branches/INFINISPAN/cache-infinispan/src/main/java/org/hibernate/cache/infinispan/InfinispanRegionFactory.java
===================================================================
--- core/branches/INFINISPAN/cache-infinispan/src/main/java/org/hibernate/cache/infinispan/InfinispanRegionFactory.java	2009-08-18 17:23:57 UTC (rev 17354)
+++ core/branches/INFINISPAN/cache-infinispan/src/main/java/org/hibernate/cache/infinispan/InfinispanRegionFactory.java	2009-08-18 19:48:57 UTC (rev 17355)
@@ -9,6 +9,8 @@
 import java.util.Properties;
 import java.util.Set;
 
+import javax.transaction.TransactionManager;
+
 import org.hibernate.cache.CacheDataDescription;
 import org.hibernate.cache.CacheException;
 import org.hibernate.cache.CollectionRegion;
@@ -20,7 +22,10 @@
 import org.hibernate.cache.infinispan.entity.InfinispanEntityRegion;
 import org.hibernate.cache.infinispan.query.InfinispanQueryResultsRegion;
 import org.hibernate.cache.infinispan.timestamp.InfinispanTimestampsRegion;
+import org.hibernate.cache.infinispan.timestamp.TimestampTypeOverrides;
+import org.hibernate.cache.infinispan.tm.HibernateTransactionManagerLookup;
 import org.hibernate.cfg.Settings;
+import org.hibernate.transaction.TransactionManagerLookup;
 import org.hibernate.util.PropertiesHelper;
 import org.infinispan.Cache;
 import org.infinispan.config.Configuration;
@@ -126,6 +131,10 @@
    private final Map<String, TypeOverrides> typeOverrides = new HashMap<String, TypeOverrides>();
    
    private final Set<String> definedConfigurations = new HashSet<String>();
+   
+   private org.infinispan.transaction.lookup.TransactionManagerLookup transactionManagerlookup;
+   
+   private TransactionManager transactionManager;
 
    /**
     * Create a new instance using the default configuration.
@@ -143,46 +152,17 @@
    }
 
    /** {@inheritDoc} */
-   public CollectionRegion buildCollectionRegion(String regionName, Properties properties,
-            CacheDataDescription metadata) throws CacheException {
+   public CollectionRegion buildCollectionRegion(String regionName, Properties properties, CacheDataDescription metadata) throws CacheException {
       log.debug("Building collection cache region [" + regionName + "]");
-      Cache cache = getCache(regionName, COLLECTION_KEY);
-      return new InfinispanCollectionRegion(cache, regionName, metadata);
+      Cache cache = getCache(regionName, COLLECTION_KEY, properties);
+      return new InfinispanCollectionRegion(cache, regionName, metadata, transactionManager);
    }
 
    /** {@inheritDoc} */
    public EntityRegion buildEntityRegion(String regionName, Properties properties, CacheDataDescription metadata) throws CacheException {
       if (log.isDebugEnabled()) log.debug("Building entity cache region [" + regionName + "]");
-      Cache cache = getCache(regionName, ENTITY_KEY);
-      return new InfinispanEntityRegion(cache, regionName, metadata);
-//      TypeOverrides regionOverride = typeOverrides.get(regionName);
-//      if (regionOverride != null) {
-//         if (log.isDebugEnabled()) log.debug("Entity cache region specific configuration exists: " + regionOverride);
-//         String cacheName = regionOverride.getCacheName();
-//         String templateCacheName = null;
-//         if (cacheName != null) {
-//            // If override has been converted to cache configuration, it means that the cache configuration has 
-//            // already been defined and hence we only need to get the cache instance corresponding to that cache name
-//            if (!regionOverride.isConvertedToInfinispanConfiguration()) {
-//               templateCacheName = cacheName;
-//               Configuration regionCacheCfg = regionOverride.createInfinispanConfiguration();
-//               manager.defineConfiguration(cacheName, templateCacheName, regionCacheCfg);
-//            } 
-//            cache = manager.getCache(cacheName);
-//         } else {
-//            // If cache name is null, the base configuration is the generic entity data type one 
-//            // and the cache name is the name of the region.
-//            if (!regionOverride.isConvertedToInfinispanConfiguration()) {
-//               templateCacheName = typeOverrides.get(ENTITY_KEY).getCacheName();
-//               Configuration regionCacheCfg = regionOverride.createInfinispanConfiguration();
-//               manager.defineConfiguration(regionName, templateCacheName, regionCacheCfg);
-//            }
-//            cache = manager.getCache(regionName);
-//         }
-//      } else {
-//         // No region specific overrides, get a cache instance for the generic entity data type region
-//         cache = manager.getCache(typeOverrides.get(ENTITY_KEY).getCacheName());
-//      }
+      Cache cache = getCache(regionName, ENTITY_KEY, properties);
+      return new InfinispanEntityRegion(cache, regionName, metadata, transactionManager);
    }
 
    /**
@@ -192,7 +172,7 @@
             throws CacheException {
       log.debug("Building query results cache region [" + regionName + "]");
       String cacheName = typeOverrides.get(QUERY_KEY).getCacheName();
-      return new InfinispanQueryResultsRegion(manager.getCache(cacheName), regionName);
+      return new InfinispanQueryResultsRegion(manager.getCache(cacheName), regionName, properties, transactionManager);
    }
 
    /**
@@ -202,7 +182,7 @@
             throws CacheException {
       log.debug("Building timestamps cache region [" + regionName + "]");
       String cacheName = typeOverrides.get(TIMESTAMPS_KEY).getCacheName();
-      return new InfinispanTimestampsRegion(manager.getCache(cacheName), regionName);
+      return new InfinispanTimestampsRegion(manager.getCache(cacheName), regionName, transactionManager);
    }
 
    /**
@@ -233,6 +213,9 @@
    public void start(Settings settings, Properties properties) throws CacheException {
       log.debug("Starting Infinispan CacheManager");
       try {
+         transactionManagerlookup = new HibernateTransactionManagerLookup(settings, properties);
+         transactionManager = transactionManagerlookup.getTransactionManager();
+         
          String configLoc = PropertiesHelper.getString(INFINISPAN_CONFIG_RESOURCE_PROP, properties, DEF_INFINISPAN_CONFIG_RESOURCE);
          manager = createCacheManager(configLoc);
          initGenericDataTypeOverrides();
@@ -244,51 +227,12 @@
                dissectProperty(prefixLoc, key, properties);
             }
          }
-         defineGenericDataTypeCacheConfigurations();
+         defineGenericDataTypeCacheConfigurations(settings, properties);
       } catch (CacheException ce) {
          throw ce;
       } catch (Throwable t) {
           throw new CacheException("Unable to start region factory", t);
       }
-               
-//               if ((suffixLoc = key.indexOf(CONFIG_SUFFIX)) != -1) {
-//                  cfgOverride = getOrCreateConfig(key, prefixLoc, suffixLoc);
-//                  cfgOverride.setCache(PropertiesHelper.extractPropertyValue(key, properties));
-////                  String name = key.substring(prefixLoc + PREFIX.length(), suffixLoc);
-////                  cfgOverride = configs.get(name);
-////                  if (cfgOverride == null) {
-////                     cfgOverride = new DataTypeConfig();
-////                     configs.put(name, cfgOverride);
-////                  }
-////                  String cache = null;
-////                  if (name.equals(ENTITY_CACHE_RESOURCE_PROP)) {
-////                     cache = PropertiesHelper.getString(ENTITY_CACHE_RESOURCE_PROP, properties, DEF_ENTITY_RESOURCE);
-////                  } else if (name.equals(COLLECTION_CACHE_RESOURCE_PROP)) {
-////                     cache = PropertiesHelper.getString(COLLECTION_CACHE_RESOURCE_PROP, properties, DEF_ENTITY_RESOURCE);
-////                  } else if (name.equals(TIMESTAMP_CACHE_RESOURCE_PROP)) {
-////                     cache = PropertiesHelper.getString(TIMESTAMP_CACHE_RESOURCE_PROP, properties, DEF_TIMESTAMP_RESOURCE);
-////                  } else if (name.equals(QUERY_CACHE_RESOURCE_PROP)) {
-////                     cache = PropertiesHelper.getString(QUERY_CACHE_RESOURCE_PROP, properties, DEF_QUERY_RESOURCE);
-////                  } else {
-////                     cache = PropertiesHelper.extractPropertyValue(key, properties);                     
-////                  }
-////                  cfgOverride.setCache(cache);
-//               } else if ((suffixLoc = key.indexOf(STRATEGY_SUFFIX)) != -1) {
-//                  cfgOverride = getOrCreateConfig(key, prefixLoc, suffixLoc);
-//                  cfgOverride.setStrategy(PropertiesHelper.extractPropertyValue(key, properties));
-//               } else if ((suffixLoc = key.indexOf(WAKE_UP_INTERVAL_SUFFIX)) != -1) {
-//                  cfgOverride = getOrCreateConfig(key, prefixLoc, suffixLoc);
-//                  cfgOverride.setWakeUpInterval(Long.parseLong(PropertiesHelper.extractPropertyValue(key, properties)));                  
-//               } else if ((suffixLoc = key.indexOf(MAX_ENTRIES_SUFFIX)) != -1) {
-//                  cfgOverride = getOrCreateConfig(key, prefixLoc, suffixLoc);
-//                  cfgOverride.setMaxEntries(PropertiesHelper.getInt(key, properties, -1));
-//               } else if ((suffixLoc = key.indexOf(LIFESPAN_SUFFIX)) != -1) {
-//                  cfgOverride = getOrCreateConfig(key, prefixLoc, suffixLoc);
-//                  cfgOverride.setLifespan(Long.parseLong(PropertiesHelper.extractPropertyValue(key, properties)));
-//               } else if ((suffixLoc = key.indexOf(MAX_IDLE_SUFFIX)) != -1) {
-//                  cfgOverride = getOrCreateConfig(key, prefixLoc, suffixLoc);
-//                  cfgOverride.setMaxIdle(Long.parseLong(PropertiesHelper.extractPropertyValue(key, properties)));
-//               }  
    }
 
    /**
@@ -341,7 +285,7 @@
       typeOverrides.put(QUERY_KEY, queryOverrides);
       return typeOverrides;
    }
-
+   
 //   private boolean isGenericDataTypeProperty(String property) {
 //      return property.startsWith(PREFIX + ENTITY_KEY) || property.startsWith(PREFIX + COLLECTION_KEY) 
 //            || property.startsWith(PREFIX + QUERY_KEY) || property.startsWith(PREFIX + TIMESTAMP_KEY);
@@ -358,7 +302,7 @@
          cfgOverride.setEvictionStrategy(PropertiesHelper.extractPropertyValue(key, properties));
       } else if ((suffixLoc = key.indexOf(WAKE_UP_INTERVAL_SUFFIX)) != -1) {
          cfgOverride = getOrCreateConfig(prefixLoc, key, suffixLoc);
-         cfgOverride.setEvictionWakeUpInterval(Long.parseLong(PropertiesHelper.extractPropertyValue(key, properties)));                  
+         cfgOverride.setEvictionWakeUpInterval(Long.parseLong(PropertiesHelper.extractPropertyValue(key, properties)));
       } else if ((suffixLoc = key.indexOf(MAX_ENTRIES_SUFFIX)) != -1) {
          cfgOverride = getOrCreateConfig(prefixLoc, key, suffixLoc);
          cfgOverride.setEvictionMaxEntries(PropertiesHelper.getInt(key, properties, -1));
@@ -399,19 +343,23 @@
       return cfgOverride;
    }
    
-   private void defineGenericDataTypeCacheConfigurations() throws CacheException {
+   private void defineGenericDataTypeCacheConfigurations(Settings settings, Properties properties) throws CacheException {
       String[] defaultGenericDataTypes = new String[]{ENTITY_KEY, COLLECTION_KEY, TIMESTAMPS_KEY, QUERY_KEY};
       for (String type : defaultGenericDataTypes) {
          TypeOverrides override = typeOverrides.get(type);
          String cacheName = override.getCacheName();
          Configuration newCacheCfg = override.createInfinispanConfiguration();
+         // Apply overrides
          Configuration cacheConfig = manager.defineConfiguration(cacheName, cacheName, newCacheCfg);
+         // Configure transaction manager
+         cacheConfig = configureTransactionManager(cacheConfig, cacheName, properties);
+         manager.defineConfiguration(cacheName, cacheName, cacheConfig);
          definedConfigurations.add(cacheName);
          override.validateInfinispanConfiguration(cacheConfig);
       }
    }
    
-   private Cache getCache(String regionName, String typeKey) {
+   private Cache getCache(String regionName, String typeKey, Properties properties) {
       TypeOverrides regionOverride = typeOverrides.get(regionName);
       if (!definedConfigurations.contains(regionName)) {
          String templateCacheName = null;
@@ -429,6 +377,9 @@
             templateCacheName = typeOverrides.get(typeKey).getCacheName();
             regionCacheCfg = typeOverrides.get(typeKey).createInfinispanConfiguration();
          }
+         // Configure transaction manager
+         regionCacheCfg = configureTransactionManager(regionCacheCfg, templateCacheName, properties);
+         // Apply overrides
          manager.defineConfiguration(regionName, templateCacheName, regionCacheCfg);
          definedConfigurations.add(regionName);
       }
@@ -467,4 +418,18 @@
 //      // No region specific overrides, get a cache instance for the generic entity data type region
 //      return manager.getCache(regionName);
    }
+   
+   private Configuration configureTransactionManager(Configuration regionOverrides, String templateCacheName, Properties properties) {
+      // Get existing configuration to verify whether a tm was configured or not.
+      Configuration templateConfig = manager.defineConfiguration(templateCacheName, new Configuration());
+      String ispnTmLookupClassName = templateConfig.getTransactionManagerLookupClass();
+      String hbTmLookupClassName = org.hibernate.cache.infinispan.tm.HibernateTransactionManagerLookup.class.getName();
+      if (ispnTmLookupClassName != null && !ispnTmLookupClassName.equals(hbTmLookupClassName)) {
+         log.debug("Infinispan is configured [" + ispnTmLookupClassName + "] with a different transaction manager lookup " +
+               "class than Hibernate [" + hbTmLookupClassName + "]");
+      } else {
+         regionOverrides.setTransactionManagerLookup(transactionManagerlookup);
+      }
+      return regionOverrides;
+   }
 }
\ No newline at end of file

Deleted: core/branches/INFINISPAN/cache-infinispan/src/main/java/org/hibernate/cache/infinispan/TimestampTypeOverrides.java
===================================================================
--- core/branches/INFINISPAN/cache-infinispan/src/main/java/org/hibernate/cache/infinispan/TimestampTypeOverrides.java	2009-08-18 17:23:57 UTC (rev 17354)
+++ core/branches/INFINISPAN/cache-infinispan/src/main/java/org/hibernate/cache/infinispan/TimestampTypeOverrides.java	2009-08-18 19:48:57 UTC (rev 17355)
@@ -1,42 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source.
- * Copyright 2009, Red Hat Middleware LLC, and individual contributors
- * as indicated by the @author tags. See the copyright.txt file in the
- * distribution for a full listing of individual contributors.
- *
- * This is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of
- * the License, or (at your option) any later version.
- *
- * This software is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this software; if not, write to the Free
- * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
- */
-package org.hibernate.cache.infinispan;
-
-import org.hibernate.cache.CacheException;
-import org.infinispan.config.Configuration;
-import org.infinispan.config.Configuration.CacheMode;
-
-/**
- * TimestampTypeOverrides.
- * 
- * @author Galder Zamarreño
- * @since 4.0
- */
-public class TimestampTypeOverrides extends TypeOverrides {
-   @Override
-   public void validateInfinispanConfiguration(Configuration configuration) throws CacheException {
-      CacheMode cacheMode = configuration.getCacheMode();
-      if (cacheMode.equals(CacheMode.INVALIDATION_ASYNC) || cacheMode.equals(CacheMode.INVALIDATION_SYNC)) {
-         throw new CacheException("Timestamp cache cannot be configured with invalidation");
-      }
-   }
-}

Modified: core/branches/INFINISPAN/cache-infinispan/src/main/java/org/hibernate/cache/infinispan/collection/InfinispanCollectionRegion.java
===================================================================
--- core/branches/INFINISPAN/cache-infinispan/src/main/java/org/hibernate/cache/infinispan/collection/InfinispanCollectionRegion.java	2009-08-18 17:23:57 UTC (rev 17354)
+++ core/branches/INFINISPAN/cache-infinispan/src/main/java/org/hibernate/cache/infinispan/collection/InfinispanCollectionRegion.java	2009-08-18 19:48:57 UTC (rev 17355)
@@ -1,5 +1,9 @@
 package org.hibernate.cache.infinispan.collection;
 
+import java.util.Properties;
+
+import javax.transaction.TransactionManager;
+
 import org.hibernate.cache.CacheDataDescription;
 import org.hibernate.cache.CacheException;
 import org.hibernate.cache.CollectionRegion;
@@ -14,8 +18,8 @@
  */
 public class InfinispanCollectionRegion extends BaseTransactionalDataRegion implements CollectionRegion {
 
-   public InfinispanCollectionRegion(Cache<Object, Object> cache, String name, CacheDataDescription metadata) {
-      super(cache, name, metadata);
+   public InfinispanCollectionRegion(Cache<Object, Object> cache, String name, CacheDataDescription metadata, TransactionManager transactionManager) {
+      super(cache, name, metadata, transactionManager);
    }
 
    public CollectionRegionAccessStrategy buildAccessStrategy(AccessType accessType) throws CacheException {

Modified: core/branches/INFINISPAN/cache-infinispan/src/main/java/org/hibernate/cache/infinispan/entity/InfinispanEntityRegion.java
===================================================================
--- core/branches/INFINISPAN/cache-infinispan/src/main/java/org/hibernate/cache/infinispan/entity/InfinispanEntityRegion.java	2009-08-18 17:23:57 UTC (rev 17354)
+++ core/branches/INFINISPAN/cache-infinispan/src/main/java/org/hibernate/cache/infinispan/entity/InfinispanEntityRegion.java	2009-08-18 19:48:57 UTC (rev 17355)
@@ -1,5 +1,9 @@
 package org.hibernate.cache.infinispan.entity;
 
+import java.util.Properties;
+
+import javax.transaction.TransactionManager;
+
 import org.hibernate.cache.CacheDataDescription;
 import org.hibernate.cache.CacheException;
 import org.hibernate.cache.EntityRegion;
@@ -14,8 +18,8 @@
  */
 public class InfinispanEntityRegion extends BaseTransactionalDataRegion implements EntityRegion {
 
-   public InfinispanEntityRegion(Cache<Object, Object> cache, String name, CacheDataDescription metadata) {
-      super(cache, name, metadata);
+   public InfinispanEntityRegion(Cache<Object, Object> cache, String name, CacheDataDescription metadata, TransactionManager transactionManager) {
+      super(cache, name, metadata, transactionManager);
    }
 
    public EntityRegionAccessStrategy buildAccessStrategy(AccessType accessType) throws CacheException {

Modified: core/branches/INFINISPAN/cache-infinispan/src/main/java/org/hibernate/cache/infinispan/impl/BaseGeneralDataRegion.java
===================================================================
--- core/branches/INFINISPAN/cache-infinispan/src/main/java/org/hibernate/cache/infinispan/impl/BaseGeneralDataRegion.java	2009-08-18 17:23:57 UTC (rev 17354)
+++ core/branches/INFINISPAN/cache-infinispan/src/main/java/org/hibernate/cache/infinispan/impl/BaseGeneralDataRegion.java	2009-08-18 19:48:57 UTC (rev 17355)
@@ -1,5 +1,9 @@
 package org.hibernate.cache.infinispan.impl;
 
+import java.util.Properties;
+
+import javax.transaction.TransactionManager;
+
 import org.hibernate.cache.CacheException;
 import org.hibernate.cache.GeneralDataRegion;
 import org.infinispan.Cache;
@@ -11,8 +15,8 @@
  */
 public abstract class BaseGeneralDataRegion extends BaseRegion implements GeneralDataRegion {
 
-   public BaseGeneralDataRegion(Cache<Object, Object> cache, String name) {
-      super(cache, name);
+   public BaseGeneralDataRegion(Cache<Object, Object> cache, String name, TransactionManager transactionManager) {
+      super(cache, name, transactionManager);
    }
 
    public void evict(Object key) throws CacheException {

Modified: core/branches/INFINISPAN/cache-infinispan/src/main/java/org/hibernate/cache/infinispan/impl/BaseRegion.java
===================================================================
--- core/branches/INFINISPAN/cache-infinispan/src/main/java/org/hibernate/cache/infinispan/impl/BaseRegion.java	2009-08-18 17:23:57 UTC (rev 17354)
+++ core/branches/INFINISPAN/cache-infinispan/src/main/java/org/hibernate/cache/infinispan/impl/BaseRegion.java	2009-08-18 19:48:57 UTC (rev 17355)
@@ -1,10 +1,20 @@
 package org.hibernate.cache.infinispan.impl;
 
+import java.lang.reflect.Field;
 import java.util.Map;
+import java.util.Properties;
 
+import javax.transaction.SystemException;
+import javax.transaction.Transaction;
+import javax.transaction.TransactionManager;
+
 import org.hibernate.cache.CacheException;
 import org.hibernate.cache.Region;
+import org.hibernate.cache.infinispan.util.CacheHelper;
+import org.hibernate.transaction.TransactionManagerLookupFactory;
 import org.infinispan.Cache;
+import org.infinispan.context.Flag;
+import org.infinispan.factories.ComponentRegistry;
 
 /**
  * Support for Infinispan {@link Region}s. Handles common "utility" methods for an underlying named
@@ -17,10 +27,12 @@
 abstract class BaseRegion implements Region {
    private final Cache cache;
    private final String name;
+   protected final TransactionManager transactionManager;
 
-   public BaseRegion(Cache cache, String name) {
+   public BaseRegion(Cache cache, String name, TransactionManager transactionManager) {
       this.cache = cache;
       this.name = name;
+      this.transactionManager = transactionManager;
    }
 
    public Cache getCache() {
@@ -71,5 +83,100 @@
    public void destroy() throws CacheException {
       // TODO see if we need to do this even in spite of RF.shutdown()
    }
+   
+   /**
+    * Performs a JBoss Cache <code>get(Fqn, Object)</code> after first
+    * {@link #suspend suspending any ongoing transaction}. Wraps any exception
+    * in a {@link CacheException}. Ensures any ongoing transaction is resumed.
+    * 
+    * @param key The key of the item to get
+    * @param opt any option to add to the get invocation. May be <code>null</code>
+    * @param suppressTimeout should any TimeoutException be suppressed?
+    * @return The retrieved object
+      * @throws CacheException issue managing transaction or talking to cache
+    */
+   protected Object suspendAndGet(Object key, Flag opt, boolean suppressTimeout) throws CacheException {
+       Transaction tx = suspend();
+       try {
+           if (suppressTimeout)
+               return CacheHelper.getAllowingTimeout(cache, key);
+           else
+               return CacheHelper.get(cache, key);
+       } finally {
+           resume(tx);
+       }
+   }
+   
+   /**
+    * Tell the TransactionManager to suspend any ongoing transaction.
+    * 
+    * @return the transaction that was suspended, or <code>null</code> if
+    *         there wasn't one
+    */
+   protected Transaction suspend() {
+       Transaction tx = null;
+       try {
+           if (transactionManager != null) {
+               tx = transactionManager.suspend();
+           }
+       } catch (SystemException se) {
+           throw new CacheException("Could not suspend transaction", se);
+       }
+       return tx;
+   }
+   
+   /**
+    * Tell the TransactionManager to resume the given transaction
+    * 
+    * @param tx
+    *            the transaction to suspend. May be <code>null</code>.
+    */
+   protected void resume(Transaction tx) {
+       try {
+           if (tx != null)
+               transactionManager.resume(tx);
+       } catch (Exception e) {
+           throw new CacheException("Could not resume transaction", e);
+       }
+   }
+   
+//   /**
+//    * HACKY WAY TO GET THE TRANSACTION MANAGER, TODO: resolve it!
+//    */
+//   private static TransactionManager getTransactionManager(Properties properties) {
+////      return cache == null ? null : extractComponent(cache, TransactionManager.class);
+//      return TransactionManagerLookupFactory.getTransactionManager(properties);
+//   }
+//   
+//   public static <T> T extractComponent(Cache cache, Class<T> componentType) {
+//      ComponentRegistry cr = extractComponentRegistry(cache);
+//      return cr.getComponent(componentType);
+//   }
+//   
+//   public static ComponentRegistry extractComponentRegistry(Cache cache) {
+//      return (ComponentRegistry) extractField(cache, "componentRegistry");
+//   }
+//   
+//   public static Object extractField(Object target, String fieldName) {
+//      return extractField(target.getClass(), target, fieldName);
+//   }
+//   
+//   public static Object extractField(Class type, Object target, String fieldName) {
+//      Field field;
+//      try {
+//         field = type.getDeclaredField(fieldName);
+//         field.setAccessible(true);
+//         return field.get(target);
+//      }
+//      catch (Exception e) {
+//         if (type.equals(Object.class)) {
+//            e.printStackTrace();
+//            return null;
+//         } else {
+//            // try with superclass!!
+//            return extractField(type.getSuperclass(), target, fieldName);
+//         }
+//      }
+//   }
 
 }
\ No newline at end of file

Modified: core/branches/INFINISPAN/cache-infinispan/src/main/java/org/hibernate/cache/infinispan/impl/BaseTransactionalDataRegion.java
===================================================================
--- core/branches/INFINISPAN/cache-infinispan/src/main/java/org/hibernate/cache/infinispan/impl/BaseTransactionalDataRegion.java	2009-08-18 17:23:57 UTC (rev 17354)
+++ core/branches/INFINISPAN/cache-infinispan/src/main/java/org/hibernate/cache/infinispan/impl/BaseTransactionalDataRegion.java	2009-08-18 19:48:57 UTC (rev 17355)
@@ -1,5 +1,9 @@
 package org.hibernate.cache.infinispan.impl;
 
+import java.util.Properties;
+
+import javax.transaction.TransactionManager;
+
 import org.hibernate.cache.CacheDataDescription;
 import org.hibernate.cache.TransactionalDataRegion;
 import org.infinispan.Cache;
@@ -13,8 +17,8 @@
 
    private final CacheDataDescription metadata;
 
-   public BaseTransactionalDataRegion(Cache<Object, Object> cache, String name, CacheDataDescription metadata) {
-      super(cache, name);
+   public BaseTransactionalDataRegion(Cache<Object, Object> cache, String name, CacheDataDescription metadata, TransactionManager transactionManager) {
+      super(cache, name, transactionManager);
       this.metadata = metadata;
    }
 
@@ -23,7 +27,7 @@
    }
 
    public boolean isTransactionAware() {
-      return true;
+      return transactionManager != null;
    }
 
 }
\ No newline at end of file

Modified: core/branches/INFINISPAN/cache-infinispan/src/main/java/org/hibernate/cache/infinispan/query/InfinispanQueryResultsRegion.java
===================================================================
--- core/branches/INFINISPAN/cache-infinispan/src/main/java/org/hibernate/cache/infinispan/query/InfinispanQueryResultsRegion.java	2009-08-18 17:23:57 UTC (rev 17354)
+++ core/branches/INFINISPAN/cache-infinispan/src/main/java/org/hibernate/cache/infinispan/query/InfinispanQueryResultsRegion.java	2009-08-18 19:48:57 UTC (rev 17355)
@@ -1,16 +1,85 @@
 package org.hibernate.cache.infinispan.query;
 
+import java.util.Properties;
+
+import javax.transaction.TransactionManager;
+
+import org.hibernate.cache.CacheDataDescription;
+import org.hibernate.cache.CacheException;
 import org.hibernate.cache.QueryResultsRegion;
 import org.hibernate.cache.infinispan.impl.BaseGeneralDataRegion;
+import org.hibernate.cache.infinispan.impl.BaseTransactionalDataRegion;
+import org.hibernate.cache.infinispan.util.CacheHelper;
+import org.hibernate.util.PropertiesHelper;
 import org.infinispan.Cache;
+import org.infinispan.context.Flag;
 
 /**
  * @author Chris Bredesen
  */
-public class InfinispanQueryResultsRegion extends BaseGeneralDataRegion implements QueryResultsRegion {
+public class InfinispanQueryResultsRegion extends BaseTransactionalDataRegion implements QueryResultsRegion {
+   public static final String QUERY_CACHE_LOCAL_ONLY_PROP = "hibernate.cache.infinispan.query.localonly";
 
-   public InfinispanQueryResultsRegion(Cache<Object, Object> cache, String name) {
-      super(cache, name);
+   private boolean localOnly;
+
+   public InfinispanQueryResultsRegion(Cache<Object, Object> cache, String name, Properties properties, TransactionManager transactionManager) {
+      super(cache, name, null, transactionManager);
+      
+      // If JBC is using INVALIDATION, we don't want to propagate changes.
+      // We use the Timestamps cache to manage invalidation
+      localOnly = CacheHelper.isClusteredInvalidation(cache);
+      if (!localOnly) {
+          // We don't want to waste effort setting an option if JBC is
+          // already in LOCAL mode. If JBC is REPL_(A)SYNC then check
+          // if they passed an config option to disable query replication
+          localOnly = CacheHelper.isClusteredReplication(cache)
+                  && PropertiesHelper.getBoolean(QUERY_CACHE_LOCAL_ONLY_PROP, properties, false);
+      }
    }
 
+   public void evict(Object key) throws CacheException {
+      if (localOnly)
+         CacheHelper.removeKey(getCache(), key, Flag.CACHE_MODE_LOCAL);
+      else 
+         CacheHelper.removeKey(getCache(), key);
+   }
+
+   public void evictAll() throws CacheException {
+      if (localOnly)
+         CacheHelper.removeAll(getCache(), Flag.CACHE_MODE_LOCAL);
+      else 
+         CacheHelper.removeAll(getCache());
+   }
+
+   public Object get(Object key) throws CacheException {
+      // Don't hold the JBC node lock throughout the tx, as that
+      // prevents updates
+      // Add a zero (or low) timeout option so we don't block
+      // waiting for tx's that did a put to commit
+      return suspendAndGet(key, Flag.ZERO_LOCK_ACQUISITION_TIMEOUT, true);
+   }
+
+   public void put(Object key, Object value) throws CacheException {
+      // Here we don't want to suspend the tx. If we do:
+      // 1) We might be caching query results that reflect uncommitted
+      // changes. No tx == no WL on cache node, so other threads
+      // can prematurely see those query results
+      // 2) No tx == immediate replication. More overhead, plus we
+      // spread issue #1 above around the cluster
+
+      // Add a zero (or quite low) timeout option so we don't block.
+      // Ignore any TimeoutException. Basically we forego caching the
+      // query result in order to avoid blocking.
+      // Reads are done with suspended tx, so they should not hold the
+      // lock for long.  Not caching the query result is OK, since
+      // any subsequent read will just see the old result with its
+      // out-of-date timestamp; that result will be discarded and the
+      // db query performed again.
+      if (localOnly)
+         CacheHelper.putAllowingTimeout(getCache(), key, value, Flag.ZERO_LOCK_ACQUISITION_TIMEOUT, Flag.CACHE_MODE_LOCAL);
+      else 
+         CacheHelper.putAllowingTimeout(getCache(), key, value, Flag.ZERO_LOCK_ACQUISITION_TIMEOUT);
+      
+   }
+
 }
\ No newline at end of file

Modified: core/branches/INFINISPAN/cache-infinispan/src/main/java/org/hibernate/cache/infinispan/timestamp/InfinispanTimestampsRegion.java
===================================================================
--- core/branches/INFINISPAN/cache-infinispan/src/main/java/org/hibernate/cache/infinispan/timestamp/InfinispanTimestampsRegion.java	2009-08-18 17:23:57 UTC (rev 17354)
+++ core/branches/INFINISPAN/cache-infinispan/src/main/java/org/hibernate/cache/infinispan/timestamp/InfinispanTimestampsRegion.java	2009-08-18 19:48:57 UTC (rev 17355)
@@ -1,16 +1,120 @@
 package org.hibernate.cache.infinispan.timestamp;
 
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+
+import javax.transaction.Transaction;
+import javax.transaction.TransactionManager;
+
+import org.hibernate.cache.CacheException;
 import org.hibernate.cache.TimestampsRegion;
 import org.hibernate.cache.infinispan.impl.BaseGeneralDataRegion;
+import org.hibernate.cache.infinispan.util.CacheHelper;
 import org.infinispan.Cache;
+import org.infinispan.context.Flag;
+import org.infinispan.notifications.Listener;
+import org.infinispan.notifications.cachelistener.annotation.CacheEntryModified;
+import org.infinispan.notifications.cachelistener.annotation.CacheEntryRemoved;
+import org.infinispan.notifications.cachelistener.event.CacheEntryModifiedEvent;
+import org.infinispan.notifications.cachelistener.event.CacheEntryRemovedEvent;
 
 /**
+ * Defines the behavior of the timestamps cache region for Infinispan.
+ * 
  * @author Chris Bredesen
+ * @author Galder Zamarreño
  */
+ at Listener
 public class InfinispanTimestampsRegion extends BaseGeneralDataRegion implements TimestampsRegion {
 
-   public InfinispanTimestampsRegion(Cache<Object, Object> cache, String name) {
-      super(cache, name);
+   private Map localCache = new ConcurrentHashMap();
+
+   public InfinispanTimestampsRegion(Cache<Object, Object> cache, String name, TransactionManager transactionManager) {
+      super(cache, name, transactionManager);
+      cache.addListener(this);
+      populateLocalCache();
    }
 
+   @Override
+   public void evict(Object key) throws CacheException {
+      // TODO Is this a valid operation on a timestamps cache?
+      CacheHelper.evict(getCache(), key);
+   }
+
+   public void evictAll() throws CacheException {
+      // TODO Is this a valid operation on a timestamps cache?
+      CacheHelper.removeAll(getCache());
+   }
+
+   public Object get(Object key) throws CacheException {
+      Object value = localCache.get(key);
+      if (value == null) {
+         value = suspendAndGet(key, null, false);
+         if (value != null)
+            localCache.put(key, value);
+      }
+      return value;
+   }
+
+   public void put(Object key, Object value) throws CacheException {
+      // Don't hold the JBC node lock throughout the tx, as that
+      // prevents reads and other updates
+      Transaction tx = suspend();
+      try {
+         // We ensure ASYNC semantics (JBCACHE-1175)
+         CacheHelper.put(getCache(), key, value, Flag.FORCE_ASYNCHRONOUS);
+      } catch (Exception e) {
+         throw new CacheException(e);
+      } finally {
+         resume(tx);
+      }
+   }
+
+   @Override
+   public void destroy() throws CacheException {
+      localCache.clear();
+      getCache().removeListener(this);
+      super.destroy();
+   }
+
+   /**
+    * Monitors cache events and updates the local cache
+    * 
+    * @param event
+    */
+   @CacheEntryModified
+   public void nodeModified(CacheEntryModifiedEvent event) {
+      if (event.isPre()) return;
+      localCache.put(event.getKey(), event.getValue());
+   }
+
+   /**
+    * Monitors cache events and updates the local cache
+    * 
+    * @param event
+    */
+   @CacheEntryRemoved
+   public void nodeRemoved(CacheEntryRemovedEvent event) {
+      if (event.isPre()) return;
+      localCache.remove(event.getKey());
+//      Fqn fqn = event.getFqn();
+//      Fqn regFqn = getRegionFqn();
+//      if (fqn.size() == regFqn.size() + 1 && fqn.isChildOf(regFqn)) {
+//         Object key = fqn.get(regFqn.size());
+//         localCache.remove(key);
+//      } else if (fqn.equals(regFqn)) {
+//         localCache.clear();
+//      }
+   }
+
+   /**
+    * Brings all data from the distributed cache into our local cache.
+    */
+   private void populateLocalCache() {
+      Set children = CacheHelper.getKeySet(getCache());
+      for (Object key : children)
+         get(key);
+   }
+
 }
\ No newline at end of file

Copied: core/branches/INFINISPAN/cache-infinispan/src/main/java/org/hibernate/cache/infinispan/timestamp/TimestampTypeOverrides.java (from rev 17297, core/branches/INFINISPAN/cache-infinispan/src/main/java/org/hibernate/cache/infinispan/TimestampTypeOverrides.java)
===================================================================
--- core/branches/INFINISPAN/cache-infinispan/src/main/java/org/hibernate/cache/infinispan/timestamp/TimestampTypeOverrides.java	                        (rev 0)
+++ core/branches/INFINISPAN/cache-infinispan/src/main/java/org/hibernate/cache/infinispan/timestamp/TimestampTypeOverrides.java	2009-08-18 19:48:57 UTC (rev 17355)
@@ -0,0 +1,48 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2009, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.hibernate.cache.infinispan.timestamp;
+
+import org.hibernate.cache.CacheException;
+import org.hibernate.cache.infinispan.TypeOverrides;
+import org.infinispan.config.Configuration;
+import org.infinispan.config.Configuration.CacheMode;
+import org.infinispan.eviction.EvictionStrategy;
+
+/**
+ * TimestampTypeOverrides.
+ * 
+ * @author Galder Zamarreño
+ * @since 4.0
+ */
+public class TimestampTypeOverrides extends TypeOverrides {
+   @Override
+   public void validateInfinispanConfiguration(Configuration configuration) throws CacheException {
+      CacheMode cacheMode = configuration.getCacheMode();
+      if (cacheMode.equals(CacheMode.INVALIDATION_ASYNC) || cacheMode.equals(CacheMode.INVALIDATION_SYNC)) {
+         throw new CacheException("Timestamp cache cannot be configured with invalidation");
+      }
+      EvictionStrategy strategy = configuration.getEvictionStrategy();
+      if (!strategy.equals(EvictionStrategy.NONE)) {
+         throw new CacheException("Timestamp cache cannot be configured with eviction");
+      }
+   }
+}

Added: core/branches/INFINISPAN/cache-infinispan/src/main/java/org/hibernate/cache/infinispan/tm/HibernateTransactionManagerLookup.java
===================================================================
--- core/branches/INFINISPAN/cache-infinispan/src/main/java/org/hibernate/cache/infinispan/tm/HibernateTransactionManagerLookup.java	                        (rev 0)
+++ core/branches/INFINISPAN/cache-infinispan/src/main/java/org/hibernate/cache/infinispan/tm/HibernateTransactionManagerLookup.java	2009-08-18 19:48:57 UTC (rev 17355)
@@ -0,0 +1,54 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2009, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.hibernate.cache.infinispan.tm;
+
+import java.util.Properties;
+
+import javax.transaction.TransactionManager;
+
+import org.hibernate.cfg.Settings;
+import org.hibernate.transaction.TransactionManagerLookup;
+
+/**
+ * HibernateTransactionManagerLookup.
+ * 
+ * @author Galder Zamarreño
+ * @since 4.0
+ */
+public class HibernateTransactionManagerLookup implements org.infinispan.transaction.lookup.TransactionManagerLookup {
+   private final TransactionManagerLookup hibernateLookup;
+   
+   private final Properties properties;
+   
+   public HibernateTransactionManagerLookup(Settings settings, Properties properties) {
+      if (settings != null)
+         this.hibernateLookup = settings.getTransactionManagerLookup();
+      else
+         this.hibernateLookup = null;
+      this.properties = properties;
+   }
+   
+   public TransactionManager getTransactionManager() throws Exception {
+      return hibernateLookup == null ? null : hibernateLookup.getTransactionManager(properties);
+   }
+   
+}

Added: core/branches/INFINISPAN/cache-infinispan/src/main/java/org/hibernate/cache/infinispan/util/CacheHelper.java
===================================================================
--- core/branches/INFINISPAN/cache-infinispan/src/main/java/org/hibernate/cache/infinispan/util/CacheHelper.java	                        (rev 0)
+++ core/branches/INFINISPAN/cache-infinispan/src/main/java/org/hibernate/cache/infinispan/util/CacheHelper.java	2009-08-18 19:48:57 UTC (rev 17355)
@@ -0,0 +1,439 @@
+/*
+ * 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.cache.infinispan.util;
+
+import java.util.Set;
+
+import org.hibernate.cache.CacheException;
+import org.infinispan.Cache;
+import org.infinispan.config.Configuration;
+import org.infinispan.context.Flag;
+import org.infinispan.util.concurrent.TimeoutException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Helper for dealing with Infinisan cache instances.
+ * 
+ * @author Steve Ebersole
+ * @author Brian Stansberry
+ * @author Galder Zamarreño
+ */
+public class CacheHelper {
+
+   /** Key under which items are cached */
+   public static final String ITEM = "item";
+   /** Key and value used in a hack to create region root nodes */
+   public static final String DUMMY = "dummy";
+
+   private static final Logger log = LoggerFactory.getLogger(CacheHelper.class);
+
+   /**
+    * Disallow external instantiation of CacheHelper.
+    */
+   private CacheHelper() {
+   }
+
+   /**
+    * Is this cache participating in a cluster with invalidation?
+    * 
+    * @param cache
+    *           The cache to check.
+    * @return True if the cache is configured for synchronous/asynchronous invalidation; false
+    *         otherwise.
+    */
+   public static boolean isClusteredInvalidation(Cache cache) {
+      return isClusteredInvalidation(cache.getConfiguration().getCacheMode());
+   }
+
+   /**
+    * Does this cache mode indicate clustered invalidation?
+    * 
+    * @param cacheMode
+    *           The cache to check
+    * @return True if the cache mode is confiogured for synchronous/asynchronous invalidation; false
+    *         otherwise.
+    */
+   public static boolean isClusteredInvalidation(Configuration.CacheMode cacheMode) {
+      return cacheMode == Configuration.CacheMode.INVALIDATION_ASYNC
+               || cacheMode == Configuration.CacheMode.INVALIDATION_SYNC;
+   }
+
+   /**
+    * Is this cache participating in a cluster with replication?
+    * 
+    * @param cache
+    *           The cache to check.
+    * @return True if the cache is configured for synchronous/asynchronous invalidation; false
+    *         otherwise.
+    */
+   public static boolean isClusteredReplication(Cache cache) {
+      return isClusteredReplication(cache.getConfiguration().getCacheMode());
+   }
+
+   /**
+    * Does this cache mode indicate clustered replication?
+    * 
+    * @param cacheMode
+    *           The cache to check
+    * @return True if the cache mode is confiogured for synchronous/asynchronous invalidation; false
+    *         otherwise.
+    */
+   public static boolean isClusteredReplication(Configuration.CacheMode cacheMode) {
+      return cacheMode == Configuration.CacheMode.REPL_ASYNC || cacheMode == Configuration.CacheMode.REPL_SYNC;
+   }
+
+   public static boolean isSynchronous(Cache cache) {
+      return isSynchronous(cache.getConfiguration().getCacheMode());
+   }
+
+   public static boolean isSynchronous(Configuration.CacheMode cacheMode) {
+      return cacheMode == Configuration.CacheMode.REPL_SYNC || cacheMode == Configuration.CacheMode.INVALIDATION_SYNC;
+   }
+
+   public static Set getKeySet(Cache cache) {
+      return cache.keySet();
+   }
+
+   /**
+    * Builds an {@link Fqn} from <code>region</code> and <code>key</code> and performs a JBoss Cache
+    * <code>get(Fqn, Object)</code>, wrapping any exception in a {@link CacheException}.
+    * 
+    * @param cache
+    *           the cache to invoke on
+    * @param region
+    *           base Fqn for the cache region
+    * @param key
+    *           specific key to append to the <code>region</code> to form the full Fqn
+    */
+   public static Object get(Cache cache, Object key) throws CacheException {
+      try {
+         return cache.get(key);
+      } catch (Exception e) {
+         throw new CacheException(e);
+      }
+   }
+
+   /**
+    * Builds an {@link Fqn} from <code>region</code> and <code>key</code> and performs a JBoss Cache
+    * <code>get(Fqn, Object)</code>, wrapping any exception in a {@link CacheException}.
+    * 
+    * @param cache
+    *           the cache to invoke on
+    * @param key
+    *           specific key to append to the <code>region</code> to form the full Fqn
+    */
+   public static Object getAllowingTimeout(Cache cache, Object key) throws CacheException {
+      try {
+         return cache.get(key);
+      } catch (TimeoutException ignored) {
+         // ignore it
+         return null;
+      } catch (Exception e) {
+         throw new CacheException(e);
+      }
+   }
+
+   /**
+    * Builds an {@link Fqn} from <code>region</code> and <code>key</code> and performs a JBoss Cache
+    * <code>put(Object, Object)</code>, wrapping any exception in a {@link CacheException}.
+    * 
+    * @param cache
+    *           the cache to invoke on
+    * @param region
+    *           base Fqn for the cache region
+    * @param key
+    *           specific key to append to the <code>region</code> to form the full Fqn
+    * @param value
+    *           data to store in the cache node
+    */
+   public static void put(Cache cache, Object key, Object value) throws CacheException {
+      put(cache, key, value, null);
+   }
+
+   /**
+    * Builds an {@link Fqn} from <code>region</code> and <code>key</code> and performs a JBoss Cache
+    * <code>put(Object, Object)</code>, wrapping any exception in a {@link CacheException}.
+    * 
+    * @param cache
+    *           the cache to invoke on
+    * @param region
+    *           base Fqn for the cache region
+    * @param key
+    *           specific key to append to the <code>region</code> to form the full Fqn
+    * @param value
+    *           data to store in the cache node
+    * @param option
+    *           invocation Option to set for this invocation. May be <code>null</code>.
+    */
+   public static void put(Cache cache, Object key, Object value, Flag option) throws CacheException {
+      try {
+         cache.getAdvancedCache().put(key, value, option);
+      } catch (Exception e) {
+         throw new CacheException(e);
+      }
+   }
+
+   /**
+    * Builds an {@link Fqn} from <code>region</code> and <code>key</code> and performs a JBoss Cache
+    * <code>put(Object, Object)</code>, ignoring any {@link TimeoutException} and wrapping any other
+    * exception in a {@link CacheException}.
+    * 
+    * @param cache
+    *           the cache to invoke on
+    * @param region
+    *           base Fqn for the cache region
+    * @param key
+    *           specific key to append to the <code>region</code> to form the full Fqn
+    * @param value
+    *           data to store in the cache node
+    * @param option
+    *           invocation Option to set for this invocation. May be <code>null</code>.
+    */
+   public static void putAllowingTimeout(Cache cache, Object key, Object value, Flag... option) throws CacheException {
+      try {
+         cache.getAdvancedCache().put(key, value, option);
+      } catch (TimeoutException allowed) {
+         // ignore it
+      } catch (Exception e) {
+         throw new CacheException(e);
+      }
+   }
+
+   /**
+    * Builds an {@link Fqn} from <code>region</code> and <code>key</code> and performs a JBoss Cache
+    * <code>putForExternalRead(Object, Object)</code>, wrapping any exception in a
+    * {@link CacheException}. Ignores any JBoss Cache {@link TimeoutException}.
+    * 
+    * @param cache
+    *           the cache to invoke on
+    * @param region
+    *           base Fqn for the cache region
+    * @param key
+    *           specific key to append to the <code>region</code> to form the full Fqn
+    * @param value
+    *           data to store in the cache node
+    */
+   public static boolean putForExternalRead(Cache cache, Object key, Object value) throws CacheException {
+      return putForExternalRead(cache, key, value, null);
+   }
+
+   /**
+    * Builds an {@link Fqn} from <code>region</code> and <code>key</code> and performs a JBoss Cache
+    * <code>putForExternalRead(Object, Object)</code>, wrapping any exception in a
+    * {@link CacheException}. Ignores any JBoss Cache {@link TimeoutException}.
+    * 
+    * @param cache
+    *           the cache to invoke on
+    * @param region
+    *           base Fqn for the cache region
+    * @param key
+    *           specific key to append to the <code>region</code> to form the full Fqn
+    * @param value
+    *           data to store in the cache node
+    * @param option
+    *           invocation Option to set for this invocation. May be <code>null</code>.
+    */
+   public static boolean putForExternalRead(Cache cache, Object key, Object value, Flag... option) throws CacheException {
+      try {
+         cache.getAdvancedCache().putForExternalRead(key, value, option);
+         return true;
+      } catch (TimeoutException te) {
+         // ignore!
+         log.debug("ignoring write lock acquisition failure");
+         return false;
+      } catch (Throwable t) {
+         throw new CacheException(t);
+      }
+   }
+
+   /**
+    * Builds an {@link Fqn} from <code>region</code> and <code>key</code> and performs a JBoss Cache
+    * <code>removeNode(Fqn)</code>, wrapping any exception in a {@link CacheException}.
+    * 
+    * @param cache
+    *           the cache to invoke on
+    * @param region
+    *           base Fqn for the cache region
+    * @param key
+    *           specific key to append to the <code>region</code> to form the full Fqn
+    */
+   public static void remove(Cache cache, Object key) throws CacheException {
+      remove(cache, key, null);
+   }
+
+   /**
+    * Builds an {@link Fqn} from <code>region</code> and <code>key</code> and performs a JBoss Cache
+    * <code>removeNode(Fqn)</code>, wrapping any exception in a {@link CacheException}.
+    * 
+    * @param cache
+    *           the cache to invoke on
+    * @param region
+    *           base Fqn for the cache region
+    * @param key
+    *           specific key to append to the <code>region</code> to form the full Fqn
+    * @param option
+    *           invocation Option to set for this invocation. May be <code>null</code>.
+    */
+   public static void remove(Cache cache, Object key, Flag option) throws CacheException {
+      try {
+         cache.getAdvancedCache().remove(key, option);
+      } catch (Exception e) {
+         throw new CacheException(e);
+      }
+   }
+
+   /**
+    * Performs a JBoss Cache <code>removeNode(Fqn)</code>, wrapping any exception in a
+    * {@link CacheException}.
+    * 
+    * @param cache
+    *           the cache to invoke on
+    * @param region
+    *           base Fqn for the cache region
+    */
+   public static void removeAll(Cache cache) throws CacheException {
+      try {
+         cache.clear();
+      } catch (Exception e) {
+         throw new CacheException(e);
+      }
+   }
+
+   /**
+    * Performs a JBoss Cache <code>removeNode(Fqn)</code>, wrapping any exception in a
+    * {@link CacheException}.
+    * 
+    * @param cache
+    *           the cache to invoke on
+    * @param region
+    *           base Fqn for the cache region
+    * @param option
+    *           invocation Option to set for this invocation. May be <code>null</code>.
+    */
+   public static void removeAll(Cache cache, Flag option) throws CacheException {
+      try {
+         cache.getAdvancedCache().clear(option);
+      } catch (Exception e) {
+         throw new CacheException(e);
+      }
+   }
+
+   /**
+    * Performs a JBoss Cache <code>removeNode(Fqn)</code>, wrapping any exception in a
+    * {@link CacheException}.
+    * 
+    * @param cache
+    *           the cache to invoke on
+    * @param region
+    *           base Fqn for the cache region
+    * @param option
+    *           invocation Option to set for this invocation. May be <code>null</code>.
+    */
+   public static void removeKey(Cache cache, Object key, Flag option) throws CacheException {
+      try {
+         cache.getAdvancedCache().remove(key, option);
+      } catch (Exception e) {
+         throw new CacheException(e);
+      }
+   }
+   
+   public static void removeKey(Cache cache, Object key) throws CacheException {
+      try {
+         cache.remove(key);
+      } catch (Exception e) {
+         throw new CacheException(e);
+      }
+   }
+   
+   public static void evict(Cache cache, Object key) throws CacheException {
+      try {
+         cache.evict(key);
+      } catch (Exception e) {
+         throw new CacheException(e);
+      }
+   }
+   
+
+//   public static Node addNode(Cache cache, Fqn fqn, boolean localOnly, boolean resident) throws CacheException {
+//      try {
+//         Option option = null;
+//         if (localOnly) {
+//            option = new Option();
+//            option.setCacheModeLocal(localOnly);
+//         }
+//
+//         Node root = cache.getRoot();
+//         setInvocationOption(cache, option);
+//         // FIXME hack to work around fact that calling
+//         // Node added = root.addChild( fqn ); doesn't
+//         // properly set the version on the node
+//         Node added = null;
+//         if (version == null) {
+//            added = root.addChild(fqn);
+//         } else {
+//            cache.put(fqn, DUMMY, DUMMY);
+//            added = root.getChild(fqn);
+//         }
+//         if (resident)
+//            added.setResident(true);
+//         return added;
+//      } catch (Exception e) {
+//         throw new CacheException(e);
+//      }
+//   }
+
+   /**
+//    * Assigns the given Option to the cache's {@link InvocationContext}. Does nothing if
+//    * <code>option</code> is <code>null</code>.
+//    * 
+//    * @param cache
+//    *           the cache. Cannot be <code>null</code>.
+//    * @param option
+//    *           the option. May be <code>null</code>.
+//    * 
+//    * @see {@link Cache#getInvocationContext()}
+//    * @see {@link InvocationContext#setOptionOverrides(Option)}
+//    */
+//   public static void setInvocationOption(Cache cache, Option option) {
+//      if (option != null) {
+//         cache.getInvocationContext().setOptionOverrides(option);
+//      }
+//   }
+
+//   /**
+//    * Creates an {@link Option} using the given {@link DataVersion} and passes it to
+//    * {@link #setInvocationOption(Cache, Option)}.
+//    * 
+//    * @param cache
+//    *           the cache to set the Option on. Cannot be <code>null</code>.
+//    * @param version
+//    *           the DataVersion to set. Cannot be <code>null</code>.
+//    */
+//   public static void setDataVersionOption(Cache cache, DataVersion version) {
+//      Option option = new Option();
+//      option.setDataVersion(version);
+//      setInvocationOption(cache, option);
+//   }
+}

Added: core/branches/INFINISPAN/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/AbstractGeneralDataRegionTestCase.java
===================================================================
--- core/branches/INFINISPAN/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/AbstractGeneralDataRegionTestCase.java	                        (rev 0)
+++ core/branches/INFINISPAN/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/AbstractGeneralDataRegionTestCase.java	2009-08-18 19:48:57 UTC (rev 17355)
@@ -0,0 +1,194 @@
+/*
+ * 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;
+
+import java.util.Iterator;
+import java.util.Set;
+
+import org.hibernate.cache.CacheException;
+import org.hibernate.cache.GeneralDataRegion;
+import org.hibernate.cache.QueryResultsRegion;
+import org.hibernate.cache.Region;
+import org.hibernate.cache.infinispan.InfinispanRegionFactory;
+import org.hibernate.cache.infinispan.util.CacheHelper;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.test.cache.infinispan.util.CacheTestUtil;
+import org.infinispan.Cache;
+import org.infinispan.transaction.tm.BatchModeTransactionManager;
+
+/**
+ * Base class for tests of QueryResultsRegion and TimestampsRegion.
+ * 
+ * @author <a href="brian.stansberry at jboss.com">Brian Stansberry</a>
+ * @version $Revision: 1 $
+ */
+public abstract class AbstractGeneralDataRegionTestCase extends AbstractRegionImplTestCase {
+   protected static final String KEY = "Key";
+
+   protected static final String VALUE1 = "value1";
+   protected static final String VALUE2 = "value2";
+
+   public AbstractGeneralDataRegionTestCase(String name) {
+      super(name);
+   }
+
+   @Override
+   protected void putInRegion(Region region, Object key, Object value) {
+      ((GeneralDataRegion) region).put(key, value);
+   }
+
+   @Override
+   protected void removeFromRegion(Region region, Object key) {
+      ((GeneralDataRegion) region).evict(key);
+   }
+
+   /**
+    * Test method for {@link QueryResultsRegion#evict(java.lang.Object)}.
+    * 
+    * FIXME add testing of the "immediately without regard for transaction isolation" bit in the
+    * CollectionRegionAccessStrategy API.
+    */
+   public void testEvict() throws Exception {
+      evictOrRemoveTest();
+   }
+
+   private void evictOrRemoveTest() throws Exception {
+      Configuration cfg = createConfiguration();
+      InfinispanRegionFactory regionFactory = CacheTestUtil.startRegionFactory(cfg, getCacheTestSupport());
+      Cache localCache = getInfinispanCache(regionFactory);
+      boolean invalidation = CacheHelper.isClusteredInvalidation(localCache);
+
+      // Sleep a bit to avoid concurrent FLUSH problem
+      avoidConcurrentFlush();
+
+      GeneralDataRegion localRegion = (GeneralDataRegion) createRegion(regionFactory,
+               getStandardRegionName(REGION_PREFIX), cfg.getProperties(), null);
+
+      cfg = createConfiguration();
+      regionFactory = CacheTestUtil.startRegionFactory(cfg, getCacheTestSupport());
+
+      GeneralDataRegion remoteRegion = (GeneralDataRegion) createRegion(regionFactory,
+               getStandardRegionName(REGION_PREFIX), cfg.getProperties(), null);
+
+      assertNull("local is clean", localRegion.get(KEY));
+      assertNull("remote is clean", remoteRegion.get(KEY));
+
+      localRegion.put(KEY, VALUE1);
+      assertEquals(VALUE1, localRegion.get(KEY));
+
+      // allow async propagation
+      sleep(250);
+      Object expected = invalidation ? null : VALUE1;
+      assertEquals(expected, remoteRegion.get(KEY));
+
+      localRegion.evict(KEY);
+
+      assertEquals(null, localRegion.get(KEY));
+
+      assertEquals(null, remoteRegion.get(KEY));
+   }
+
+   protected abstract String getStandardRegionName(String regionPrefix);
+
+   /**
+    * Test method for {@link QueryResultsRegion#evictAll()}.
+    * 
+    * FIXME add testing of the "immediately without regard for transaction isolation" bit in the
+    * CollectionRegionAccessStrategy API.
+    */
+   public void testEvictAll() throws Exception {
+      evictOrRemoveAllTest("entity");
+   }
+
+   private void evictOrRemoveAllTest(String configName) throws Exception {
+      Configuration cfg = createConfiguration();
+      InfinispanRegionFactory regionFactory = CacheTestUtil.startRegionFactory(cfg, getCacheTestSupport());
+      Cache localCache = getInfinispanCache(regionFactory);
+      boolean invalidation = CacheHelper.isClusteredInvalidation(localCache);
+
+      // Sleep a bit to avoid concurrent FLUSH problem
+      avoidConcurrentFlush();
+
+      GeneralDataRegion localRegion = (GeneralDataRegion) createRegion(regionFactory,
+               getStandardRegionName(REGION_PREFIX), cfg.getProperties(), null);
+
+      cfg = createConfiguration();
+      regionFactory = CacheTestUtil.startRegionFactory(cfg, getCacheTestSupport());
+      Cache remoteCache = getInfinispanCache(regionFactory);
+
+      // Sleep a bit to avoid concurrent FLUSH problem
+      avoidConcurrentFlush();
+
+      GeneralDataRegion remoteRegion = (GeneralDataRegion) createRegion(regionFactory,
+               getStandardRegionName(REGION_PREFIX), cfg.getProperties(), null);
+      String regionName = REGION_PREFIX;
+
+      Set children = CacheHelper.getKeySet(localCache);
+      assertEquals("No children in " + children, 0, children.size());
+
+      children = CacheHelper.getKeySet(remoteCache);
+      assertEquals("No children in " + children, 0, children.size());
+
+      assertNull("local is clean", localRegion.get(KEY));
+      assertNull("remote is clean", remoteRegion.get(KEY));
+
+      localRegion.put(KEY, VALUE1);
+      assertEquals(VALUE1, localRegion.get(KEY));
+
+      // Allow async propagation
+      sleep(250);
+
+      remoteRegion.put(KEY, VALUE1);
+      assertEquals(VALUE1, remoteRegion.get(KEY));
+
+      // Allow async propagation
+      sleep(250);
+
+      localRegion.evictAll();
+
+      // This should re-establish the region root node in the optimistic case
+      assertNull(localRegion.get(KEY));
+
+      // Re-establishing the region root on the local node doesn't
+      // propagate it to other nodes. Do a get on the remote node to re-establish
+      // This only adds a node in the case of optimistic locking
+      assertEquals(null, remoteRegion.get(KEY));
+
+      assertEquals("local is clean", null, localRegion.get(KEY));
+      assertEquals("remote is clean", null, remoteRegion.get(KEY));
+   }
+
+   protected Configuration createConfiguration() {
+      Configuration cfg = CacheTestUtil.buildConfiguration("test", InfinispanRegionFactory.class, false, true);
+      return cfg;
+   }
+
+   protected void rollback() {
+      try {
+         BatchModeTransactionManager.getInstance().rollback();
+      } catch (Exception e) {
+         log.error(e.getMessage(), e);
+      }
+   }
+}
\ No newline at end of file

Added: core/branches/INFINISPAN/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/AbstractNonFunctionalTestCase.java
===================================================================
--- core/branches/INFINISPAN/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/AbstractNonFunctionalTestCase.java	                        (rev 0)
+++ core/branches/INFINISPAN/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/AbstractNonFunctionalTestCase.java	2009-08-18 19:48:57 UTC (rev 17355)
@@ -0,0 +1,97 @@
+/*
+ * 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;
+
+import org.hibernate.cache.RegionFactory;
+import org.hibernate.junit.UnitTestCase;
+import org.hibernate.test.cache.infinispan.util.CacheTestSupport;
+import org.infinispan.Cache;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Base class for all non-functional tests of Infinispan integration.
+ * 
+ * @author <a href="brian.stansberry at jboss.com">Brian Stansberry</a>
+ * @version $Revision: 1 $
+ */
+public abstract class AbstractNonFunctionalTestCase extends UnitTestCase {
+
+    public static final String REGION_PREFIX = "test";
+    
+    private CacheTestSupport testSupport;
+    protected final Logger log = LoggerFactory.getLogger(getClass());
+    
+    public AbstractNonFunctionalTestCase(String name) {
+        super(name);
+        testSupport = new CacheTestSupport(log);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        
+        testSupport.setUp();
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        super.tearDown();
+        
+        testSupport.tearDown();
+    }
+
+    protected void registerCache(Cache cache) {
+        testSupport.registerCache(cache);
+    }
+
+    protected void unregisterCache(Cache cache) {
+        testSupport.unregisterCache(cache);
+    }
+
+    protected void registerFactory(RegionFactory factory) {
+        testSupport.registerFactory(factory);
+    }
+
+    protected void unregisterFactory(RegionFactory factory) {
+        testSupport.unregisterFactory(factory);
+    }
+
+    protected CacheTestSupport getCacheTestSupport() {
+        return testSupport;
+    }
+    
+    protected void sleep(long ms) {
+        try {
+            Thread.sleep(ms);
+        }
+        catch (InterruptedException e) {
+            log.warn("Interrupted during sleep", e);
+        }
+    }
+    
+    protected void avoidConcurrentFlush() {
+        testSupport.avoidConcurrentFlush();
+    }
+}
\ No newline at end of file

Added: core/branches/INFINISPAN/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/AbstractRegionImplTestCase.java
===================================================================
--- core/branches/INFINISPAN/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/AbstractRegionImplTestCase.java	                        (rev 0)
+++ core/branches/INFINISPAN/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/AbstractRegionImplTestCase.java	2009-08-18 19:48:57 UTC (rev 17355)
@@ -0,0 +1,64 @@
+/*
+ * 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;
+
+import java.util.Map;
+import java.util.Properties;
+
+import org.hibernate.cache.CacheDataDescription;
+import org.hibernate.cache.Region;
+import org.hibernate.cache.impl.CacheDataDescriptionImpl;
+import org.hibernate.cache.infinispan.InfinispanRegionFactory;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.test.cache.infinispan.util.CacheTestUtil;
+import org.hibernate.util.ComparableComparator;
+import org.infinispan.Cache;
+import org.infinispan.manager.DefaultCacheManager;
+import org.jgroups.JChannelFactory;
+
+/**
+ * Base class for tests of Region implementations.
+ * 
+ * @author <a href="brian.stansberry at jboss.com">Brian Stansberry</a>
+ * @version $Revision: 1 $
+ */
+public abstract class AbstractRegionImplTestCase extends AbstractNonFunctionalTestCase {
+
+   public AbstractRegionImplTestCase(String name) {
+      super(name);
+   }
+
+   protected abstract Cache getInfinispanCache(InfinispanRegionFactory regionFactory);
+
+   protected abstract Region createRegion(InfinispanRegionFactory regionFactory, String regionName, Properties properties, CacheDataDescription cdd);
+
+   protected abstract void putInRegion(Region region, Object key, Object value);
+
+   protected abstract void removeFromRegion(Region region, Object key);
+
+   protected CacheDataDescription getCacheDataDescription() {
+      return new CacheDataDescriptionImpl(true, true, ComparableComparator.INSTANCE);
+   }
+
+}

Modified: core/branches/INFINISPAN/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/InfinispanRegionFactoryTestCase.java
===================================================================
--- core/branches/INFINISPAN/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/InfinispanRegionFactoryTestCase.java	2009-08-18 17:23:57 UTC (rev 17354)
+++ core/branches/INFINISPAN/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/InfinispanRegionFactoryTestCase.java	2009-08-18 19:48:57 UTC (rev 17355)
@@ -287,8 +287,6 @@
          fail("Should have failed saying that invalidation is not allowed for timestamp caches.");
       } catch(CacheException ce) {
       }
-      
-      fail("Add more validations!");
    }
    
    public void testBuildDefaultTimestampsRegion() {
@@ -342,26 +340,62 @@
       }
    }
    
-   public void testBuildTimestamRegionWithOverrides() {
+   public void testBuildTimestamRegionWithCacheNameOverride() {
       final String timestamps = "org.hibernate.cache.UpdateTimestampsCache";
       Properties p = new Properties();
       InfinispanRegionFactory factory = new InfinispanRegionFactory();
       p.setProperty("hibernate.cache.infinispan.timestamps.cfg", "mytimestamps-cache");
-      p.setProperty("hibernate.cache.infinispan.entity.eviction.strategy", "FIFO");
-      p.setProperty("hibernate.cache.infinispan.entity.eviction.wake_up_interval", "3000");
-      p.setProperty("hibernate.cache.infinispan.entity.eviction.max_entries", "10000");
       factory.start(null, p);
       CacheManager manager = factory.getCacheManager();
       manager.getGlobalConfiguration().setTransportClass(null);
       try {
          InfinispanTimestampsRegion region = (InfinispanTimestampsRegion) factory.buildTimestampsRegion(timestamps, p);
-         assertTrue(factory.getDefinedConfigurations().contains(timestamps));
+         assertTrue(factory.getDefinedConfigurations().contains("mytimestamps-cache"));
+      } finally {
+         factory.stop();
+      }
+   }
+   
+   public void testBuildTimestamRegionWithFifoEvictionOverride() {
+      final String timestamps = "org.hibernate.cache.UpdateTimestampsCache";
+      Properties p = new Properties();
+      InfinispanRegionFactory factory = new InfinispanRegionFactory();
+      p.setProperty("hibernate.cache.infinispan.timestamps.cfg", "mytimestamps-cache");
+      p.setProperty("hibernate.cache.infinispan.timestamps.eviction.strategy", "FIFO");
+      p.setProperty("hibernate.cache.infinispan.timestamps.eviction.wake_up_interval", "3000");
+      p.setProperty("hibernate.cache.infinispan.timestamps.eviction.max_entries", "10000");
+      try {
+         factory.start(null, p);
+         CacheManager manager = factory.getCacheManager();
+         manager.getGlobalConfiguration().setTransportClass(null);
+         InfinispanTimestampsRegion region = (InfinispanTimestampsRegion) factory.buildTimestampsRegion(timestamps, p);
+         assertTrue(factory.getDefinedConfigurations().contains("mytimestamps-cache"));
          fail("Should fail cos no eviction configurations are allowed for timestamp caches");
+      } catch(CacheException ce) {
       } finally {
          factory.stop();
       }
    }
    
+   public void testBuildTimestamRegionWithNoneEvictionOverride() {
+      final String timestamps = "org.hibernate.cache.UpdateTimestampsCache";
+      Properties p = new Properties();
+      InfinispanRegionFactory factory = new InfinispanRegionFactory();
+      p.setProperty("hibernate.cache.infinispan.timestamps.cfg", "timestamps-none-eviction");
+      p.setProperty("hibernate.cache.infinispan.timestamps.eviction.strategy", "NONE");
+      p.setProperty("hibernate.cache.infinispan.timestamps.eviction.wake_up_interval", "3000");
+      p.setProperty("hibernate.cache.infinispan.timestamps.eviction.max_entries", "10000");
+      factory.start(null, p);
+      CacheManager manager = factory.getCacheManager();
+      manager.getGlobalConfiguration().setTransportClass(null);
+      try {
+         InfinispanTimestampsRegion region = (InfinispanTimestampsRegion) factory.buildTimestampsRegion(timestamps, p);
+         assertTrue(factory.getDefinedConfigurations().contains("timestamps-none-eviction"));
+      } finally {
+         factory.stop();
+      }
+   }
+   
    public void testBuildQueryRegion() {
       final String query = "org.hibernate.cache.StandardQueryCache";
       Properties p = new Properties();

Copied: core/branches/INFINISPAN/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/AbstractFunctionalTestCase.java (from rev 17244, core/branches/INFINISPAN/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/AbstractInfinispanTestCase.java)
===================================================================
--- core/branches/INFINISPAN/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/AbstractFunctionalTestCase.java	                        (rev 0)
+++ core/branches/INFINISPAN/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/AbstractFunctionalTestCase.java	2009-08-18 19:48:57 UTC (rev 17355)
@@ -0,0 +1,104 @@
+package org.hibernate.test.cache.infinispan.functional;
+
+import java.util.Map;
+
+import org.hibernate.Session;
+import org.hibernate.junit.functional.FunctionalTestCase;
+import org.hibernate.stat.SecondLevelCacheStatistics;
+import org.hibernate.stat.Statistics;
+
+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 testEntityCache() {
+      Item item = new Item("chris", "Chris's Item");
+
+      Session s = openSession();
+      Statistics stats = s.getSessionFactory().getStatistics();
+      s.getTransaction().begin();
+      s.persist(item);
+      s.getTransaction().commit();
+      s.close();
+
+      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 testQueryCache() {
+      Item item = new Item("chris", "Chris's Item");
+
+      Session s = openSession();
+      s.getTransaction().begin();
+      s.persist(item);
+      s.getTransaction().commit();
+      s.close();
+
+      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();
+   }
+   
+   public void testCollectionCache() {
+      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();
+
+      s = openSession();
+      Statistics stats = s.getSessionFactory().getStatistics();
+      Item loaded = (Item) s.load(Item.class, item.getId());
+      assertEquals(1, loaded.getItems().size());
+      s.close();
+
+      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());
+      s.close();
+   }
+   
+   public void testEmptySecondLevelCacheEntry() throws Exception {
+      getSessions().evictEntity(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

Deleted: core/branches/INFINISPAN/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/AbstractInfinispanTestCase.java
===================================================================
--- core/branches/INFINISPAN/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/AbstractInfinispanTestCase.java	2009-08-18 17:23:57 UTC (rev 17354)
+++ core/branches/INFINISPAN/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/AbstractInfinispanTestCase.java	2009-08-18 19:48:57 UTC (rev 17355)
@@ -1,104 +0,0 @@
-package org.hibernate.test.cache.infinispan.functional;
-
-import java.util.Map;
-
-import org.hibernate.Session;
-import org.hibernate.junit.functional.FunctionalTestCase;
-import org.hibernate.stat.SecondLevelCacheStatistics;
-import org.hibernate.stat.Statistics;
-
-public abstract class AbstractInfinispanTestCase extends FunctionalTestCase {
-   private final String cacheConcurrencyStrategy;
-
-   public AbstractInfinispanTestCase(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 testEntityCache() {
-      Item item = new Item("chris", "Chris's Item");
-
-      Session s = openSession();
-      Statistics stats = s.getSessionFactory().getStatistics();
-      s.getTransaction().begin();
-      s.persist(item);
-      s.getTransaction().commit();
-      s.close();
-
-      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 testQueryCache() {
-      Item item = new Item("chris", "Chris's Item");
-
-      Session s = openSession();
-      s.getTransaction().begin();
-      s.persist(item);
-      s.getTransaction().commit();
-      s.close();
-
-      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();
-   }
-   
-   public void testCollectionCache() {
-      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();
-
-      s = openSession();
-      Statistics stats = s.getSessionFactory().getStatistics();
-      Item loaded = (Item) s.load(Item.class, item.getId());
-      assertEquals(1, loaded.getItems().size());
-      s.close();
-
-      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());
-      s.close();
-   }
-   
-   public void testEmptySecondLevelCacheEntry() throws Exception {
-      getSessions().evictEntity(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/branches/INFINISPAN/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/BasicReadOnlyTestCase.java
===================================================================
--- core/branches/INFINISPAN/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/BasicReadOnlyTestCase.java	2009-08-18 17:23:57 UTC (rev 17354)
+++ core/branches/INFINISPAN/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/BasicReadOnlyTestCase.java	2009-08-18 19:48:57 UTC (rev 17355)
@@ -1,6 +1,6 @@
 package org.hibernate.test.cache.infinispan.functional;
 
-public class BasicReadOnlyTestCase extends AbstractInfinispanTestCase {
+public class BasicReadOnlyTestCase extends AbstractFunctionalTestCase {
 
    public BasicReadOnlyTestCase(String string) {
       super(string, "read-only");

Modified: core/branches/INFINISPAN/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/BasicTransactionalTestCase.java
===================================================================
--- core/branches/INFINISPAN/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/BasicTransactionalTestCase.java	2009-08-18 17:23:57 UTC (rev 17354)
+++ core/branches/INFINISPAN/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/BasicTransactionalTestCase.java	2009-08-18 19:48:57 UTC (rev 17355)
@@ -7,7 +7,7 @@
 import org.hibernate.cache.entry.CacheEntry;
 import org.hibernate.stat.SecondLevelCacheStatistics;
 
-public class BasicTransactionalTestCase extends AbstractInfinispanTestCase {
+public class BasicTransactionalTestCase extends AbstractFunctionalTestCase {
 
    public BasicTransactionalTestCase(String string) {
       super(string, "transactional");

Modified: core/branches/INFINISPAN/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/bulk/BulkOperationsTestCase.java
===================================================================
--- core/branches/INFINISPAN/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/bulk/BulkOperationsTestCase.java	2009-08-18 17:23:57 UTC (rev 17354)
+++ core/branches/INFINISPAN/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/bulk/BulkOperationsTestCase.java	2009-08-18 19:48:57 UTC (rev 17355)
@@ -25,6 +25,8 @@
 import java.util.List;
 import java.util.Set;
 
+import javax.transaction.TransactionManager;
+
 import org.hibernate.FlushMode;
 import org.hibernate.cfg.Configuration;
 import org.hibernate.cfg.Environment;
@@ -34,6 +36,8 @@
 import org.hibernate.test.cache.infinispan.functional.Customer;
 import org.hibernate.test.tm.SimpleJtaTransactionManagerImpl;
 import org.hibernate.transaction.CMTTransactionFactory;
+import org.hibernate.transaction.TransactionManagerLookup;
+import org.hibernate.util.ReflectHelper;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -46,6 +50,8 @@
 public class BulkOperationsTestCase extends FunctionalTestCase {
 
    private static final Logger log = LoggerFactory.getLogger(BulkOperationsTestCase.class);
+   
+   private TransactionManager tm;
             
    public BulkOperationsTestCase(String string) {
       super(string);
@@ -65,11 +71,13 @@
    }
 
    protected Class getConnectionProviderClass() {
-      return org.hibernate.test.tm.ConnectionProviderImpl.class;
+//      return org.hibernate.test.tm.ConnectionProviderImpl.class;
+      return org.hibernate.test.cache.infinispan.tm.XaConnectionProvider.class;
    }
   
-   protected Class getTransactionManagerLookupClass() {
-      return org.hibernate.test.tm.TransactionManagerLookupImpl.class;
+   protected Class<? extends TransactionManagerLookup> getTransactionManagerLookupClass() {
+      return org.hibernate.test.cache.infinispan.tm.XaTransactionManagerLookup.class;
+//      return org.hibernate.test.tm.TransactionManagerLookupImpl.class;
    }
 
    public void configure(Configuration cfg) {
@@ -84,9 +92,12 @@
       cfg.setProperty( Environment.TRANSACTION_STRATEGY, transactionFactory.getName());
    }
 
-   public void testBulkOperations() throws Exception {
+   public void testBulkOperations() throws Throwable {
       System.out.println("*** testBulkOperations()");
+      boolean cleanedUp = false;
       try {
+         tm = getTransactionManagerLookupClass().newInstance().getTransactionManager(null);
+         
          createContacts();
 
          List<Integer> rhContacts = getContactsByCustomer("Red Hat");
@@ -118,21 +129,30 @@
          List<Integer> updated = getContactsByTLF("Updated");
          assertNotNull("Got updated contacts", updated);
          assertEquals("Updated contacts", 5, updated.size());
+      } catch(Throwable t) {
+         cleanedUp = true;
+         log.debug("Exceptional cleanup");
+         cleanup(true);
+         throw t;
       } finally {
          // cleanup the db so we can run this test multiple times w/o restarting the cluster
-         cleanup();
+         if (!cleanedUp) {
+            log.debug("Non exceptional cleanup");
+            cleanup(false);
+         }
       }
    }
 
    public void createContacts() throws Exception {
-      SimpleJtaTransactionManagerImpl.getInstance().begin();
+      log.debug("Create 10 contacts");
+      tm.begin();
       try {
          for (int i = 0; i < 10; i++)
             createCustomer(i);
-         SimpleJtaTransactionManagerImpl.getInstance().commit();
+         tm.commit();
       } catch (Exception e) {
          log.error("Unable to create customer", e);
-         SimpleJtaTransactionManagerImpl.getInstance().rollback();
+         tm.rollback();
          throw e;
       }
    }
@@ -142,16 +162,20 @@
       deleteHQL += " (select customer FROM Customer as customer ";
       deleteHQL += " where customer.name = :cName)";
 
-      SimpleJtaTransactionManagerImpl.getInstance().begin();
+      tm.begin();
       try {
 
          Session session = getSessions().getCurrentSession();
          int rowsAffected = session.createQuery(deleteHQL).setFlushMode(FlushMode.AUTO)
                   .setParameter("cName", "Red Hat").executeUpdate();
-         SimpleJtaTransactionManagerImpl.getInstance().commit();
+         tm.commit();
          return rowsAffected;
       } catch (Exception e) {
-         SimpleJtaTransactionManagerImpl.getInstance().rollback();
+         try {
+            tm.rollback();
+         } catch (Exception ee) {
+            // ignored
+         }
          throw e;
       }
    }
@@ -160,16 +184,17 @@
       String selectHQL = "select contact.id from Contact contact";
       selectHQL += " where contact.customer.name = :cName";
 
-      SimpleJtaTransactionManagerImpl.getInstance().begin();
+      log.debug("Get contacts for customer " + customerName);
+      tm.begin();
       try {
 
          Session session = getSessions().getCurrentSession();
          List results = session.createQuery(selectHQL).setFlushMode(FlushMode.AUTO).setParameter("cName", customerName)
                   .list();
-         SimpleJtaTransactionManagerImpl.getInstance().commit();
+         tm.commit();
          return results;
       } catch (Exception e) {
-         SimpleJtaTransactionManagerImpl.getInstance().rollback();
+         tm.rollback();
          throw e;
       }
    }
@@ -178,15 +203,15 @@
       String selectHQL = "select contact.id from Contact contact";
       selectHQL += " where contact.tlf = :cTLF";
 
-      SimpleJtaTransactionManagerImpl.getInstance().begin();
+      tm.begin();
       try {
 
          Session session = getSessions().getCurrentSession();
          List results = session.createQuery(selectHQL).setFlushMode(FlushMode.AUTO).setParameter("cTLF", tlf).list();
-         SimpleJtaTransactionManagerImpl.getInstance().commit();
+         tm.commit();
          return results;
       } catch (Exception e) {
-         SimpleJtaTransactionManagerImpl.getInstance().rollback();
+         tm.rollback();
          throw e;
       }
    }
@@ -194,51 +219,72 @@
    public int updateContacts(String name, String newTLF) throws Exception {
       String updateHQL = "update Contact set tlf = :cNewTLF where name = :cName";
 
-      SimpleJtaTransactionManagerImpl.getInstance().begin();
+      tm.begin();
       try {
 
          Session session = getSessions().getCurrentSession();
          int rowsAffected = session.createQuery(updateHQL).setFlushMode(FlushMode.AUTO).setParameter("cNewTLF", newTLF)
                   .setParameter("cName", name).executeUpdate();
-         SimpleJtaTransactionManagerImpl.getInstance().commit();
+         tm.commit();
          return rowsAffected;
       } catch (Exception e) {
-         SimpleJtaTransactionManagerImpl.getInstance().rollback();
+         tm.rollback();
          throw e;
       }
    }
 
    public Contact getContact(Integer id) throws Exception {
-
-      SimpleJtaTransactionManagerImpl.getInstance().begin();
+      tm.begin();
       try {
 
          Session session = getSessions().getCurrentSession();
          Contact contact = (Contact) session.get(Contact.class, id);
-         SimpleJtaTransactionManagerImpl.getInstance().commit();
+         tm.commit();
          return contact;
       } catch (Exception e) {
-         SimpleJtaTransactionManagerImpl.getInstance().rollback();
+         tm.rollback();
          throw e;
       }
    }
 
-   public void cleanup() throws Exception {
+//   public void cleanup() throws Exception {
+//      String deleteContactHQL = "delete from Contact";
+//      String deleteCustomerHQL = "delete from Customer";
+//      tm.begin();
+//      try {
+//         Session session = getSessions().getCurrentSession();
+//         session.createQuery(deleteContactHQL).setFlushMode(FlushMode.AUTO).executeUpdate();
+//         session.createQuery(deleteCustomerHQL).setFlushMode(FlushMode.AUTO).executeUpdate();
+//         tm.commit();
+//      } catch (Exception e) {
+//         try {
+//            tm.rollback();
+//         } catch (Exception ee) {
+//            // ignored
+//         }
+//         throw e;
+//      }
+//   }
+   
+   public void cleanup(boolean ignore) throws Exception {
       String deleteContactHQL = "delete from Contact";
       String deleteCustomerHQL = "delete from Customer";
-
-      SimpleJtaTransactionManagerImpl.getInstance().begin();
+      tm.begin();
       try {
-
          Session session = getSessions().getCurrentSession();
          session.createQuery(deleteContactHQL).setFlushMode(FlushMode.AUTO).executeUpdate();
          session.createQuery(deleteCustomerHQL).setFlushMode(FlushMode.AUTO).executeUpdate();
-         SimpleJtaTransactionManagerImpl.getInstance().commit();
+         tm.commit();
       } catch (Exception e) {
-         SimpleJtaTransactionManagerImpl.getInstance().rollback();
-         throw e;
+         if (!ignore) {
+            try {
+               tm.rollback();
+            } catch (Exception ee) {
+               // ignored
+            }
+            throw e;
+         }
       }
-
    }
 
    private Customer createCustomer(int id) throws Exception {

Modified: core/branches/INFINISPAN/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/cluster/DualNodeJtaTransactionImpl.java
===================================================================
--- core/branches/INFINISPAN/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/cluster/DualNodeJtaTransactionImpl.java	2009-08-18 17:23:57 UTC (rev 17354)
+++ core/branches/INFINISPAN/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/cluster/DualNodeJtaTransactionImpl.java	2009-08-18 19:48:57 UTC (rev 17355)
@@ -25,7 +25,11 @@
 
 import java.sql.Connection;
 import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Collection;
 import java.util.LinkedList;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
 
 import javax.transaction.HeuristicMixedException;
 import javax.transaction.HeuristicRollbackException;
@@ -34,7 +38,9 @@
 import javax.transaction.Synchronization;
 import javax.transaction.SystemException;
 import javax.transaction.Transaction;
+import javax.transaction.xa.XAException;
 import javax.transaction.xa.XAResource;
+import javax.transaction.xa.Xid;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -51,6 +57,8 @@
    private LinkedList synchronizations;
    private Connection connection; // the only resource we care about is jdbc connection
    private final DualNodeJtaTransactionManagerImpl jtaTransactionManager;
+   private List<XAResource> enlistedResources = new ArrayList<XAResource>();
+   private Xid xid = new DualNodeJtaTransactionXid();
 
    public DualNodeJtaTransactionImpl(DualNodeJtaTransactionManagerImpl jtaTransactionManager) {
       this.jtaTransactionManager = jtaTransactionManager;
@@ -69,11 +77,17 @@
          rollback();
       } else {
          status = Status.STATUS_PREPARING;
-
+         
          for (int i = 0; i < synchronizations.size(); i++) {
             Synchronization s = (Synchronization) synchronizations.get(i);
             s.beforeCompletion();
          }
+         
+         if (!runXaResourcePrepare()) {
+            status = Status.STATUS_ROLLING_BACK;
+         } else {
+            status = Status.STATUS_PREPARED;
+         }
 
          status = Status.STATUS_COMMITTING;
 
@@ -86,7 +100,10 @@
                throw new SystemException();
             }
          }
+         
 
+         runXaResourceCommitTx();
+
          status = Status.STATUS_COMMITTED;
 
          for (int i = 0; i < synchronizations.size(); i++) {
@@ -100,6 +117,8 @@
    }
 
    public void rollback() throws IllegalStateException, SystemException {
+      status = Status.STATUS_ROLLING_BACK;
+      runXaResourceRollback();
       status = Status.STATUS_ROLLEDBACK;
 
       if (connection != null) {
@@ -149,11 +168,86 @@
 
    public boolean enlistResource(XAResource xaResource) throws RollbackException,
             IllegalStateException, SystemException {
-      return false;
+      enlistedResources.add(xaResource);
+      try {
+         xaResource.start(xid, 0);
+      } catch (XAException e) {
+         log.error("Got an exception", e);
+         throw new SystemException(e.getMessage());
+      }
+      return true;
    }
 
    public boolean delistResource(XAResource xaResource, int i) throws IllegalStateException,
             SystemException {
-      return false;
+      throw new SystemException("not supported");
    }
+   
+   public Collection<XAResource> getEnlistedResources() {
+      return enlistedResources;
+   }
+   
+   private boolean runXaResourcePrepare() throws SystemException {
+      Collection<XAResource> resources = getEnlistedResources();
+      for (XAResource res : resources) {
+         try {
+            res.prepare(xid);
+         } catch (XAException e) {
+            log.trace("The resource wants to rollback!", e);
+            return false;
+         } catch (Throwable th) {
+            log.error("Unexpected error from resource manager!", th);
+            throw new SystemException(th.getMessage());
+         }
+      }
+      return true;
+   }
+   
+   private void runXaResourceRollback() {
+      Collection<XAResource> resources = getEnlistedResources();
+      for (XAResource res : resources) {
+         try {
+            res.rollback(xid);
+         } catch (XAException e) {
+            log.warn("Error while rolling back",e);
+         }
+      }
+   }
+
+   private boolean runXaResourceCommitTx() throws HeuristicMixedException {
+      Collection<XAResource> resources = getEnlistedResources();
+      for (XAResource res : resources) {
+         try {
+            res.commit(xid, false);//todo we only support one phase commit for now, change this!!!
+         } catch (XAException e) {
+            log.warn("exception while committing",e);
+            throw new HeuristicMixedException(e.getMessage());
+         }
+      }
+      return true;
+   }
+   
+   private static class DualNodeJtaTransactionXid implements Xid {
+      private static AtomicInteger txIdCounter = new AtomicInteger(0);
+      private int id = txIdCounter.incrementAndGet();
+
+      public int getFormatId() {
+         return id;
+      }
+
+      public byte[] getGlobalTransactionId() {
+         throw new IllegalStateException("TODO - please implement me!!!"); //todo implement!!!
+      }
+
+      public byte[] getBranchQualifier() {
+         throw new IllegalStateException("TODO - please implement me!!!"); //todo implement!!!
+      }
+
+      @Override
+      public String toString() {
+         return getClass().getSimpleName() + "{" +
+               "id=" + id +
+               '}';
+      }
+   }
 }

Modified: core/branches/INFINISPAN/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/cluster/EntityCollectionInvalidationTestCase.java
===================================================================
--- core/branches/INFINISPAN/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/cluster/EntityCollectionInvalidationTestCase.java	2009-08-18 17:23:57 UTC (rev 17354)
+++ core/branches/INFINISPAN/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/cluster/EntityCollectionInvalidationTestCase.java	2009-08-18 19:48:57 UTC (rev 17355)
@@ -36,7 +36,9 @@
 import org.infinispan.manager.CacheManager;
 import org.infinispan.marshall.MarshalledValue;
 import org.infinispan.notifications.Listener;
+import org.infinispan.notifications.cachelistener.annotation.CacheEntryModified;
 import org.infinispan.notifications.cachelistener.annotation.CacheEntryVisited;
+import org.infinispan.notifications.cachelistener.event.CacheEntryModifiedEvent;
 import org.infinispan.notifications.cachelistener.event.CacheEntryVisitedEvent;
 import org.jboss.util.collection.ConcurrentSet;
 import org.slf4j.Logger;
@@ -138,12 +140,12 @@
          // Modify customer in remote
          remoteListener.clear();
          ids = modifyCustomer(ids.customerId, remoteFactory, remoteTM);
-         assertLoadedFromCache(remoteListener, ids.customerId, ids.contactIds);         
+         assertLoadedFromCache(remoteListener, ids.customerId, ids.contactIds);
 
          // After modification, local cache should have been invalidated and hence should be empty
          assertTrue(localCollectionCache.isEmpty());
          assertTrue(localCustomerCache.isEmpty());
-         assertTrue(localContactCache.isEmpty());         
+         assertTrue(localContactCache.isEmpty());
       } catch (Exception e) {
          log.error("Error", e);
          throw e;
@@ -328,7 +330,6 @@
       @CacheEntryVisited
       public void nodeVisited(CacheEntryVisitedEvent event) {
          log.debug(event.toString());
-
          if (!event.isPre()) {
             MarshalledValue mv = (MarshalledValue) event.getKey();
             CacheKey cacheKey = (CacheKey) mv.get();
@@ -336,7 +337,7 @@
             String key = (String) cacheKey.getEntityOrRoleName() + '#' + primKey;
             log.debug("MyListener[" + name +"] - Visiting key " + key);
             // String name = fqn.toString();
-            String token = ".functional.cluster.";
+            String token = ".functional.";
             int index = key.indexOf(token);
             if (index > -1) {
                index += token.length();
@@ -346,6 +347,27 @@
             }
          }
       }
+      
+//      @CacheEntryModified
+//      public void nodeModified(CacheEntryModifiedEvent event) {
+//         log.debug(event.toString());
+//         if (!event.isPre()) {
+//            MarshalledValue mv = (MarshalledValue) event.getKey();
+//            CacheKey cacheKey = (CacheKey) mv.get();
+//            Integer primKey = (Integer) cacheKey.getKey();
+//            String key = (String) cacheKey.getEntityOrRoleName() + '#' + primKey;
+//            log.debug("MyListener[" + name +"] - Modified key " + key);
+//            // String name = fqn.toString();
+//            String token = ".functional.";
+//            int index = key.indexOf(token);
+//            if (index > -1) {
+//               index += token.length();
+//               key = key.substring(index);
+//               log.debug("MyListener[" + name +"] - recording modification of " + key);
+//               visited.add(key);
+//            }
+//         }
+//      }
    }
 
    private class IdContainer {

Added: core/branches/INFINISPAN/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/query/QueryRegionImplTestCase.java
===================================================================
--- core/branches/INFINISPAN/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/query/QueryRegionImplTestCase.java	                        (rev 0)
+++ core/branches/INFINISPAN/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/query/QueryRegionImplTestCase.java	2009-08-18 19:48:57 UTC (rev 17355)
@@ -0,0 +1,299 @@
+/*
+ * 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.query;
+
+import java.util.Properties;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import junit.framework.AssertionFailedError;
+
+import org.hibernate.cache.CacheDataDescription;
+import org.hibernate.cache.QueryResultsRegion;
+import org.hibernate.cache.Region;
+import org.hibernate.cache.StandardQueryCache;
+import org.hibernate.cache.infinispan.InfinispanRegionFactory;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.test.cache.infinispan.AbstractGeneralDataRegionTestCase;
+import org.hibernate.test.cache.infinispan.util.CacheTestUtil;
+import org.infinispan.Cache;
+import org.infinispan.notifications.Listener;
+import org.infinispan.notifications.cachelistener.annotation.CacheEntryVisited;
+import org.infinispan.notifications.cachelistener.event.CacheEntryVisitedEvent;
+import org.infinispan.transaction.tm.BatchModeTransactionManager;
+import org.infinispan.util.concurrent.IsolationLevel;
+
+/**
+ * Tests of QueryResultRegionImpl.
+ * 
+ * @author <a href="brian.stansberry at jboss.com">Brian Stansberry</a>
+ * @version $Revision: 1 $
+ */
+public class QueryRegionImplTestCase extends AbstractGeneralDataRegionTestCase {
+
+   // protected static final String REGION_NAME = "test/" + StandardQueryCache.class.getName();
+
+   /**
+    * Create a new EntityRegionImplTestCase.
+    * 
+    * @param name
+    */
+   public QueryRegionImplTestCase(String name) {
+      super(name);
+   }
+
+   @Override
+   protected Region createRegion(InfinispanRegionFactory regionFactory, String regionName, Properties properties,
+            CacheDataDescription cdd) {
+      return regionFactory.buildQueryResultsRegion(regionName, properties);
+   }
+
+   @Override
+   protected String getStandardRegionName(String regionPrefix) {
+      return regionPrefix + "/" + StandardQueryCache.class.getName();
+   }
+
+   @Override
+   protected Cache getInfinispanCache(InfinispanRegionFactory regionFactory) {
+      return regionFactory.getCacheManager().getCache("local-query");
+   }
+
+   public void testPutDoesNotBlockGet() throws Exception {
+      putDoesNotBlockGetTest();
+   }
+
+   private void putDoesNotBlockGetTest() throws Exception {
+      Configuration cfg = createConfiguration();
+      InfinispanRegionFactory regionFactory = CacheTestUtil.startRegionFactory(cfg, getCacheTestSupport());
+
+      // Sleep a bit to avoid concurrent FLUSH problem
+      avoidConcurrentFlush();
+
+      final QueryResultsRegion region = regionFactory.buildQueryResultsRegion(getStandardRegionName(REGION_PREFIX), cfg
+               .getProperties());
+
+      region.put(KEY, VALUE1);
+      assertEquals(VALUE1, region.get(KEY));
+
+      final CountDownLatch readerLatch = new CountDownLatch(1);
+      final CountDownLatch writerLatch = new CountDownLatch(1);
+      final CountDownLatch completionLatch = new CountDownLatch(1);
+      final ExceptionHolder holder = new ExceptionHolder();
+
+      Thread reader = new Thread() {
+         public void run() {
+            try {
+               BatchModeTransactionManager.getInstance().begin();
+               log.debug("Transaction began, get value for key");
+               assertTrue(VALUE2.equals(region.get(KEY)) == false);
+               BatchModeTransactionManager.getInstance().commit();
+            } catch (AssertionFailedError e) {
+               holder.a1 = e;
+               rollback();
+            } catch (Exception e) {
+               holder.e1 = e;
+               rollback();
+            } finally {
+               readerLatch.countDown();
+            }
+         }
+      };
+
+      Thread writer = new Thread() {
+         public void run() {
+            try {
+               BatchModeTransactionManager.getInstance().begin();
+               log.debug("Put value2");
+               region.put(KEY, VALUE2);
+               log.debug("Put finished for value2, await writer latch");
+               writerLatch.await();
+               log.debug("Writer latch finished");
+               BatchModeTransactionManager.getInstance().commit();
+               log.debug("Transaction committed");
+            } catch (Exception e) {
+               holder.e2 = e;
+               rollback();
+            } finally {
+               completionLatch.countDown();
+            }
+         }
+      };
+
+      reader.setDaemon(true);
+      writer.setDaemon(true);
+
+      writer.start();
+      assertFalse("Writer is blocking", completionLatch.await(100, TimeUnit.MILLISECONDS));
+
+      // Start the reader
+      reader.start();
+      assertTrue("Reader finished promptly", readerLatch.await(1000000000, TimeUnit.MILLISECONDS));
+
+      writerLatch.countDown();
+      assertTrue("Reader finished promptly", completionLatch.await(100, TimeUnit.MILLISECONDS));
+
+      assertEquals(VALUE2, region.get(KEY));
+
+      if (holder.a1 != null)
+         throw holder.a1;
+      else if (holder.a2 != null)
+         throw holder.a2;
+
+      assertEquals("writer saw no exceptions", null, holder.e1);
+      assertEquals("reader saw no exceptions", null, holder.e2);
+   }
+
+   public void testGetDoesNotBlockPut() throws Exception {
+      getDoesNotBlockPutTest();
+   }
+
+   // public void testGetDoesNotBlockPutPessimisticRepeatableRead() throws Exception {
+   // getDoesNotBlockPutTest();
+   // }
+
+   private void getDoesNotBlockPutTest() throws Exception {
+      Configuration cfg = createConfiguration();
+      InfinispanRegionFactory regionFactory = CacheTestUtil.startRegionFactory(cfg, getCacheTestSupport());
+
+      // Sleep a bit to avoid concurrent FLUSH problem
+      avoidConcurrentFlush();
+
+      final QueryResultsRegion region = regionFactory.buildQueryResultsRegion(getStandardRegionName(REGION_PREFIX), cfg
+               .getProperties());
+
+      region.put(KEY, VALUE1);
+      assertEquals(VALUE1, region.get(KEY));
+
+      // final Fqn rootFqn = getRegionFqn(getStandardRegionName(REGION_PREFIX), REGION_PREFIX);
+      final Cache jbc = getInfinispanCache(regionFactory);
+
+      final CountDownLatch blockerLatch = new CountDownLatch(1);
+      final CountDownLatch writerLatch = new CountDownLatch(1);
+      final CountDownLatch completionLatch = new CountDownLatch(1);
+      final ExceptionHolder holder = new ExceptionHolder();
+
+      Thread blocker = new Thread() {
+
+         public void run() {
+            // Fqn toBlock = new Fqn(rootFqn, KEY);
+            GetBlocker blocker = new GetBlocker(blockerLatch, KEY);
+            try {
+               jbc.addListener(blocker);
+
+               BatchModeTransactionManager.getInstance().begin();
+               region.get(KEY);
+               BatchModeTransactionManager.getInstance().commit();
+            } catch (Exception e) {
+               holder.e1 = e;
+               rollback();
+            } finally {
+               jbc.removeListener(blocker);
+            }
+         }
+      };
+
+      Thread writer = new Thread() {
+
+         public void run() {
+            try {
+               writerLatch.await();
+
+               BatchModeTransactionManager.getInstance().begin();
+               region.put(KEY, VALUE2);
+               BatchModeTransactionManager.getInstance().commit();
+            } catch (Exception e) {
+               holder.e2 = e;
+               rollback();
+            } finally {
+               completionLatch.countDown();
+            }
+         }
+      };
+
+      blocker.setDaemon(true);
+      writer.setDaemon(true);
+
+      boolean unblocked = false;
+      try {
+         blocker.start();
+         writer.start();
+
+         assertFalse("Blocker is blocking", completionLatch.await(100, TimeUnit.MILLISECONDS));
+         // Start the writer
+         writerLatch.countDown();
+         assertTrue("Writer finished promptly", completionLatch.await(100, TimeUnit.MILLISECONDS));
+
+         blockerLatch.countDown();
+         unblocked = true;
+
+         if (IsolationLevel.REPEATABLE_READ.equals(jbc.getConfiguration().getIsolationLevel())) {
+            assertEquals(VALUE1, region.get(KEY));
+         } else {
+            assertEquals(VALUE2, region.get(KEY));
+         }
+
+         if (holder.a1 != null)
+            throw holder.a1;
+         else if (holder.a2 != null)
+            throw holder.a2;
+
+         assertEquals("blocker saw no exceptions", null, holder.e1);
+         assertEquals("writer saw no exceptions", null, holder.e2);
+      } finally {
+         if (!unblocked)
+            blockerLatch.countDown();
+      }
+   }
+
+   @Listener
+   public class GetBlocker {
+
+      private CountDownLatch latch;
+      // private Fqn fqn;
+      private Object key;
+
+      GetBlocker(CountDownLatch latch, Object key) {
+         this.latch = latch;
+         this.key = key;
+      }
+
+      @CacheEntryVisited
+      public void nodeVisisted(CacheEntryVisitedEvent event) {
+         if (event.isPre() && event.getKey().equals(key)) {
+            try {
+               latch.await();
+            } catch (InterruptedException e) {
+               log.error("Interrupted waiting for latch", e);
+            }
+         }
+      }
+   }
+
+   private class ExceptionHolder {
+      Exception e1;
+      Exception e2;
+      AssertionFailedError a1;
+      AssertionFailedError a2;
+   }
+}

Added: core/branches/INFINISPAN/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/tm/XaConnectionProvider.java
===================================================================
--- core/branches/INFINISPAN/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/tm/XaConnectionProvider.java	                        (rev 0)
+++ core/branches/INFINISPAN/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/tm/XaConnectionProvider.java	2009-08-18 19:48:57 UTC (rev 17355)
@@ -0,0 +1,78 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2009, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.hibernate.test.cache.infinispan.tm;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.util.Properties;
+
+import org.hibernate.HibernateException;
+import org.hibernate.connection.ConnectionProvider;
+import org.hibernate.connection.ConnectionProviderFactory;
+
+/**
+ * XaConnectionProvider.
+ * 
+ * @author Galder Zamarreño
+ * @since 4.0
+ */
+public class XaConnectionProvider implements ConnectionProvider {
+   private static ConnectionProvider actualConnectionProvider = ConnectionProviderFactory.newConnectionProvider();
+   private boolean isTransactional;
+
+   public static ConnectionProvider getActualConnectionProvider() {
+      return actualConnectionProvider;
+   }
+
+   public void configure(Properties props) throws HibernateException {
+   }
+
+   public Connection getConnection() throws SQLException {
+      XaTransactionImpl currentTransaction = XaTransactionManagerImpl.getInstance().getCurrentTransaction();
+      if (currentTransaction == null) {
+         isTransactional = false;
+         return actualConnectionProvider.getConnection();
+      } else {
+         isTransactional = true;
+         Connection connection = currentTransaction.getEnlistedConnection();
+         if (connection == null) {
+            connection = actualConnectionProvider.getConnection();
+            currentTransaction.enlistConnection(connection);
+         }
+         return connection;
+      }
+   }
+
+   public void closeConnection(Connection conn) throws SQLException {
+      if (!isTransactional) {
+         conn.close();
+      }
+   }
+
+   public void close() throws HibernateException {
+      actualConnectionProvider.close();
+   }
+
+   public boolean supportsAggressiveRelease() {
+      return true;
+   }
+}

Added: core/branches/INFINISPAN/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/tm/XaTransactionImpl.java
===================================================================
--- core/branches/INFINISPAN/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/tm/XaTransactionImpl.java	                        (rev 0)
+++ core/branches/INFINISPAN/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/tm/XaTransactionImpl.java	2009-08-18 19:48:57 UTC (rev 17355)
@@ -0,0 +1,247 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2009, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.hibernate.test.cache.infinispan.tm;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import javax.transaction.HeuristicMixedException;
+import javax.transaction.HeuristicRollbackException;
+import javax.transaction.RollbackException;
+import javax.transaction.Status;
+import javax.transaction.Synchronization;
+import javax.transaction.SystemException;
+import javax.transaction.Transaction;
+import javax.transaction.xa.XAException;
+import javax.transaction.xa.XAResource;
+import javax.transaction.xa.Xid;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * XaResourceCapableTransactionImpl.
+ * 
+ * @author Galder Zamarreño
+ * @since 4.0
+ */
+public class XaTransactionImpl implements Transaction {
+   private static final Logger log = LoggerFactory.getLogger(XaTransactionImpl.class);
+   private int status;
+   private LinkedList synchronizations;
+   private Connection connection; // the only resource we care about is jdbc connection
+   private final XaTransactionManagerImpl jtaTransactionManager;
+   private List<XAResource> enlistedResources = new ArrayList<XAResource>();
+   private Xid xid = new XaResourceCapableTransactionXid();
+
+   public XaTransactionImpl(XaTransactionManagerImpl jtaTransactionManager) {
+      this.jtaTransactionManager = jtaTransactionManager;
+      this.status = Status.STATUS_ACTIVE;
+   }
+
+   public int getStatus() {
+      return status;
+   }
+
+   public void commit() throws RollbackException, HeuristicMixedException, HeuristicRollbackException,
+            IllegalStateException, SystemException {
+
+      if (status == Status.STATUS_MARKED_ROLLBACK) {
+         log.trace("on commit, status was marked for rollback-only");
+         rollback();
+      } else {
+         status = Status.STATUS_PREPARING;
+
+         for (int i = 0; i < synchronizations.size(); i++) {
+            Synchronization s = (Synchronization) synchronizations.get(i);
+            s.beforeCompletion();
+         }
+
+//         if (!runXaResourcePrepare()) {
+//            status = Status.STATUS_ROLLING_BACK;
+//         } else {
+//            status = Status.STATUS_PREPARED;
+//         }
+
+         status = Status.STATUS_COMMITTING;
+
+         if (connection != null) {
+            try {
+               connection.commit();
+               connection.close();
+            } catch (SQLException sqle) {
+               status = Status.STATUS_UNKNOWN;
+               throw new SystemException();
+            }
+         }
+
+//         runXaResourceCommitTx();
+
+         status = Status.STATUS_COMMITTED;
+
+         for (int i = 0; i < synchronizations.size(); i++) {
+            Synchronization s = (Synchronization) synchronizations.get(i);
+            s.afterCompletion(status);
+         }
+
+         // status = Status.STATUS_NO_TRANSACTION;
+         jtaTransactionManager.endCurrent(this);
+      }
+   }
+
+   public void rollback() throws IllegalStateException, SystemException {
+//      status = Status.STATUS_ROLLING_BACK;
+//      runXaResourceRollback();
+      status = Status.STATUS_ROLLEDBACK;
+
+      if (connection != null) {
+         try {
+            connection.rollback();
+            connection.close();
+         } catch (SQLException sqle) {
+            status = Status.STATUS_UNKNOWN;
+            throw new SystemException();
+         }
+      }
+
+      for (int i = 0; i < synchronizations.size(); i++) {
+         Synchronization s = (Synchronization) synchronizations.get(i);
+         s.afterCompletion(status);
+      }
+
+      // status = Status.STATUS_NO_TRANSACTION;
+      jtaTransactionManager.endCurrent(this);
+   }
+
+   public void setRollbackOnly() throws IllegalStateException, SystemException {
+      status = Status.STATUS_MARKED_ROLLBACK;
+   }
+
+   public void registerSynchronization(Synchronization synchronization) throws RollbackException,
+            IllegalStateException, SystemException {
+      // todo : find the spec-allowable statuses during which synch can be registered...
+      if (synchronizations == null) {
+         synchronizations = new LinkedList();
+      }
+      synchronizations.add(synchronization);
+   }
+
+   public void enlistConnection(Connection connection) {
+      if (this.connection != null) {
+         throw new IllegalStateException("Connection already registered");
+      }
+      this.connection = connection;
+   }
+
+   public Connection getEnlistedConnection() {
+      return connection;
+   }
+
+   public boolean enlistResource(XAResource xaResource) throws RollbackException, IllegalStateException,
+            SystemException {
+      enlistedResources.add(xaResource);
+      try {
+         xaResource.start(xid, 0);
+      } catch (XAException e) {
+         log.error("Got an exception", e);
+         throw new SystemException(e.getMessage());
+      }
+      return true;
+   }
+
+   public boolean delistResource(XAResource xaResource, int i) throws IllegalStateException, SystemException {
+      throw new SystemException("not supported");
+   }
+   
+   public Collection<XAResource> getEnlistedResources() {
+      return enlistedResources;
+   }
+   
+   private boolean runXaResourcePrepare() throws SystemException {
+      Collection<XAResource> resources = getEnlistedResources();
+      for (XAResource res : resources) {
+         try {
+            res.prepare(xid);
+         } catch (XAException e) {
+            log.trace("The resource wants to rollback!", e);
+            return false;
+         } catch (Throwable th) {
+            log.error("Unexpected error from resource manager!", th);
+            throw new SystemException(th.getMessage());
+         }
+      }
+      return true;
+   }
+   
+   private void runXaResourceRollback() {
+      Collection<XAResource> resources = getEnlistedResources();
+      for (XAResource res : resources) {
+         try {
+            res.rollback(xid);
+         } catch (XAException e) {
+            log.warn("Error while rolling back",e);
+         }
+      }
+   }
+
+   private boolean runXaResourceCommitTx() throws HeuristicMixedException {
+      Collection<XAResource> resources = getEnlistedResources();
+      for (XAResource res : resources) {
+         try {
+            res.commit(xid, false);//todo we only support one phase commit for now, change this!!!
+         } catch (XAException e) {
+            log.warn("exception while committing",e);
+            throw new HeuristicMixedException(e.getMessage());
+         }
+      }
+      return true;
+   }
+   
+   private static class XaResourceCapableTransactionXid implements Xid {
+      private static AtomicInteger txIdCounter = new AtomicInteger(0);
+      private int id = txIdCounter.incrementAndGet();
+
+      public int getFormatId() {
+         return id;
+      }
+
+      public byte[] getGlobalTransactionId() {
+         throw new IllegalStateException("TODO - please implement me!!!"); //todo implement!!!
+      }
+
+      public byte[] getBranchQualifier() {
+         throw new IllegalStateException("TODO - please implement me!!!"); //todo implement!!!
+      }
+
+      @Override
+      public String toString() {
+         return getClass().getSimpleName() + "{" +
+               "id=" + id +
+               '}';
+      }
+   }
+}

Added: core/branches/INFINISPAN/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/tm/XaTransactionManagerImpl.java
===================================================================
--- core/branches/INFINISPAN/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/tm/XaTransactionManagerImpl.java	                        (rev 0)
+++ core/branches/INFINISPAN/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/tm/XaTransactionManagerImpl.java	2009-08-18 19:48:57 UTC (rev 17355)
@@ -0,0 +1,108 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2009, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.hibernate.test.cache.infinispan.tm;
+
+import javax.transaction.HeuristicMixedException;
+import javax.transaction.HeuristicRollbackException;
+import javax.transaction.InvalidTransactionException;
+import javax.transaction.NotSupportedException;
+import javax.transaction.RollbackException;
+import javax.transaction.Status;
+import javax.transaction.SystemException;
+import javax.transaction.Transaction;
+import javax.transaction.TransactionManager;
+
+import org.hibernate.test.tm.SimpleJtaTransactionImpl;
+import org.hibernate.test.tm.SimpleJtaTransactionManagerImpl;
+
+/**
+ * XaResourceCapableTransactionManagerImpl.
+ * 
+ * @author Galder Zamarreño
+ * @since 4.0
+ */
+public class XaTransactionManagerImpl implements TransactionManager {
+   private static final XaTransactionManagerImpl INSTANCE = new XaTransactionManagerImpl();
+   private XaTransactionImpl currentTransaction;
+
+   public static XaTransactionManagerImpl getInstance() {
+      return INSTANCE;
+   }
+
+   public int getStatus() throws SystemException {
+      return currentTransaction == null ? Status.STATUS_NO_TRANSACTION : currentTransaction.getStatus();
+   }
+
+   public Transaction getTransaction() throws SystemException {
+      return currentTransaction;
+   }
+
+   public XaTransactionImpl getCurrentTransaction() {
+      return currentTransaction;
+   }
+
+   public void begin() throws NotSupportedException, SystemException {
+      currentTransaction = new XaTransactionImpl(this);
+   }
+
+   public Transaction suspend() throws SystemException {
+      Transaction suspended = currentTransaction;
+      currentTransaction = null;
+      return suspended;
+   }
+
+   public void resume(Transaction transaction) throws InvalidTransactionException, IllegalStateException,
+            SystemException {
+      currentTransaction = (XaTransactionImpl) transaction;
+   }
+
+   public void commit() throws RollbackException, HeuristicMixedException, HeuristicRollbackException,
+            SecurityException, IllegalStateException, SystemException {
+      if (currentTransaction == null) {
+         throw new IllegalStateException("no current transaction to commit");
+      }
+      currentTransaction.commit();
+   }
+
+   public void rollback() throws IllegalStateException, SecurityException, SystemException {
+      if (currentTransaction == null) {
+         throw new IllegalStateException("no current transaction");
+      }
+      currentTransaction.rollback();
+   }
+
+   public void setRollbackOnly() throws IllegalStateException, SystemException {
+      if (currentTransaction == null) {
+         throw new IllegalStateException("no current transaction");
+      }
+      currentTransaction.setRollbackOnly();
+   }
+
+   public void setTransactionTimeout(int i) throws SystemException {
+   }
+
+   void endCurrent(Transaction transaction) {
+      if (transaction == currentTransaction) {
+         currentTransaction = null;
+      }
+   }
+}

Added: core/branches/INFINISPAN/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/tm/XaTransactionManagerLookup.java
===================================================================
--- core/branches/INFINISPAN/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/tm/XaTransactionManagerLookup.java	                        (rev 0)
+++ core/branches/INFINISPAN/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/tm/XaTransactionManagerLookup.java	2009-08-18 19:48:57 UTC (rev 17355)
@@ -0,0 +1,53 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2009, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.hibernate.test.cache.infinispan.tm;
+
+import java.util.Properties;
+
+import javax.transaction.Transaction;
+import javax.transaction.TransactionManager;
+
+import org.hibernate.HibernateException;
+import org.hibernate.test.tm.SimpleJtaTransactionManagerImpl;
+import org.hibernate.transaction.TransactionManagerLookup;
+
+/**
+ * XaResourceCapableTransactionManagerLookup.
+ * 
+ * @author Galder Zamarreño
+ * @since 3.5
+ */
+public class XaTransactionManagerLookup implements TransactionManagerLookup {
+
+   public Object getTransactionIdentifier(Transaction transaction) {
+      return transaction;
+   }
+
+   public TransactionManager getTransactionManager(Properties props) throws HibernateException {
+      return XaTransactionManagerImpl.getInstance();
+   }
+
+   public String getUserTransactionName() {
+      throw new UnsupportedOperationException( "jndi currently not implemented for these tests" );
+   }
+
+}

Added: core/branches/INFINISPAN/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/util/BatchModeTransactionManagerLookup.java
===================================================================
--- core/branches/INFINISPAN/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/util/BatchModeTransactionManagerLookup.java	                        (rev 0)
+++ core/branches/INFINISPAN/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/util/BatchModeTransactionManagerLookup.java	2009-08-18 19:48:57 UTC (rev 17355)
@@ -0,0 +1,61 @@
+/*
+ * 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.util;
+
+import java.util.Properties;
+
+import javax.transaction.TransactionManager;
+import javax.transaction.Transaction;
+
+import org.hibernate.HibernateException;
+import org.hibernate.transaction.TransactionManagerLookup;
+import org.infinispan.transaction.tm.BatchModeTransactionManager;
+
+/**
+ * Uses the JBoss Cache BatchModeTransactionManager. Should not be used in
+ * any tests that simulate usage of database connections.
+ * 
+ * @author Brian Stansberry
+ */
+public class BatchModeTransactionManagerLookup
+    implements TransactionManagerLookup {
+
+    public TransactionManager getTransactionManager(Properties props) throws HibernateException {
+        try {
+            return BatchModeTransactionManager.getInstance();
+        }
+        catch (Exception e) {
+            throw new HibernateException("Failed getting BatchModeTransactionManager", e);
+        }
+    }
+
+    public String getUserTransactionName() {
+        throw new UnsupportedOperationException();
+    }
+
+	public Object getTransactionIdentifier(Transaction transaction) {
+		return transaction;
+	}
+
+}


Property changes on: core/branches/INFINISPAN/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/util/BatchModeTransactionManagerLookup.java
___________________________________________________________________
Name: svn:executable
   + *

Added: core/branches/INFINISPAN/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/util/CacheTestSupport.java
===================================================================
--- core/branches/INFINISPAN/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/util/CacheTestSupport.java	                        (rev 0)
+++ core/branches/INFINISPAN/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/util/CacheTestSupport.java	2009-08-18 19:48:57 UTC (rev 17355)
@@ -0,0 +1,152 @@
+/*
+ * 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.util;
+
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import org.slf4j.Logger;
+
+import org.hibernate.cache.RegionFactory;
+import org.infinispan.Cache;
+
+/**
+ * Support class for tracking and cleaning up objects used in tests.
+ * 
+ * @author <a href="brian.stansberry at jboss.com">Brian Stansberry</a>
+ * @version $Revision: 1 $
+ */
+public class CacheTestSupport {
+    
+    private static final String PREFER_IPV4STACK = "java.net.preferIPv4Stack";
+    
+    private Logger log;
+    
+    private Set<Cache> caches = new HashSet();
+    private Set<RegionFactory> factories = new HashSet();
+    private Exception exception;
+    private String preferIPv4Stack;
+ 
+    public CacheTestSupport(Logger log) {
+       this.log = log;
+    }
+    
+    public void registerCache(Cache cache) {
+        caches.add(cache);
+    }
+    
+    public void registerFactory(RegionFactory factory) {
+        factories.add(factory);
+    }
+ 
+    public void unregisterCache(Cache cache) {
+        caches.remove(cache);
+    }
+    
+    public void unregisterFactory(RegionFactory factory) {
+        factories.remove(factory);
+    }
+    
+    public void setUp() throws Exception {   
+        
+        // Try to ensure we use IPv4; otherwise cluster formation is very slow 
+        preferIPv4Stack = System.getProperty(PREFER_IPV4STACK);
+        System.setProperty(PREFER_IPV4STACK, "true");
+
+        cleanUp();
+        throwStoredException();
+    }
+
+    public void tearDown() throws Exception {       
+        
+        if (preferIPv4Stack == null)
+            System.clearProperty(PREFER_IPV4STACK);
+        else 
+            System.setProperty(PREFER_IPV4STACK, preferIPv4Stack);
+        
+        cleanUp();
+        throwStoredException();
+    }
+    
+    public void avoidConcurrentFlush() {
+       // JG 2.6.1 has a problem where calling flush more than once too quickly
+       // can result in several second delays
+       sleep(100);
+    }
+    
+    private void sleep(long ms) {
+        try {
+            Thread.sleep(ms);
+        }
+        catch (InterruptedException e) {
+            log.warn("Interrupted during sleep", e);
+        }
+    }
+
+    private void cleanUp() {
+        for (Iterator it = factories.iterator(); it.hasNext(); ) {
+            try {
+                ((RegionFactory) it.next()).stop();
+            }
+            catch (Exception e) {
+                storeException(e);
+            }
+            finally {
+                it.remove();
+            }
+        }        
+        factories.clear();
+        
+        for (Iterator it = caches.iterator(); it.hasNext(); ) {
+            try {
+                Cache cache = (Cache) it.next();
+                cache.stop();
+            }
+            catch (Exception e) {
+                storeException(e);
+            }
+            finally {
+                it.remove();
+            }
+            avoidConcurrentFlush();
+        }        
+        caches.clear();
+    }
+    
+    private void storeException(Exception e) {
+        if (this.exception == null) {
+            this.exception = e;
+        }
+    }
+    
+    private void throwStoredException() throws Exception {
+        if (exception != null) {
+            Exception toThrow = exception;
+            exception = null;
+            throw toThrow;
+        }
+    }
+
+}

Added: core/branches/INFINISPAN/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/util/CacheTestUtil.java
===================================================================
--- core/branches/INFINISPAN/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/util/CacheTestUtil.java	                        (rev 0)
+++ core/branches/INFINISPAN/cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/util/CacheTestUtil.java	2009-08-18 19:48:57 UTC (rev 17355)
@@ -0,0 +1,140 @@
+/*
+ * 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.util;
+
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Properties;
+import java.util.Set;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+import org.hibernate.cache.infinispan.InfinispanRegionFactory;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.cfg.Environment;
+import org.hibernate.cfg.Settings;
+
+/**
+ * Utilities for cache testing.
+ * 
+ * @author <a href="brian.stansberry at jboss.com">Brian Stansberry</a>
+ * @version $Revision: 1 $
+ */
+public class CacheTestUtil {
+
+   public static Configuration buildConfiguration(String regionPrefix, Class regionFactory, boolean use2ndLevel, boolean useQueries) {
+      Configuration cfg = new Configuration();
+      cfg.setProperty(Environment.GENERATE_STATISTICS, "true");
+      cfg.setProperty(Environment.USE_STRUCTURED_CACHE, "true");
+      cfg.setProperty(Environment.TRANSACTION_MANAGER_STRATEGY, BatchModeTransactionManagerLookup.class.getName());
+
+      cfg.setProperty(Environment.CACHE_REGION_FACTORY, regionFactory.getName());
+      cfg.setProperty(Environment.CACHE_REGION_PREFIX, regionPrefix);
+      cfg.setProperty(Environment.USE_SECOND_LEVEL_CACHE, String.valueOf(use2ndLevel));
+      cfg.setProperty(Environment.USE_QUERY_CACHE, String.valueOf(useQueries));
+
+      return cfg;
+   }
+
+   public static Configuration buildLocalOnlyConfiguration(String regionPrefix, boolean use2ndLevel, boolean useQueries) {
+      Configuration cfg = buildConfiguration(regionPrefix, InfinispanRegionFactory.class, use2ndLevel, useQueries);
+      cfg.setProperty(InfinispanRegionFactory.INFINISPAN_CONFIG_RESOURCE_PROP,
+               InfinispanRegionFactory.DEF_INFINISPAN_CONFIG_RESOURCE);
+      return cfg;
+   }
+
+   public static InfinispanRegionFactory startRegionFactory(Configuration cfg) throws ClassNotFoundException,
+            InstantiationException, IllegalAccessException {
+
+      Settings settings = cfg.buildSettings();
+      Properties properties = cfg.getProperties();
+
+      String factoryType = cfg.getProperty(Environment.CACHE_REGION_FACTORY);
+      Class factoryClass = Thread.currentThread().getContextClassLoader().loadClass(factoryType);
+      InfinispanRegionFactory regionFactory = (InfinispanRegionFactory) factoryClass.newInstance();
+
+      regionFactory.start(settings, properties);
+
+      return regionFactory;
+   }
+
+   public static InfinispanRegionFactory startRegionFactory(Configuration cfg, CacheTestSupport testSupport)
+            throws ClassNotFoundException, InstantiationException, IllegalAccessException {
+      InfinispanRegionFactory factory = startRegionFactory(cfg);
+      testSupport.registerFactory(factory);
+      return factory;
+   }
+
+   public static void stopRegionFactory(InfinispanRegionFactory factory, CacheTestSupport testSupport) {
+      factory.stop();
+      testSupport.unregisterFactory(factory);
+   }
+
+   /**
+    * Supports easy creation of a TestSuite where a subclass' "FailureExpected" version of a base
+    * test is included in the suite, while the base test is excluded. E.g. test class FooTestCase
+    * includes method testBar(), while test class SubFooTestCase extends FooTestCase includes method
+    * testBarFailureExcluded(). Passing SubFooTestCase.class to this method will return a suite that
+    * does not include testBar().
+    * 
+    * FIXME Move this to UnitTestCase
+    */
+   public static TestSuite createFailureExpectedSuite(Class testClass) {
+
+      TestSuite allTests = new TestSuite(testClass);
+      Set failureExpected = new HashSet();
+      Enumeration tests = allTests.tests();
+      while (tests.hasMoreElements()) {
+         Test t = (Test) tests.nextElement();
+         if (t instanceof TestCase) {
+            String name = ((TestCase) t).getName();
+            if (name.endsWith("FailureExpected"))
+               failureExpected.add(name);
+         }
+      }
+
+      TestSuite result = new TestSuite();
+      tests = allTests.tests();
+      while (tests.hasMoreElements()) {
+         Test t = (Test) tests.nextElement();
+         if (t instanceof TestCase) {
+            String name = ((TestCase) t).getName();
+            if (!failureExpected.contains(name + "FailureExpected")) {
+               result.addTest(t);
+            }
+         }
+      }
+
+      return result;
+   }
+
+   /**
+    * Prevent instantiation.
+    */
+   private CacheTestUtil() {
+   }
+
+}



More information about the hibernate-commits mailing list