[SCM] hibernate-jbosscache: Integration of Hibernate with JBossCache branch, upstream, updated. upstream/3.6.8-2-g3828d4b

Miguel Landaeta miguel at miguel.cc
Tue Mar 20 00:20:46 UTC 2012


The following commit has been merged in the upstream branch:
commit 3828d4b38bef34ba72bd2f3f204197a12eb56be1
Author: Miguel Landaeta <miguel at miguel.cc>
Date:   Sun Mar 18 18:47:49 2012 -0430

    Revert "Revert "Imported Upstream version 3.6.8""
    
    This reverts commit 5d98ff11c75d1cbb7788db341443e12912757011.

diff --git a/pom.xml b/pom.xml
deleted file mode 100644
index ae9c17e..0000000
--- a/pom.xml
+++ /dev/null
@@ -1,87 +0,0 @@
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
-
-    <modelVersion>4.0.0</modelVersion>
-
-    <parent>
-        <groupId>org.hibernate</groupId>
-        <artifactId>hibernate-parent</artifactId>
-        <version>3.3.2.GA</version>
-        <relativePath>../parent/pom.xml</relativePath>
-    </parent>
-    
-    <groupId>org.hibernate</groupId>
-    <artifactId>hibernate-jbosscache</artifactId>
-    <packaging>jar</packaging>
-
-    <name>Hibernate JBossCache Integration</name>
-    <description>Integration of Hibernate with JBossCache (based on JBossCache1.x APIs)</description>
-
-    <dependencies>
-        <dependency>
-            <groupId>${groupId}</groupId>
-            <artifactId>hibernate-core</artifactId>
-            <version>${version}</version>
-        </dependency>
-        <dependency>
-            <groupId>jboss</groupId>
-            <artifactId>jboss-cache</artifactId>
-            <version>1.4.1.GA</version>
-        </dependency>
-        <!-- jboss-cache (the one from the jboss repo, anyway) does not properly define its dependencies -->
-        <dependency>
-            <groupId>jboss</groupId>
-            <artifactId>jboss-system</artifactId>
-            <version>4.0.2</version>
-        </dependency>
-        <dependency>
-            <groupId>jboss</groupId>
-            <artifactId>jboss-common</artifactId>
-            <version>4.0.2</version>
-        </dependency>
-        <dependency>
-            <groupId>jboss</groupId>
-            <artifactId>jboss-minimal</artifactId>
-            <version>4.0.2</version>
-        </dependency>
-        <dependency>
-            <groupId>jboss</groupId>
-            <artifactId>jboss-j2se</artifactId>
-            <version>200504122039</version>
-        </dependency>
-        <dependency>
-            <groupId>concurrent</groupId>
-            <artifactId>concurrent</artifactId>
-            <version>1.3.4</version>
-        </dependency>
-        <dependency>
-            <groupId>jgroups</groupId>
-            <artifactId>jgroups-all</artifactId>
-            <version>2.2.7</version>
-        </dependency>
-
-        <!-- testing deps -->
-        <dependency>
-            <groupId>${groupId}</groupId>
-            <artifactId>hibernate-testing</artifactId>
-            <version>${version}</version>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>hsqldb</groupId>
-            <artifactId>hsqldb</artifactId>
-            <version>1.8.0.2</version>
-            <scope>test</scope>
-        </dependency>
-        <!-- these are optional on core... :( -->
-        <dependency>
-            <groupId>javassist</groupId>
-            <artifactId>javassist</artifactId>
-            <scope>test</scope>
-        </dependency>
-        <dependency>
-            <groupId>cglib</groupId>
-            <artifactId>cglib</artifactId>
-            <scope>test</scope>
-        </dependency>
-    </dependencies>
-</project>
\ No newline at end of file
diff --git a/src/main/java/hibernate/cache/jbc/BasicRegionAdapter.java b/src/main/java/hibernate/cache/jbc/BasicRegionAdapter.java
new file mode 100644
index 0000000..b536c97
--- /dev/null
+++ b/src/main/java/hibernate/cache/jbc/BasicRegionAdapter.java
@@ -0,0 +1,580 @@
+/*
+ * 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.jbc;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicReference;
+
+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.jbc.util.CacheHelper;
+import org.hibernate.cache.jbc.util.NonLockingDataVersion;
+import org.jboss.cache.Cache;
+import org.jboss.cache.Fqn;
+import org.jboss.cache.Node;
+import org.jboss.cache.NodeSPI;
+import org.jboss.cache.config.Configuration;
+import org.jboss.cache.config.Option;
+import org.jboss.cache.config.Configuration.NodeLockingScheme;
+import org.jboss.cache.notifications.annotation.NodeInvalidated;
+import org.jboss.cache.notifications.annotation.NodeModified;
+import org.jboss.cache.notifications.annotation.ViewChanged;
+import org.jboss.cache.notifications.event.NodeInvalidatedEvent;
+import org.jboss.cache.notifications.event.NodeModifiedEvent;
+import org.jboss.cache.notifications.event.ViewChangedEvent;
+import org.jboss.cache.optimistic.DataVersion;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * General support for writing {@link Region} implementations for JBoss Cache
+ * 2.x.
+ * 
+ * @author Steve Ebersole
+ */
+public abstract class BasicRegionAdapter implements Region {
+   
+    private enum InvalidateState { INVALID, CLEARING, VALID };
+    
+    public static final String ITEM = CacheHelper.ITEM;
+
+    protected final Cache jbcCache;
+    protected final String regionName;
+    protected final Fqn regionFqn;
+    protected final Fqn internalFqn;
+    protected Node regionRoot;
+    protected final boolean optimistic;
+    protected final TransactionManager transactionManager;
+    protected final Logger log;
+    protected final Object regionRootMutex = new Object();
+    protected final Object memberId;
+    protected final boolean replication;
+    protected final Object invalidationMutex = new Object();
+    protected final AtomicReference<InvalidateState> invalidateState = 
+       new AtomicReference<InvalidateState>(InvalidateState.VALID);
+    protected final Set<Object> currentView = new HashSet<Object>();
+
+//    protected RegionRootListener listener;
+    
+    public BasicRegionAdapter(Cache jbcCache, String regionName, String regionPrefix) {
+
+        this.log = LoggerFactory.getLogger(getClass());
+        
+        this.jbcCache = jbcCache;
+        this.transactionManager = jbcCache.getConfiguration().getRuntimeConfig().getTransactionManager();
+        this.regionName = regionName;
+        this.regionFqn = createRegionFqn(regionName, regionPrefix);
+        this.internalFqn = CacheHelper.getInternalFqn(regionFqn);
+        this.optimistic = jbcCache.getConfiguration().getNodeLockingScheme() == NodeLockingScheme.OPTIMISTIC;
+        this.memberId = jbcCache.getLocalAddress();
+        this.replication = CacheHelper.isClusteredReplication(jbcCache);
+        
+        this.jbcCache.addCacheListener(this);
+        
+        synchronized (currentView) {
+           List view = jbcCache.getMembers();
+           if (view != null) {
+              currentView.addAll(view);
+           }
+        }
+        
+        activateLocalClusterNode();
+        
+        log.debug("Created Region for " + regionName + " -- regionPrefix is " + regionPrefix);
+    }
+
+    protected abstract Fqn<String> createRegionFqn(String regionName, String regionPrefix);
+
+    protected void activateLocalClusterNode() {
+       
+        // Regions can get instantiated in the course of normal work (e.g.
+        // a named query region will be created the first time the query is
+        // executed), so suspend any ongoing tx
+        Transaction tx = suspend();
+        try {
+            Configuration cfg = jbcCache.getConfiguration();
+            if (cfg.isUseRegionBasedMarshalling()) {
+                org.jboss.cache.Region jbcRegion = jbcCache.getRegion(regionFqn, true);
+                ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
+                if (classLoader == null) {
+                    classLoader = getClass().getClassLoader();
+                }
+                jbcRegion.registerContextClassLoader(classLoader);
+                if ( !jbcRegion.isActive() ) {
+                    jbcRegion.activate();
+                }
+            }
+            
+//            // If we are using replication, we may remove the root node
+//            // and then need to re-add it. In that case, the fact
+//            // that it is resident will not replicate, so use a listener
+//            // to set it as resident
+//            if (CacheHelper.isClusteredReplication(cfg.getCacheMode()) 
+//                  || CacheHelper.isClusteredInvalidation(cfg.getCacheMode())) {
+//                listener = new RegionRootListener();
+//                jbcCache.addCacheListener(listener);
+//            }
+            
+            regionRoot = jbcCache.getRoot().getChild( regionFqn );
+            if (regionRoot == null || !regionRoot.isValid()) {
+               // Establish the region root node with a non-locking data version
+               DataVersion version = optimistic ? NonLockingDataVersion.INSTANCE : null;
+               regionRoot = CacheHelper.addNode(jbcCache, regionFqn, true, true, version);
+            }
+            else if (optimistic && regionRoot instanceof NodeSPI) {
+                // FIXME Hacky workaround to JBCACHE-1202
+                if ( !( ( ( NodeSPI ) regionRoot ).getVersion() instanceof NonLockingDataVersion ) ) {
+                    ((NodeSPI) regionRoot).setVersion(NonLockingDataVersion.INSTANCE);
+                }
+            }
+            if (!regionRoot.isResident()) {
+               regionRoot.setResident(true);
+            }
+            establishInternalNodes();
+        }
+        catch (Exception e) {
+            throw new CacheException(e.getMessage(), e);
+        }
+        finally {
+            resume(tx);
+        }
+        
+    }
+
+    private void establishRegionRootNode()
+    {
+        synchronized (regionRootMutex) {
+            // If we've been blocking for the mutex, perhaps another
+            // thread has already reestablished the root.
+            // In case the node was reestablised via replication, confirm it's 
+            // marked "resident" (a status which doesn't replicate)
+            if (regionRoot != null && regionRoot.isValid()) {
+                return;
+            }
+            
+            // For pessimistic locking, we just want to toss out our ref
+            // to any old invalid root node and get the latest (may be null)            
+            if (!optimistic) {
+               establishInternalNodes();
+               regionRoot = jbcCache.getRoot().getChild( regionFqn );
+               return;
+            }
+            
+            // The rest only matters for optimistic locking, where we
+            // need to establish the proper data version on the region root
+            
+            // Don't hold a transactional lock for this 
+            Transaction tx = suspend();
+            Node newRoot = null;
+            try {
+                 // Make sure the root node for the region exists and 
+                 // has a DataVersion that never complains
+                 newRoot = jbcCache.getRoot().getChild( regionFqn );
+                 if (newRoot == null || !newRoot.isValid()) {                
+                     // Establish the region root node with a non-locking data version
+                     DataVersion version = optimistic ? NonLockingDataVersion.INSTANCE : null;
+                     newRoot = CacheHelper.addNode(jbcCache, regionFqn, true, true, version);    
+                 }
+                 else if (newRoot instanceof NodeSPI) {
+                     // FIXME Hacky workaround to JBCACHE-1202
+                     if ( !( ( ( NodeSPI ) newRoot ).getVersion() instanceof NonLockingDataVersion ) ) {
+                          ((NodeSPI) newRoot).setVersion(NonLockingDataVersion.INSTANCE);
+                     }
+                 }
+                 // Never evict this node
+                 newRoot.setResident(true);
+                 establishInternalNodes();
+            }
+            finally {
+                resume(tx);
+                regionRoot = newRoot;
+            }
+        }
+    }
+
+    private void establishInternalNodes()
+    {
+       synchronized (currentView) {
+          Transaction tx = suspend();
+          try {
+             for (Object member : currentView) {
+                DataVersion version = optimistic ? NonLockingDataVersion.INSTANCE : null;
+                Fqn f = Fqn.fromRelativeElements(internalFqn, member);
+                CacheHelper.addNode(jbcCache, f, true, false, version);
+             }
+          }
+          finally {
+             resume(tx);
+          }
+       }
+       
+    }
+
+    public String getName() {
+        return regionName;
+    }
+
+    public Cache getCacheInstance() {
+        return jbcCache;
+    }
+
+    public Fqn getRegionFqn() {
+        return regionFqn;
+    }
+    
+    public Object getMemberId()
+    {
+       return this.memberId;
+    }
+    
+    /**
+     * Checks for the validity of the root cache node for this region,
+     * creating a new one if it does not exist or is invalid, and also
+     * ensuring that the root node is marked as resident.  Suspends any 
+     * transaction while doing this to ensure no transactional locks are held 
+     * on the region root.
+     * 
+     * TODO remove this once JBCACHE-1250 is resolved.
+     */
+    public void ensureRegionRootExists() {
+       
+       if (regionRoot == null || !regionRoot.isValid())
+          establishRegionRootNode();
+       
+       // Fix up the resident flag
+       if (regionRoot != null && regionRoot.isValid() && !regionRoot.isResident())
+          regionRoot.setResident(true);
+    }
+    
+    public boolean checkValid()
+    {
+       boolean valid = invalidateState.get() == InvalidateState.VALID;
+       
+       if (!valid) {
+          synchronized (invalidationMutex) {
+             if (invalidateState.compareAndSet(InvalidateState.INVALID, InvalidateState.CLEARING)) {
+                Transaction tx = suspend();
+                try {
+                   Option opt = new Option();
+                   opt.setLockAcquisitionTimeout(1);
+                   opt.setCacheModeLocal(true);
+                   CacheHelper.removeAll(jbcCache, regionFqn, opt);
+                   invalidateState.compareAndSet(InvalidateState.CLEARING, InvalidateState.VALID);
+                }
+                catch (Exception e) {
+                   if (log.isTraceEnabled()) {
+                      log.trace("Could not invalidate region: " + e.getLocalizedMessage());
+                   }
+                }
+                finally {
+                   resume(tx);
+                }
+             }
+          }
+          valid = invalidateState.get() == InvalidateState.VALID;
+       }
+       
+       return valid;   
+    }
+
+    public void destroy() throws CacheException {
+        try {
+            // NOTE : this is being used from the process of shutting down a
+            // SessionFactory. Specific things to consider:
+            // (1) this clearing of the region should not propagate to
+            // other nodes on the cluster (if any); this is the
+            // cache-mode-local option bit...
+            // (2) really just trying a best effort to cleanup after
+            // ourselves; lock failures, etc are not critical here;
+            // this is the fail-silently option bit...
+            Option option = new Option();
+            option.setCacheModeLocal(true);
+            option.setFailSilently(true);
+            if (optimistic) {
+                option.setDataVersion(NonLockingDataVersion.INSTANCE);
+            }
+            jbcCache.getInvocationContext().setOptionOverrides(option);
+            jbcCache.removeNode(regionFqn);
+            deactivateLocalNode();            
+        } catch (Exception e) {
+            throw new CacheException(e);
+        }
+        finally {
+            jbcCache.removeCacheListener(this);
+        }
+    }
+
+    protected void deactivateLocalNode() {
+        org.jboss.cache.Region jbcRegion = jbcCache.getRegion(regionFqn, false);
+        if (jbcRegion != null && jbcRegion.isActive()) {
+            jbcRegion.deactivate();
+            jbcRegion.unregisterContextClassLoader();
+        }
+    }
+
+	public boolean contains(Object key) {
+		if ( !checkValid() ) {
+			return false;
+		}
+
+		try {
+			Option opt = new Option();
+            opt.setLockAcquisitionTimeout(100);
+            CacheHelper.setInvocationOption( jbcCache, opt );
+			return CacheHelper.getAllowingTimeout( jbcCache, regionFqn, key ) != null;
+		}
+		catch ( CacheException ce ) {
+			throw ce;
+		}
+		catch ( Throwable t ) {
+			throw new CacheException( t );
+		}
+	}
+
+    public long getSizeInMemory() {
+        // not supported
+        return -1;
+    }
+
+    public long getElementCountInMemory() {
+        if (checkValid()) {
+           try {
+               Set childrenNames = CacheHelper.getChildrenNames(jbcCache, regionFqn);
+               int size = childrenNames.size();
+               if (childrenNames.contains(CacheHelper.Internal.NODE)) {
+                  size--;
+               }
+               return size;
+           }
+		   catch ( CacheException ce ) {
+			   throw ce;
+		   }
+		   catch (Exception e) {
+               throw new CacheException(e);
+           }
+        }
+        else {
+           return 0;
+        }           
+    }
+
+    public long getElementCountOnDisk() {
+        return -1;
+    }
+
+    public Map toMap() {
+        if (checkValid()) {
+           try {
+               Map result = new HashMap();
+               Set childrenNames = CacheHelper.getChildrenNames(jbcCache, regionFqn);
+               for (Object childName : childrenNames) {
+                   if (CacheHelper.Internal.NODE != childName) {
+                      result.put(childName, CacheHelper.get(jbcCache,regionFqn, childName));
+                   }
+               }
+               return result;
+           } catch (CacheException e) {
+               throw e;
+           } catch (Exception e) {
+               throw new CacheException(e);
+           }
+        }
+        else {
+           return Collections.emptyMap();
+        }
+    }
+
+    public long nextTimestamp() {
+        return System.currentTimeMillis() / 100;
+    }
+
+    public int getTimeout() {
+        return 600; // 60 seconds
+    }
+
+    /**
+     * 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, Option opt, boolean suppressTimeout) throws CacheException {
+        Transaction tx = suspend();
+        try {
+            CacheHelper.setInvocationOption(getCacheInstance(), opt);
+            if (suppressTimeout)
+                return CacheHelper.getAllowingTimeout(getCacheInstance(), getRegionFqn(), key);
+            else
+                return CacheHelper.get(getCacheInstance(), getRegionFqn(), 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
+     */
+    public 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>.
+     */
+    public void resume(Transaction tx) {
+        try {
+            if (tx != null)
+                transactionManager.resume(tx);
+        } catch (Exception e) {
+            throw new CacheException("Could not resume transaction", e);
+        }
+    }
+
+    /**
+     * Get an Option with a {@link Option#getDataVersion() data version}
+     * of {@link NonLockingDataVersion}.  The data version will not be 
+     * set if the cache is not configured for optimistic locking.
+     * 
+     * @param allowNullReturn If <code>true</code>, return <code>null</code>
+     *                        if the cache is not using optimistic locking.
+     *                        If <code>false</code>, return a default
+     *                        {@link Option}.
+     *                        
+     * @return the Option, or <code>null</code>.
+     */
+    protected Option getNonLockingDataVersionOption(boolean allowNullReturn) {
+        return optimistic ? NonLockingDataVersion.getInvocationOption() 
+                          : (allowNullReturn) ? null : new Option();
+    }
+
+    public static Fqn<String> getTypeFirstRegionFqn(String regionName, String regionPrefix, String regionType) {
+        Fqn<String> base = Fqn.fromString(regionType);
+        Fqn<String> added = Fqn.fromString(escapeRegionName(regionName, regionPrefix));
+        return new Fqn<String>(base, added);
+    }
+
+    public static Fqn<String> getTypeLastRegionFqn(String regionName, String regionPrefix, String regionType) {
+        Fqn<String> base = Fqn.fromString(escapeRegionName(regionName, regionPrefix));
+        return new Fqn<String>(base, regionType);
+    }
+
+    public static String escapeRegionName(String regionName, String regionPrefix) {
+        String escaped = null;
+        int idx = -1;
+        if (regionPrefix != null) {
+            idx = regionName.indexOf(regionPrefix);
+        }
+
+        if (idx > -1) {
+            int regionEnd = idx + regionPrefix.length();
+            String prefix = regionName.substring(0, regionEnd);
+            String suffix = regionName.substring(regionEnd);
+            suffix = suffix.replace('.', '/');
+            escaped = prefix + suffix;
+        } else {
+            escaped = regionName.replace('.', '/');
+            if (regionPrefix != null && regionPrefix.length() > 0) {
+                escaped = regionPrefix + "/" + escaped;
+            }
+        }
+        return escaped;
+    }
+    
+    @NodeModified
+    public void nodeModified(NodeModifiedEvent event)
+    {
+       handleEvictAllModification(event);
+    }
+    
+    protected boolean handleEvictAllModification(NodeModifiedEvent event) {
+       
+       if (!event.isPre() && (replication || event.isOriginLocal()) && event.getData().containsKey(ITEM))
+       {
+          if (event.getFqn().isChildOf(internalFqn))
+          {
+             invalidateState.set(InvalidateState.INVALID);
+             return true;
+          }
+       }
+       return false;       
+    }
+    
+    @NodeInvalidated
+    public void nodeInvalidated(NodeInvalidatedEvent event)
+    {
+       handleEvictAllInvalidation(event);
+    }
+    
+    protected boolean handleEvictAllInvalidation(NodeInvalidatedEvent event)
+    {
+       if (!event.isPre() && event.getFqn().isChildOf(internalFqn))
+       {
+          invalidateState.set(InvalidateState.INVALID);
+          return true;
+       }      
+       return false;
+    }
+    
+    @ViewChanged
+    public void viewChanged(ViewChangedEvent event) {
+       
+       synchronized (currentView) {
+          List view = event.getNewView().getMembers();
+          if (view != null) {
+             currentView.addAll(view);
+             establishInternalNodes();
+          }
+       }
+       
+    }
+   
+}
diff --git a/src/main/java/hibernate/cache/jbc/CacheInstanceManager.java b/src/main/java/hibernate/cache/jbc/CacheInstanceManager.java
new file mode 100644
index 0000000..d9dd0d3
--- /dev/null
+++ b/src/main/java/hibernate/cache/jbc/CacheInstanceManager.java
@@ -0,0 +1,91 @@
+/*
+ * 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.jbc;
+
+import java.util.Properties;
+
+import org.hibernate.cache.CacheException;
+import org.hibernate.cfg.Settings;
+import org.jboss.cache.Cache;
+
+/**
+ * Acts as a buffer from how instances of {@link Cache} are built/obtained.
+ * 
+ * @author Steve Ebersole
+ */
+public interface CacheInstanceManager {
+    /**
+     * Retrieve a handle to the {@link Cache} instance to be used for storing
+     * entity data.
+     * 
+     * @return The entity data cache instance.
+     */
+    public Cache getEntityCacheInstance();
+
+    /**
+     * Retrieve a handle to the {@link Cache} instance to be used for storing
+     * collection data.
+     * 
+     * @return The collection data cache instance.
+     */
+    public Cache getCollectionCacheInstance();
+
+    /**
+     * Retrieve a handle to the {@link Cache} instance to be used for storing
+     * query results.
+     * 
+     * @return The query result cache instance.
+     */
+    public Cache getQueryCacheInstance();
+
+    /**
+     * Retrieve a handle to the {@link Cache} instance to be used for storing
+     * timestamps.
+     * 
+     * @return The timestamps cache instance.
+     */
+    public Cache getTimestampsCacheInstance();
+
+    /**
+     * Lifecycle callback to perform any necessary initialization of the
+     * CacheInstanceManager. Called exactly once during the construction of a
+     * {@link org.hibernate.impl.SessionFactoryImpl}.
+     * 
+     * @param settings
+     *            The settings in effect.
+     * @param properties
+     *            The defined cfg properties
+     * @throws CacheException
+     *             Indicates problems starting the L2 cache impl; considered as
+     *             a sign to stop {@link org.hibernate.SessionFactory} building.
+     */
+    public void start(Settings settings, Properties properties) throws CacheException;
+
+    /**
+     * Lifecycle callback to perform any necessary cleanup of the underlying
+     * CacheInstanceManager. Called exactly once during
+     * {@link org.hibernate.SessionFactory#close}.
+     */
+    public void stop();
+}
diff --git a/src/main/java/hibernate/cache/jbc/JBossCacheRegionFactory.java b/src/main/java/hibernate/cache/jbc/JBossCacheRegionFactory.java
new file mode 100644
index 0000000..fe1808e
--- /dev/null
+++ b/src/main/java/hibernate/cache/jbc/JBossCacheRegionFactory.java
@@ -0,0 +1,164 @@
+/*
+ * 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.jbc;
+
+import java.util.Properties;
+
+import org.hibernate.cache.CacheDataDescription;
+import org.hibernate.cache.CacheException;
+import org.hibernate.cache.CollectionRegion;
+import org.hibernate.cache.EntityRegion;
+import org.hibernate.cache.QueryResultsRegion;
+import org.hibernate.cache.RegionFactory;
+import org.hibernate.cache.TimestampsRegion;
+import org.hibernate.cache.access.AccessType;
+import org.hibernate.cache.jbc.builder.JndiSharedCacheInstanceManager;
+import org.hibernate.cache.jbc.builder.SharedCacheInstanceManager;
+import org.hibernate.cache.jbc.collection.CollectionRegionImpl;
+import org.hibernate.cache.jbc.entity.EntityRegionImpl;
+import org.hibernate.cache.jbc.query.QueryResultsRegionImpl;
+import org.hibernate.cache.jbc.timestamp.TimestampsRegionImpl;
+import org.hibernate.cfg.Environment;
+import org.hibernate.cfg.Settings;
+import org.hibernate.util.PropertiesHelper;
+import org.jboss.cache.DefaultCacheFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * {@link RegionFactory} that uses one or more JBoss Cache instances for 
+ * caching entities, collections, queries and timestamps. How the factory
+ * obtains a reference to the needed JBoss Cache instance(s) is determined
+ * by the injected {@link CacheInstanceManager}.
+ * <p>
+ * By default uses {@link SharedCacheInstanceManager} as its
+ * {@link #getCacheInstanceManager() CacheInstanceManager}.
+ * Basically, this uses a single shared JBoss Cache for entities, collections,
+ * queries and timestamps. The JBoss Cache instance is created by the
+ * JBC {@link DefaultCacheFactory} using the resource identified by the
+ * {@link JndiSharedCacheInstanceManager#CACHE_RESOURCE_PROP}
+ * configuration property. 
+ * </p>
+ * <p>
+ * Also exposes an overloaded constructor that allows injection of different
+ * <code>CacheInstanceManager</code> implementations.
+ * </p>
+ *
+ * @deprecated Favor Infinispan integration; see HHH-5489 for details.
+ * 
+ * @author Steve Ebersole
+ * @author Brian Stansberry
+ */
+ at Deprecated
+public class JBossCacheRegionFactory implements RegionFactory {
+	private static final Logger log = LoggerFactory.getLogger( JBossCacheRegionFactory.class );
+    private CacheInstanceManager cacheInstanceManager;
+
+    /**
+     * FIXME Per the RegionFactory class Javadoc, this constructor version
+     * should not be necessary.
+     * 
+     * @param props The configuration properties
+     */
+    public JBossCacheRegionFactory(Properties props) {
+        this();
+    }
+
+    /**
+     *  Create a new JBossCacheRegionFactory.
+     */
+    public JBossCacheRegionFactory() {
+		log.warn( "Integration with JBossCache is deprecated in favor of Infinispan" );
+    }
+
+    /**
+     * Create a new JBossCacheRegionFactory that uses the provided
+     * {@link CacheInstanceManager}.
+     * 
+     * @param cacheInstanceManager The contract for how we get JBC cache instances.
+     */
+    public JBossCacheRegionFactory(CacheInstanceManager cacheInstanceManager) {
+        this.cacheInstanceManager = cacheInstanceManager;
+		log.warn( "Integration with JBossCache is deprecated in favor of Infinispan" );
+    }
+
+    public CacheInstanceManager getCacheInstanceManager() {
+        return cacheInstanceManager;
+    }
+
+    public void start(Settings settings, Properties properties) throws CacheException {
+        if (cacheInstanceManager == null) {
+            cacheInstanceManager = new SharedCacheInstanceManager();
+        }
+
+        cacheInstanceManager.start(settings, properties);
+    }
+
+    public void stop() {
+        if (cacheInstanceManager != null) {
+            cacheInstanceManager.stop();
+        }
+    }
+
+    public boolean isMinimalPutsEnabledByDefault() {
+        return true;
+    }
+
+	public AccessType getDefaultAccessType() {
+		return AccessType.TRANSACTIONAL;
+	}
+
+	public long nextTimestamp() {
+        return System.currentTimeMillis() / 100;
+    }
+
+    public EntityRegion buildEntityRegion(String regionName, Properties properties, CacheDataDescription metadata)
+            throws CacheException {
+        return new EntityRegionImpl(cacheInstanceManager.getEntityCacheInstance(), regionName,
+                getRegionPrefix(properties), metadata);
+    }
+
+    public CollectionRegion buildCollectionRegion(String regionName, Properties properties,
+            CacheDataDescription metadata) throws CacheException {
+        return new CollectionRegionImpl(cacheInstanceManager.getCollectionCacheInstance(), regionName,
+                getRegionPrefix(properties), metadata);
+    }
+
+    public QueryResultsRegion buildQueryResultsRegion(String regionName, Properties properties) throws CacheException {
+
+        return new QueryResultsRegionImpl(cacheInstanceManager.getQueryCacheInstance(), regionName,
+                getRegionPrefix(properties), properties);
+    }
+
+    public TimestampsRegion buildTimestampsRegion(String regionName, Properties properties) throws CacheException {
+
+        return new TimestampsRegionImpl(cacheInstanceManager.getTimestampsCacheInstance(), regionName,
+                getRegionPrefix(properties), properties);
+    }
+
+    public static String getRegionPrefix(Properties properties) {
+        return PropertiesHelper.getString(Environment.CACHE_REGION_PREFIX, properties, null);
+    }
+
+}
diff --git a/src/main/java/hibernate/cache/jbc/JndiMultiplexedJBossCacheRegionFactory.java b/src/main/java/hibernate/cache/jbc/JndiMultiplexedJBossCacheRegionFactory.java
new file mode 100644
index 0000000..d13f7ce
--- /dev/null
+++ b/src/main/java/hibernate/cache/jbc/JndiMultiplexedJBossCacheRegionFactory.java
@@ -0,0 +1,74 @@
+/*
+ * 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.jbc;
+
+import java.util.Properties;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.hibernate.cache.jbc.builder.JndiMultiplexingCacheInstanceManager;
+
+/**
+ * {@link JBossCacheRegionFactory} that uses
+ * {@link JndiMultiplexingCacheInstanceManager} as its
+ * {@link #getCacheInstanceManager() CacheInstanceManager}.
+ * <p>
+ * Supports separate JBoss Cache instances for entity, collection, query
+ * and timestamp caching, with the expectation that a single multiplexed JGroups 
+ * resource (i.e. a multiplexed channel or a shared transport channel) will be 
+ * shared between the caches. JBoss Cache instances are created from a factory.
+ * </p>
+ * <p>
+ * This version finds the factory in JNDI. See 
+ * {@link JndiMultiplexingCacheInstanceManager} for configuration details. 
+ * </p>
+ *
+ * @deprecated Favor Infinispan integration; see HHH-5489 for details.
+ *
+ * @author Brian Stansberry
+ * @version $Revision$
+ */
+ at Deprecated
+public class JndiMultiplexedJBossCacheRegionFactory extends JBossCacheRegionFactory {
+
+    /**
+     * FIXME Per the RegionFactory class Javadoc, this constructor version
+     * should not be necessary.
+     * 
+     * @param props The configuration properties
+     */
+    public JndiMultiplexedJBossCacheRegionFactory(Properties props) {
+        this();
+    }
+
+    /**
+     * Create a new MultiplexedJBossCacheRegionFactory.
+     * 
+     */
+    public JndiMultiplexedJBossCacheRegionFactory() {
+        super(new JndiMultiplexingCacheInstanceManager());
+    }
+
+}
diff --git a/src/main/java/hibernate/cache/jbc/JndiSharedJBossCacheRegionFactory.java b/src/main/java/hibernate/cache/jbc/JndiSharedJBossCacheRegionFactory.java
new file mode 100644
index 0000000..12f55cf
--- /dev/null
+++ b/src/main/java/hibernate/cache/jbc/JndiSharedJBossCacheRegionFactory.java
@@ -0,0 +1,67 @@
+/*
+ * 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.jbc;
+
+import java.util.Properties;
+
+import org.hibernate.cache.jbc.builder.JndiSharedCacheInstanceManager;
+
+/**
+ * {@link JBossCacheRegionFactory} that uses
+ * {@link JndiSharedCacheInstanceManager} as its
+ * {@link #getCacheInstanceManager() CacheInstanceManager}.
+ * <p>
+ * Basically, uses a single shared JBoss Cache for entities, collections,
+ * queries and timestamps. The JBoss Cache instance is found in JNDI
+ * using the value of the {@link JndiSharedCacheInstanceManager#CACHE_RESOURCE_PROP}
+ * configuration property as the name to look up. 
+ * </p>
+ *
+ * @deprecated Favor Infinispan integration; see HHH-5489 for details.
+ * 
+ * @author Brian Stansberry
+ * @version $Revision$
+ */
+ at Deprecated
+public class JndiSharedJBossCacheRegionFactory extends JBossCacheRegionFactory {
+
+    /**
+     * FIXME Per the RegionFactory class Javadoc, this constructor version
+     * should not be necessary.
+     * 
+     * @param props The configuration properties
+     */
+    public JndiSharedJBossCacheRegionFactory(Properties props) {
+        this();
+    }
+
+    /**
+     * Create a new MultiplexedJBossCacheRegionFactory.
+     * 
+     */
+    public JndiSharedJBossCacheRegionFactory() {
+        super(new JndiSharedCacheInstanceManager());
+    }
+
+}
diff --git a/src/main/java/hibernate/cache/jbc/MultiplexedJBossCacheRegionFactory.java b/src/main/java/hibernate/cache/jbc/MultiplexedJBossCacheRegionFactory.java
new file mode 100644
index 0000000..a3b3ec4
--- /dev/null
+++ b/src/main/java/hibernate/cache/jbc/MultiplexedJBossCacheRegionFactory.java
@@ -0,0 +1,71 @@
+/*
+ * 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.jbc;
+
+import java.util.Properties;
+
+import org.hibernate.cache.jbc.builder.MultiplexingCacheInstanceManager;
+
+/**
+ * {@link JBossCacheRegionFactory} that uses
+ * {@link MultiplexingCacheInstanceManager} as its
+ * {@link #getCacheInstanceManager() CacheInstanceManager}.
+ * <p>
+ * Supports separate JBoss Cache instances for entity, collection, query
+ * and timestamp caching, with the expectation that a single JGroups resource 
+ * (i.e. a multiplexed channel or a shared transport channel) will be shared 
+ * between the caches. JBoss Cache instances are created from a factory.
+ * </p>
+ * <p>
+ * This version instantiates the factory itself. See 
+ * {@link MultiplexingCacheInstanceManager} for configuration details. 
+ * </p>
+ *
+ * @deprecated Favor Infinispan integration; see HHH-5489 for details.
+ *
+ * @author Brian Stansberry
+ * @version $Revision$
+ */
+ at Deprecated
+public class MultiplexedJBossCacheRegionFactory extends JBossCacheRegionFactory {
+
+    /**
+     * FIXME Per the RegionFactory class Javadoc, this constructor version
+     * should not be necessary.
+     * 
+     * @param props The configuration properties
+     */
+    public MultiplexedJBossCacheRegionFactory(Properties props) {
+        this();
+    }
+
+    /**
+     * Create a new MultiplexedJBossCacheRegionFactory.
+     * 
+     */
+    public MultiplexedJBossCacheRegionFactory() {
+        super(new MultiplexingCacheInstanceManager());
+    }
+
+}
diff --git a/src/main/java/hibernate/cache/jbc/SharedJBossCacheRegionFactory.java b/src/main/java/hibernate/cache/jbc/SharedJBossCacheRegionFactory.java
new file mode 100644
index 0000000..63c78f3
--- /dev/null
+++ b/src/main/java/hibernate/cache/jbc/SharedJBossCacheRegionFactory.java
@@ -0,0 +1,72 @@
+/*
+ * 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.jbc;
+
+import java.util.Properties;
+
+import org.hibernate.cache.jbc.builder.JndiSharedCacheInstanceManager;
+import org.hibernate.cache.jbc.builder.SharedCacheInstanceManager;
+import org.jboss.cache.DefaultCacheFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * {@link JBossCacheRegionFactory} that uses
+ * {@link SharedCacheInstanceManager} as its
+ * {@link #getCacheInstanceManager() CacheInstanceManager}.
+ * <p>
+ * Basically, uses a single shared JBoss Cache for entities, collections,
+ * queries and timestamps. The JBoss Cache instance created by the
+ * JBC {@link DefaultCacheFactory} using the resource identified by the
+ * {@link JndiSharedCacheInstanceManager#CACHE_RESOURCE_PROP}
+ * configuration property. 
+ * </p>
+ *
+ * @deprecated Favor Infinispan integration; see HHH-5489 for details.
+ *
+ * @author Brian Stansberry
+ * @version $Revision$
+ */
+ at Deprecated
+public class SharedJBossCacheRegionFactory extends JBossCacheRegionFactory {
+
+    /**
+     * FIXME Per the RegionFactory class Javadoc, this constructor version
+     * should not be necessary.
+     * 
+     * @param props The configuration properties
+     */
+    public SharedJBossCacheRegionFactory(Properties props) {
+        this();
+    }
+
+    /**
+     * Create a new MultiplexedJBossCacheRegionFactory.
+     * 
+     */
+    public SharedJBossCacheRegionFactory() {
+        super(new SharedCacheInstanceManager());
+    }
+
+}
diff --git a/src/test/java/org/hibernate/cache/PessimisticTreeCacheTest.java b/src/main/java/hibernate/cache/jbc/TransactionalDataRegionAdapter.java
similarity index 53%
copy from src/test/java/org/hibernate/cache/PessimisticTreeCacheTest.java
copy to src/main/java/hibernate/cache/jbc/TransactionalDataRegionAdapter.java
index a16245b..e592cd5 100644
--- a/src/test/java/org/hibernate/cache/PessimisticTreeCacheTest.java
+++ b/src/main/java/hibernate/cache/jbc/TransactionalDataRegionAdapter.java
@@ -21,44 +21,40 @@
  * 51 Franklin Street, Fifth Floor
  * Boston, MA  02110-1301  USA
  */
-package org.hibernate.cache;
+package org.hibernate.cache.jbc;
 
-import junit.framework.Test;
-
-import org.hibernate.cfg.Environment;
-import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
-import org.hibernate.test.cache.BaseCacheProviderTestCase;
+import org.hibernate.cache.CacheDataDescription;
+import org.hibernate.cache.TransactionalDataRegion;
+import org.jboss.cache.Cache;
 
 /**
+ * {@inheritDoc}
+ * 
  * @author Steve Ebersole
  */
-public class PessimisticTreeCacheTest extends BaseCacheProviderTestCase {
-	public PessimisticTreeCacheTest(String x) {
-		super( x );
-	}
-
-	public static Test suite() {
-		return new FunctionalTestClassTestSuite( PessimisticTreeCacheTest.class );
-	}
-
-	public String getCacheConcurrencyStrategy() {
-		return "transactional";
-	}
-
-	protected Class getCacheProvider() {
-		return TreeCacheProvider.class;
-	}
-
-	protected String getConfigResourceKey() {
-		return Environment.CACHE_PROVIDER_CONFIG;
-	}
-
-	protected String getConfigResourceLocation() {
-		return "treecache-pessimistic.xml";
-	}
-
-	protected boolean useTransactionManager() {
-		return true;
-	}
+public abstract class TransactionalDataRegionAdapter extends BasicRegionAdapter implements TransactionalDataRegion {
+
+    protected final CacheDataDescription metadata;
+
+    public TransactionalDataRegionAdapter(Cache jbcCache, String regionName, String regionPrefix,
+            CacheDataDescription metadata) {
+        super(jbcCache, regionName, regionPrefix);
+        this.metadata = metadata;
+    }
+
+    /**
+     * Here, for JBossCache, we consider the cache to be transaction aware if
+     * the underlying cache instance has a reference to the transaction manager.
+     */
+    public boolean isTransactionAware() {
+        return transactionManager != null;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public CacheDataDescription getCacheDataDescription() {
+        return metadata;
+    }
 
 }
diff --git a/src/main/java/hibernate/cache/jbc/access/OptimisticTransactionalAccessDelegate.java b/src/main/java/hibernate/cache/jbc/access/OptimisticTransactionalAccessDelegate.java
new file mode 100644
index 0000000..2ae9995
--- /dev/null
+++ b/src/main/java/hibernate/cache/jbc/access/OptimisticTransactionalAccessDelegate.java
@@ -0,0 +1,212 @@
+/*
+ * 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.jbc.access;
+
+import javax.transaction.Transaction;
+
+import org.hibernate.cache.CacheDataDescription;
+import org.hibernate.cache.CacheException;
+import org.hibernate.cache.access.CollectionRegionAccessStrategy;
+import org.hibernate.cache.access.EntityRegionAccessStrategy;
+import org.hibernate.cache.jbc.TransactionalDataRegionAdapter;
+import org.hibernate.cache.jbc.util.CacheHelper;
+import org.hibernate.cache.jbc.util.DataVersionAdapter;
+import org.hibernate.cache.jbc.util.NonLockingDataVersion;
+import org.jboss.cache.config.Option;
+
+/**
+ * Defines the strategy for transactional access to entity or collection data in
+ * an optimistic-locking JBoss Cache using its 2.x APIs.
+ * <p>
+ * The intent of this class is to encapsulate common code and serve as a
+ * delegate for {@link EntityRegionAccessStrategy} and
+ * {@link CollectionRegionAccessStrategy} implementations.
+ * </p>
+ * 
+ * @author Brian Stansberry
+ * @version $Revision: 1 $
+ */
+public class OptimisticTransactionalAccessDelegate extends TransactionalAccessDelegate {
+
+    protected final CacheDataDescription dataDescription;
+
+    public OptimisticTransactionalAccessDelegate(TransactionalDataRegionAdapter region, PutFromLoadValidator validator) {
+        super(region, validator);
+        this.dataDescription = region.getCacheDataDescription();
+    }
+
+    /**
+     * Overrides the
+     * {@link TransactionalAccessDelegate#evict(Object) superclass} by adding a
+     * {@link NonLockingDataVersion} to the invocation.
+     */
+    @Override
+    public void evict(Object key) throws CacheException {
+    	if (!putValidator.invalidateKey(key)) {
+    		throw new CacheException("Failed to invalidate pending putFromLoad calls for key " + key + " from region " + region.getName());
+    	}
+        region.ensureRegionRootExists();
+
+        Option opt = NonLockingDataVersion.getInvocationOption();
+        CacheHelper.remove(cache, regionFqn, key, opt);
+    } 
+    
+    
+
+    @Override
+    public void evictAll() throws CacheException
+    {
+    	if (!putValidator.invalidateRegion()) {
+     	   throw new CacheException("Failed to invalidate pending putFromLoad calls for region " + region.getName());
+        }        
+       
+       Transaction tx = region.suspend();
+       try {        
+          region.ensureRegionRootExists();
+          Option opt = NonLockingDataVersion.getInvocationOption();
+          CacheHelper.sendEvictAllNotification(cache, regionFqn, region.getMemberId(), opt);
+       }
+       finally {
+          region.resume(tx);
+       }
+    }
+
+   /**
+     * Overrides the
+     * {@link TransactionalAccessDelegate#insert(Object, Object, Object) superclass}
+     * by adding a {@link DataVersion} to the invocation.
+     */
+    @Override
+    public boolean insert(Object key, Object value, Object version) throws CacheException {
+       
+        if (!region.checkValid())
+            return false;
+        
+        region.ensureRegionRootExists();
+
+        Option opt = getDataVersionOption(version, null);
+        if (this.invalidation) {
+        	opt.setCacheModeLocal(true);
+        }
+        CacheHelper.put(cache, regionFqn, key, value, opt);
+        return true;
+    }
+
+    @Override
+    public boolean putFromLoad(Object key, Object value, long txTimestamp, Object version, boolean minimalPutOverride)
+            throws CacheException {
+       
+        if (!region.checkValid())
+            return false;
+        
+        if (!putValidator.acquirePutFromLoadLock(key))
+           return false;
+        
+        try {
+	        region.ensureRegionRootExists();
+	
+	        // We ignore minimalPutOverride. JBossCache putForExternalRead is
+	        // already about as minimal as we can get; it will promptly return
+	        // if it discovers that the node we want to write to already exists
+	        Option opt = getDataVersionOption(version, version);
+	        return CacheHelper.putForExternalRead(cache, regionFqn, key, value, opt);
+        }
+        finally {
+        	putValidator.releasePutFromLoadLock(key);
+        }
+    }
+
+    @Override
+    public boolean putFromLoad(Object key, Object value, long txTimestamp, Object version) throws CacheException {
+       
+        if (!region.checkValid())
+            return false;
+        
+        if (!putValidator.acquirePutFromLoadLock(key))
+           return false;
+        
+        try {
+	        region.ensureRegionRootExists();
+	
+	        Option opt = getDataVersionOption(version, version);
+	        return CacheHelper.putForExternalRead(cache, regionFqn, key, value, opt);
+        }
+        finally {
+        	putValidator.releasePutFromLoadLock(key);
+        }
+    }
+
+    @Override
+    public void remove(Object key) throws CacheException {
+       
+    	if (!putValidator.invalidateKey(key)) {
+    		throw new CacheException("Failed to invalidate pending putFromLoad calls for key " + key + " from region " + region.getName());
+    	}
+        
+        // We remove whether or not the region is valid. Other nodes
+        // may have already restored the region so they need to
+        // be informed of the change.
+        
+        region.ensureRegionRootExists();
+
+        Option opt = NonLockingDataVersion.getInvocationOption();
+        CacheHelper.remove(cache, regionFqn, key, opt);
+    }
+
+    @Override
+    public void removeAll() throws CacheException {
+       if (!putValidator.invalidateRegion()) {
+    	   throw new CacheException("Failed to invalidate pending putFromLoad calls for region " + region.getName());
+       }
+       Option opt = NonLockingDataVersion.getInvocationOption();
+       CacheHelper.removeAll(cache, regionFqn, opt);
+    }
+
+    @Override
+    public boolean update(Object key, Object value, Object currentVersion, Object previousVersion)
+            throws CacheException {
+       
+        // We update whether or not the region is valid. Other nodes
+        // may have already restored the region so they need to
+        // be informed of the change.
+        
+        region.ensureRegionRootExists();
+
+        Option opt = getDataVersionOption(currentVersion, previousVersion);
+        CacheHelper.put(cache, regionFqn, key, value, opt);
+        return true;
+    }
+
+    @SuppressWarnings("deprecation")
+    private Option getDataVersionOption(Object currentVersion, Object previousVersion) {
+        
+       org.jboss.cache.optimistic.DataVersion dv = (dataDescription != null && dataDescription.isVersioned()) ? new DataVersionAdapter(
+                currentVersion, previousVersion, dataDescription.getVersionComparator(), dataDescription.toString())
+                : NonLockingDataVersion.INSTANCE;
+        Option opt = new Option();
+        opt.setDataVersion(dv);
+        return opt;
+    }
+
+}
diff --git a/src/main/java/hibernate/cache/jbc/access/PutFromLoadValidator.java b/src/main/java/hibernate/cache/jbc/access/PutFromLoadValidator.java
new file mode 100644
index 0000000..c68d45f
--- /dev/null
+++ b/src/main/java/hibernate/cache/jbc/access/PutFromLoadValidator.java
@@ -0,0 +1,744 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2009, Red Hat, Inc or third-party contributors as
+ * indicated by the @author tags or express copyright attribution
+ * statements applied by the authors.  All third-party contributions are
+ * distributed under license by Red Hat Middleware LLC.
+ *
+ * This copyrighted material is made available to anyone wishing to use, modify,
+ * copy, or redistribute it subject to the terms and conditions of the GNU
+ * Lesser General Public License, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this distribution; if not, write to:
+ * Free Software Foundation, Inc.
+ * 51 Franklin Street, Fifth Floor
+ * Boston, MA  02110-1301  USA
+ */
+package org.hibernate.cache.jbc.access;
+
+import java.lang.ref.WeakReference;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantLock;
+
+import javax.transaction.SystemException;
+import javax.transaction.Transaction;
+import javax.transaction.TransactionManager;
+
+import org.hibernate.cache.CacheException;
+
+/**
+ * Encapsulates logic to allow a {@link TransactionalAccessDelegate} to determine
+ * whether a {@link TransactionalAccessDelegate#putFromLoad(Object, Object, long, Object, boolean)
+ * call should be allowed to update the cache. A <code>putFromLoad</code> has
+ * the potential to store stale data, since the data may have been removed from the
+ * database and the cache between the time when the data was read from the database 
+ * and the actual call to <code>putFromLoad</code>.
+ * <p>
+ * The expected usage of this class by a thread that read the cache and did
+ * not find data is:
+ * 
+ * <ol>
+ * <li> Call {@link #registerPendingPut(Object)}</li>
+ * <li> Read the database</li>
+ * <li> Call {@link #acquirePutFromLoadLock(Object)}
+ * <li> if above returns <code>false</code>, the thread should not cache the data;
+ *      only if above returns <code>true</code>, put data in the cache and...</li>
+ * <li> then call {@link #releasePutFromLoadLock(Object)}</li>
+ * </ol>
+ * </p>
+ * 
+ * <p>
+ * The expected usage by a thread that is taking an action such that any pending
+ * <code>putFromLoad</code> may have stale data and should not cache it is to either
+ * call
+ * 
+ * <ul>
+ * <li> {@link #invalidateKey(Object)} (for a single key invalidation)</li>
+ * <li>or {@link #invalidateRegion()} (for a general invalidation all pending puts)</li>
+ * </ul>
+ * </p>
+ * 
+ * <p>
+ * This class also supports the concept of "naked puts", which are calls to
+ * {@link #acquirePutFromLoadLock(Object)} without a preceding {@link #registerPendingPut(Object)}
+ * call. 
+ * </p>
+ *
+ * @author Brian Stansberry
+ * 
+ * @version $Revision: $
+ */
+public class PutFromLoadValidator {
+	/**
+	 * Period in ms after a removal during which a call to
+	 * {@link #acquirePutFromLoadLock(Object)} that hasn't been
+	 * {@link #registerPendingPut(Object) pre-registered} (aka a "naked put")
+	 * will return false.
+	 */
+	public static final long NAKED_PUT_INVALIDATION_PERIOD = 20 * 1000;
+
+	/** Period (in ms) after which a pending put is placed in the over-age queue */
+	private static final long PENDING_PUT_OVERAGE_PERIOD = 5 * 1000;
+
+	/** Period (in ms) before which we stop trying to clean out pending puts */
+	private static final long PENDING_PUT_RECENT_PERIOD = 2 * 1000;
+
+	/**
+	 * Period (in ms) after which a pending put is never expected to come in 
+	 * and should be cleaned
+	 */
+	private static final long MAX_PENDING_PUT_DELAY = 2 * 60 * 1000;
+
+	/**
+	 * Used to determine whether the owner of a pending put is a thread or a
+	 * transaction
+	 */
+	private final TransactionManager transactionManager;
+
+	private final long nakedPutInvalidationPeriod;
+	private final long pendingPutOveragePeriod;
+	private final long pendingPutRecentPeriod;
+	private final long maxPendingPutDelay;
+
+	/**
+	 * Registry of expected, future, isPutValid calls. If a key+owner is
+	 * registered in this map, it is not a "naked put" and is allowed to
+	 * proceed.
+	 */
+	private final ConcurrentMap<Object, PendingPutMap> pendingPuts = new ConcurrentHashMap<Object, PendingPutMap>();
+	/**
+	 * List of pending puts. Used to ensure we don't leak memory via the
+	 * pendingPuts map
+	 */
+	private final List<WeakReference<PendingPut>> pendingQueue = new LinkedList<WeakReference<PendingPut>>();
+	/**
+	 * Separate list of pending puts that haven't been resolved within
+	 * PENDING_PUT_OVERAGE_PERIOD. Used to ensure we don't leak memory via the
+	 * pendingPuts map. Tracked separately from more recent pending puts for
+	 * efficiency reasons.
+	 */
+	private final List<WeakReference<PendingPut>> overagePendingQueue = new LinkedList<WeakReference<PendingPut>>();
+	/** Lock controlling access to pending put queues */
+	private final Lock pendingLock = new ReentrantLock();
+	private final ConcurrentMap<Object, Long> recentRemovals = new ConcurrentHashMap<Object, Long>();
+	/**
+	 * List of recent removals. Used to ensure we don't leak memory via the
+	 * recentRemovals map
+	 */
+	private final List<RecentRemoval> removalsQueue = new LinkedList<RecentRemoval>();
+	/**
+	 * The time when the first element in removalsQueue will expire. No reason
+	 * to do housekeeping on the queue before this time.
+	 */
+	private volatile long earliestRemovalTimestamp;
+	/** Lock controlling access to removalsQueue */
+	private final Lock removalsLock = new ReentrantLock();
+
+	/**
+	 * The time of the last call to regionRemoved(), plus
+	 * NAKED_PUT_INVALIDATION_PERIOD. All naked puts will be rejected until the
+	 * current time is greater than this value.
+	 */
+	private volatile long invalidationTimestamp;
+
+	/**
+	 * Creates a new PutFromLoadValidator.
+	 * 
+	 * @param transactionManager
+	 *            transaction manager to use to associate changes with a
+	 *            transaction; may be <code>null</code>
+	 */
+	public PutFromLoadValidator(TransactionManager transactionManager) {
+		this(transactionManager, NAKED_PUT_INVALIDATION_PERIOD,
+				PENDING_PUT_OVERAGE_PERIOD, PENDING_PUT_RECENT_PERIOD,
+				MAX_PENDING_PUT_DELAY);
+	}
+
+	/**
+	 * Constructor variant for use by unit tests; allows control of various
+	 * timeouts by the test.
+	 */
+	protected PutFromLoadValidator(TransactionManager transactionManager,
+			long nakedPutInvalidationPeriod, long pendingPutOveragePeriod,
+			long pendingPutRecentPeriod, long maxPendingPutDelay) {
+		this.transactionManager = transactionManager;
+		this.nakedPutInvalidationPeriod = nakedPutInvalidationPeriod;
+		this.pendingPutOveragePeriod = pendingPutOveragePeriod;
+		this.pendingPutRecentPeriod = pendingPutRecentPeriod;
+		this.maxPendingPutDelay = maxPendingPutDelay;
+	}
+
+	// ----------------------------------------------------------------- Public
+
+	/**
+	 * Acquire a lock giving the calling thread the right to put data in the
+	 * cache for the given key.
+	 * <p>
+	 * <strong>NOTE:</strong> A call to this method that returns <code>true</code>
+	 * should always be matched with a call to {@link #releasePutFromLoadLock(Object)}.
+	 * </p>
+	 * 
+	 * @param key the key
+	 * 
+	 * @return <code>true</code> if the lock is acquired and the cache put
+	 *         can proceed; <code>false</code> if the data should not be cached
+	 */
+	public boolean acquirePutFromLoadLock(Object key) {	
+		
+		boolean valid = false;
+		boolean locked = false;
+		long now = System.currentTimeMillis();
+
+		// Important: Do cleanup before we acquire any locks so we
+		// don't deadlock with invalidateRegion
+		cleanOutdatedPendingPuts(now, true);
+		
+		try {
+			PendingPutMap pending = pendingPuts.get(key);
+			if (pending != null) {
+				locked = pending.acquireLock(100, TimeUnit.MILLISECONDS);
+				if (locked) {
+					try {
+						PendingPut toCancel = pending.remove(getOwnerForPut());
+						if (toCancel != null) {  
+							valid = !toCancel.completed;
+							toCancel.completed = true;
+						}
+					}
+					finally {
+						if (!valid) {
+							pending.releaseLock();
+							locked = false;
+						}
+					}
+				}
+			}
+			else {
+				// Key wasn't in pendingPuts, so either this is a "naked put"
+				// or regionRemoved has been called. Check if we can proceed
+				if (now > invalidationTimestamp) {
+					Long removedTime = recentRemovals.get(key);
+					if (removedTime == null || now > removedTime.longValue()) {
+						// It's legal to proceed. But we have to record this key
+						// in pendingPuts so releasePutFromLoadLock can find it.
+						// To do this we basically simulate a normal "register
+						// then acquire lock" pattern
+						registerPendingPut(key);
+						locked = acquirePutFromLoadLock(key);
+						valid = locked;
+					}
+				}
+			}			
+		}
+		catch (Throwable t) {
+			
+			valid = false;
+			
+			if (locked) {
+				PendingPutMap toRelease = pendingPuts.get(key);
+				if (toRelease != null) {
+					toRelease.releaseLock();
+				}
+			}
+			
+			if (t instanceof RuntimeException) {
+				throw (RuntimeException) t;
+			}			
+			else if (t instanceof Error) {
+				throw (Error) t;
+			}			
+			else {
+				throw new RuntimeException(t);
+			}
+		}
+		
+		return valid;
+	}
+	
+	/**
+	 * Releases the lock previously obtained by a call to
+	 * {@link #acquirePutFromLoadLock(Object)} that returned <code>true</code>.
+	 * 
+	 * @param key the key
+	 */
+	public void releasePutFromLoadLock(Object key) {
+		PendingPutMap pending = pendingPuts.get(key);
+		if (pending != null) {
+			if (pending.size() == 0) {
+				pendingPuts.remove(key);
+			}
+			pending.releaseLock();
+		}
+	}
+
+	/**
+	 * Invalidates any {@link #registerPendingPut(Object) previously registered pending puts} 
+	 * ensuring a subsequent call to {@link #acquirePutFromLoadLock(Object)} will
+	 * return <code>false</code>.
+	 * <p>
+	 * This method will block until any concurrent thread that has 
+	 * {@link #acquirePutFromLoadLock(Object) acquired the putFromLoad lock} for
+	 * the given key has released the lock. This allows the caller to be certain
+	 * the putFromLoad will not execute after this method returns, possibly
+	 * caching stale data.
+	 * </p>
+	 * 
+	 * @param key key identifying data whose pending puts should be invalidated
+	 * 
+	 * @return <code>true</code> if the invalidation was successful; <code>false</code>
+	 *         if a problem occured (which the caller should treat as an
+	 *         exception condition)
+	 */
+	public boolean invalidateKey(Object key) {
+		
+		boolean success = true;
+		
+		// Invalidate any pending puts
+		PendingPutMap pending = pendingPuts.get(key);		
+		if (pending != null) {
+			// This lock should be available very quickly, but we'll be
+			// very patient waiting for it as callers should treat not
+			// acquiring it as an exception condition
+			if (pending.acquireLock(60, TimeUnit.SECONDS)) {
+				try {
+					pending.invalidate();
+				}
+				finally {
+					pending.releaseLock();
+				}
+			}
+			else {
+				success = false;
+			}
+		}
+
+		// Record when this occurred to invalidate later naked puts
+		RecentRemoval removal = new RecentRemoval(key,
+				this.nakedPutInvalidationPeriod);
+		recentRemovals.put(key, removal.timestamp);
+
+		// Don't let recentRemovals map become a memory leak
+		RecentRemoval toClean = null;
+		boolean attemptClean = removal.timestamp.longValue() > earliestRemovalTimestamp;
+		removalsLock.lock();
+		try {
+			removalsQueue.add(removal);
+
+			if (attemptClean) {
+				if (removalsQueue.size() > 1) { // we have at least one as we
+												// just added it
+					toClean = removalsQueue.remove(0);
+				}
+				earliestRemovalTimestamp = removalsQueue.get(0).timestamp
+						.longValue();
+			}
+		} finally {
+			removalsLock.unlock();
+		}
+
+		if (toClean != null) {
+			Long cleaned = recentRemovals.get(toClean.key);
+			if (cleaned != null && cleaned.equals(toClean.timestamp)) {
+				cleaned = recentRemovals.remove(toClean.key);
+				if (cleaned != null
+						&& cleaned.equals(toClean.timestamp) == false) {
+					// Oops; removed the wrong timestamp; restore it
+					recentRemovals.putIfAbsent(toClean.key, cleaned);
+				}
+			}
+		}
+		
+		return success;
+	}
+
+	/**
+	 * Invalidates all {@link #registerPendingPut(Object) previously registered pending puts} 
+	 * ensuring a subsequent call to {@link #acquirePutFromLoadLock(Object)} will
+	 * return <code>false</code>.
+	 * <p>
+	 * This method will block until any concurrent thread that has 
+	 * {@link #acquirePutFromLoadLock(Object) acquired the putFromLoad lock} for
+	 * the any key has released the lock. This allows the caller to be certain
+	 * the putFromLoad will not execute after this method returns, possibly
+	 * caching stale data.
+	 * </p>
+	 * 
+	 * @return <code>true</code> if the invalidation was successful; <code>false</code>
+	 *         if a problem occured (which the caller should treat as an
+	 *         exception condition)
+	 */
+	public boolean invalidateRegion() {
+		
+		boolean ok = false;
+		invalidationTimestamp = System.currentTimeMillis()
+				+ this.nakedPutInvalidationPeriod;
+		
+		try {
+			
+			// Acquire the lock for each entry to ensure any ongoing
+			// work associated with it is completed before we return
+			for (PendingPutMap entry : pendingPuts.values()) {
+				if (entry.acquireLock(60, TimeUnit.SECONDS)) {
+					try {
+						entry.invalidate();
+					}
+					finally {
+						entry.releaseLock();
+					}
+				}
+				else {
+					ok = false;
+				}
+			}
+			
+			removalsLock.lock();
+			try {
+				recentRemovals.clear();
+				removalsQueue.clear();				
+				
+				ok = true;
+
+			} finally {
+				removalsLock.unlock();
+			}
+		}
+		catch (Exception e) {
+			ok = false;
+		}
+		finally {
+			earliestRemovalTimestamp = invalidationTimestamp;
+		}
+		
+		return ok;
+	}
+
+	/**
+	 * Notifies this validator that it is expected that a database read followed
+	 * by a subsequent {@link #acquirePutFromLoadLock(Object)} call will occur. The intent
+	 * is this method would be called following a cache miss wherein it is
+	 * expected that a database read plus cache put will occur. Calling this
+	 * method allows the validator to treat the subsequent
+	 * <code>acquirePutFromLoadLock</code> as if the database read occurred when this method
+	 * was invoked. This allows the validator to compare the timestamp of this
+	 * call against the timestamp of subsequent removal notifications. A put
+	 * that occurs without this call preceding it is "naked"; i.e the validator
+	 * must assume the put is not valid if any relevant removal has occurred
+	 * within {@link #NAKED_PUT_INVALIDATION_PERIOD} milliseconds.
+	 * 
+	 * @param key key that will be used for subsequent cache put
+	 */
+	public void registerPendingPut(Object key) {
+		PendingPut pendingPut = new PendingPut(key, getOwnerForPut());
+		PendingPutMap pendingForKey = new PendingPutMap(pendingPut);
+		
+		for (;;) {
+			PendingPutMap existing = pendingPuts.putIfAbsent(key,
+					pendingForKey);
+			if (existing != null) {
+				if (existing.acquireLock(10, TimeUnit.SECONDS)) {
+					try {
+						existing.put(pendingPut);
+						PendingPutMap doublecheck = pendingPuts.putIfAbsent(
+								key, existing);
+						if (doublecheck == null || doublecheck == existing) {
+							break;
+						}
+						// else we hit a race and need to loop to try again
+					}
+					finally {
+						existing.releaseLock();
+					}
+				}
+				else {
+					// Can't get the lock; when we come back we'll be a "naked put"
+					break;
+				}
+			} else {
+				// normal case
+				break;
+			}
+		}
+
+		// Guard against memory leaks
+		preventOutdatedPendingPuts(pendingPut);
+	}
+
+	// -------------------------------------------------------------- Protected
+
+	/** Only for use by unit tests; may be removed at any time */
+	protected int getPendingPutQueueLength() {
+		pendingLock.lock();
+		try {
+			return pendingQueue.size();
+		} finally {
+			pendingLock.unlock();
+		}
+	}
+
+	/** Only for use by unit tests; may be removed at any time */
+	protected int getOveragePendingPutQueueLength() {
+		pendingLock.lock();
+		try {
+			return overagePendingQueue.size();
+		} finally {
+			pendingLock.unlock();
+		}
+	}
+
+	/** Only for use by unit tests; may be removed at any time */
+	protected int getRemovalQueueLength() {
+		removalsLock.lock();
+		try {
+			return removalsQueue.size();
+		} finally {
+			removalsLock.unlock();
+		}
+	}
+
+	// ---------------------------------------------------------------- Private
+
+	private Object getOwnerForPut() {
+		Transaction tx = null;
+		try {
+			if (transactionManager != null) {
+				tx = transactionManager.getTransaction();
+			}
+		} catch (SystemException se) {
+			throw new CacheException("Could not obtain transaction", se);
+		}
+		return tx == null ? Thread.currentThread() : tx;
+
+	}
+
+	private void preventOutdatedPendingPuts(PendingPut pendingPut) {
+		pendingLock.lock();
+		try {
+			pendingQueue.add(new WeakReference<PendingPut>(pendingPut));
+			if (pendingQueue.size() > 1) {
+				cleanOutdatedPendingPuts(pendingPut.timestamp, false);
+			}
+		} finally {
+			pendingLock.unlock();
+		}
+	}
+
+	private void cleanOutdatedPendingPuts(long now, boolean lock) {
+
+		PendingPut toClean = null;
+		if (lock) {
+			pendingLock.lock();
+		}
+		try {
+			// Clean items out of the basic queue
+			long overaged = now - this.pendingPutOveragePeriod;
+			long recent = now - this.pendingPutRecentPeriod;
+
+			int pos = 0;
+			while (pendingQueue.size() > pos) {
+				WeakReference<PendingPut> ref = pendingQueue.get(pos);
+				PendingPut item = ref.get();
+				if (item == null || item.completed) {
+					pendingQueue.remove(pos);
+				} else if (item.timestamp < overaged) {
+					// Potential leak; move to the overaged queued
+					pendingQueue.remove(pos);
+					overagePendingQueue.add(ref);
+				} else if (item.timestamp >= recent) {
+					// Don't waste time on very recent items
+					break;
+				} else if (pos > 2) {
+					// Don't spend too much time getting nowhere
+					break;
+				} else {
+					// Move on to the next item
+					pos++;
+				}
+			}
+
+			// Process the overage queue until we find an item to clean
+			// or an incomplete item that hasn't aged out
+			long mustCleanTime = now - this.maxPendingPutDelay;
+
+			while (overagePendingQueue.size() > 0) {
+				WeakReference<PendingPut> ref = overagePendingQueue.get(0);
+				PendingPut item = ref.get();
+				if (item == null || item.completed) {
+					overagePendingQueue.remove(0);
+				} else {
+					if (item.timestamp < mustCleanTime) {
+						overagePendingQueue.remove(0);
+						toClean = item;
+					}
+					break;
+				}
+			}
+		} finally {
+			if (lock) {
+				pendingLock.unlock();
+			}
+		}
+
+		// We've found a pendingPut that never happened; clean it up
+		if (toClean != null) {
+			PendingPutMap map = pendingPuts.get(toClean.key);
+			if (map != null) {
+				if (map.acquireLock(100, TimeUnit.MILLISECONDS)) {
+					try {
+						PendingPut cleaned = map.remove(toClean.owner);
+						if (toClean.equals(cleaned) == false) {
+							// Oops. Restore it.
+							map.put(cleaned);
+						} else if (map.size() == 0) {
+							pendingPuts.remove(toClean.key);
+						}
+					}
+					finally {
+						map.releaseLock();
+					}
+				}
+				else {
+					// Something's gone wrong and the lock isn't being released. 
+					// We removed toClean from the queue and need to restore it
+					// TODO this is pretty dodgy
+					restorePendingPut(toClean);
+				}
+			}
+		}
+
+	}
+		
+	private void restorePendingPut(PendingPut toRestore) {
+		pendingLock.lock();
+		try {
+			// Give it a new lease on life so it's not out of order. We could
+			// scan the queue and put toRestore back at the front, but then
+			// we'll just immediately try removing it again; instead we
+			// let it cycle through the queue again
+			toRestore.refresh();
+			pendingQueue.add(new WeakReference<PendingPut>(toRestore));
+		}
+		finally {
+			pendingLock.unlock();
+		}
+	}
+
+	/**
+	 * Lazy-initialization map for PendingPut. Optimized for the expected usual
+	 * case where only a single put is pending for a given key.
+	 * 
+	 * This class is NOT THREAD SAFE. All operations on it must be performed
+	 * with the lock held.
+	 */
+	private static class PendingPutMap {
+		private PendingPut singlePendingPut;
+		private Map<Object, PendingPut> fullMap;
+		private final Lock lock = new ReentrantLock();
+		
+		PendingPutMap(PendingPut singleItem) {
+			this.singlePendingPut = singleItem;
+		}
+		
+		public void put(PendingPut pendingPut) {
+			if (singlePendingPut == null) {
+				if (fullMap == null) {
+					// initial put
+					singlePendingPut = pendingPut;
+				} else {
+					fullMap.put(pendingPut.owner, pendingPut);
+				}
+			} else {
+				// 2nd put; need a map
+				fullMap = new HashMap<Object, PendingPut>(4);
+				fullMap.put(singlePendingPut.owner, singlePendingPut);
+				singlePendingPut = null;
+				fullMap.put(pendingPut.owner, pendingPut);
+			}
+		}
+
+		public PendingPut remove(Object ownerForPut) {
+			PendingPut removed = null;
+			if (fullMap == null) {
+				if (singlePendingPut != null
+						&& singlePendingPut.owner.equals(ownerForPut)) {
+					removed = singlePendingPut;
+					singlePendingPut = null;
+				}
+			} else {
+				removed = fullMap.remove(ownerForPut);
+			}
+			return removed;
+		}
+
+		public int size() {
+			return fullMap == null ? (singlePendingPut == null ? 0 : 1)
+					: fullMap.size();
+		}
+		
+		public boolean acquireLock(long time, TimeUnit unit) {
+			try {
+				return lock.tryLock(time, unit);
+			} catch (InterruptedException e) {
+				Thread.currentThread().interrupt();
+				return false;
+			}
+		}
+		
+		public void releaseLock() {
+			lock.unlock();
+		}
+		
+		public void invalidate() {
+			if (singlePendingPut != null) {
+				singlePendingPut.completed = true;
+			}
+			else if (fullMap != null) {
+				for (PendingPut pp : fullMap.values()) {
+					pp.completed = true;
+				}
+			}
+		}
+	}
+
+	private static class PendingPut {
+		private final Object key;
+		private final Object owner;
+		private long timestamp = System.currentTimeMillis();
+		private volatile boolean completed;
+
+		private PendingPut(Object key, Object owner) {
+			this.key = key;
+			this.owner = owner;
+		}
+		
+		private void refresh() {
+			timestamp = System.currentTimeMillis();
+		}
+
+	}
+
+	private static class RecentRemoval {
+		private final Object key;
+		private final Long timestamp;
+
+		private RecentRemoval(Object key, long nakedPutInvalidationPeriod) {
+			this.key = key;
+			timestamp = Long.valueOf(System.currentTimeMillis()
+					+ nakedPutInvalidationPeriod);
+		}
+	}
+
+}
diff --git a/src/main/java/hibernate/cache/jbc/access/TransactionalAccessDelegate.java b/src/main/java/hibernate/cache/jbc/access/TransactionalAccessDelegate.java
new file mode 100644
index 0000000..487637e
--- /dev/null
+++ b/src/main/java/hibernate/cache/jbc/access/TransactionalAccessDelegate.java
@@ -0,0 +1,222 @@
+/*
+ * 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.jbc.access;
+
+import javax.transaction.Transaction;
+
+import org.hibernate.cache.CacheException;
+import org.hibernate.cache.access.CollectionRegionAccessStrategy;
+import org.hibernate.cache.access.EntityRegionAccessStrategy;
+import org.hibernate.cache.access.SoftLock;
+import org.hibernate.cache.jbc.BasicRegionAdapter;
+import org.hibernate.cache.jbc.util.CacheHelper;
+import org.jboss.cache.Cache;
+import org.jboss.cache.Fqn;
+import org.jboss.cache.config.Option;
+
+/**
+ * Defines the strategy for transactional access to entity or collection data in
+ * a pessimistic-locking JBoss Cache using its 2.x APIs.
+ * <p>
+ * The intent of this class is to encapsulate common code and serve as a
+ * delegate for {@link EntityRegionAccessStrategy} and
+ * {@link CollectionRegionAccessStrategy} implementations.
+ * </p>
+ * 
+ * @author Brian Stansberry
+ */
+public class TransactionalAccessDelegate {
+        
+    protected final Cache cache;
+    protected final Fqn regionFqn;
+    protected final boolean invalidation;
+    protected final BasicRegionAdapter region;
+    protected final PutFromLoadValidator putValidator;
+
+    public TransactionalAccessDelegate(BasicRegionAdapter adapter, PutFromLoadValidator validator) {
+        this.region = adapter;
+        this.cache = adapter.getCacheInstance();
+        this.regionFqn = adapter.getRegionFqn();
+        this.putValidator = validator;
+        this.invalidation = CacheHelper.isClusteredInvalidation(this.cache);
+    }
+
+    public Object get(Object key, long txTimestamp) throws CacheException {
+        
+        if (!region.checkValid())
+           return null;
+        
+        region.ensureRegionRootExists();
+        
+        Object val = CacheHelper.get(cache, regionFqn, key);
+        
+        if (val == null) {
+           putValidator.registerPendingPut(key);
+        }
+        
+        return val;
+    }
+
+   public boolean putFromLoad(Object key, Object value, long txTimestamp, Object version) throws CacheException {
+       
+        if (!region.checkValid())
+            return false;
+        
+        if (!putValidator.acquirePutFromLoadLock(key))
+            return false;
+       
+        try {
+	        region.ensureRegionRootExists();
+	
+	        return CacheHelper.putForExternalRead(cache, regionFqn, key, value);
+        }
+        finally {
+        	putValidator.releasePutFromLoadLock(key);
+        }
+    }
+
+   public boolean putFromLoad(Object key, Object value, long txTimestamp, Object version, boolean minimalPutOverride)
+            throws CacheException {
+       
+        if (!region.checkValid())
+            return false;
+        
+        if (!putValidator.acquirePutFromLoadLock(key))
+            return false;
+        
+        try {
+	        region.ensureRegionRootExists();
+	
+	        // We ignore minimalPutOverride. JBossCache putForExternalRead is
+	        // already about as minimal as we can get; it will promptly return
+	        // if it discovers that the node we want to write to already exists
+	        return CacheHelper.putForExternalRead(cache, regionFqn, key, value);
+        }
+        finally {
+        	putValidator.releasePutFromLoadLock(key);
+        }
+    }
+
+    public SoftLock lockItem(Object key, Object version) throws CacheException {
+        return null;
+    }
+
+    public SoftLock lockRegion() throws CacheException {
+        return null;
+    }
+
+    public void unlockItem(Object key, SoftLock lock) throws CacheException {
+    }
+
+    public void unlockRegion(SoftLock lock) throws CacheException {
+    }
+
+    public boolean insert(Object key, Object value, Object version) throws CacheException {
+       
+        if (!region.checkValid())
+            return false;
+       
+        region.ensureRegionRootExists();
+        if (invalidation) {
+        	Option opt = new Option();
+        	opt.setCacheModeLocal(true);
+        	CacheHelper.put(cache, regionFqn, key, value, opt);
+        }
+        else {
+        	CacheHelper.put(cache, regionFqn, key, value);
+        }
+        return true;
+    }
+
+    public boolean afterInsert(Object key, Object value, Object version) throws CacheException {
+        return false;
+    }
+
+    public boolean update(Object key, Object value, Object currentVersion, Object previousVersion)
+            throws CacheException {
+       
+        // We update whether or not the region is valid. Other nodes
+        // may have already restored the region so they need to
+        // be informed of the change.
+       
+        region.ensureRegionRootExists();
+
+        CacheHelper.put(cache, regionFqn, key, value);
+        return true;
+    }
+
+    public boolean afterUpdate(Object key, Object value, Object currentVersion, Object previousVersion, SoftLock lock)
+            throws CacheException {
+        return false;
+    }
+
+    public void remove(Object key) throws CacheException {
+       
+    	if (!putValidator.invalidateKey(key)) {
+    		throw new CacheException("Failed to invalidate pending putFromLoad calls for key " + key + " from region " + region.getName());
+    	}        
+       
+        // We remove whether or not the region is valid. Other nodes
+        // may have already restored the region so they need to
+        // be informed of the change.
+       
+        region.ensureRegionRootExists();
+
+        CacheHelper.remove(cache, regionFqn, key);
+    }
+
+    public void removeAll() throws CacheException {
+       if (!putValidator.invalidateRegion()) {
+     	  throw new CacheException("Failed to invalidate pending putFromLoad calls for region " + region.getName());
+       }
+       CacheHelper.removeAll(cache, regionFqn); 
+    }
+
+    public void evict(Object key) throws CacheException {
+       
+    	if (!putValidator.invalidateKey(key)) {
+    		throw new CacheException("Failed to invalidate pending putFromLoad calls for key " + key + " from region " + region.getName());
+    	}        
+       
+        region.ensureRegionRootExists();
+        
+        CacheHelper.remove(cache, regionFqn, key);
+    }
+
+    public void evictAll() throws CacheException {
+       if (!putValidator.invalidateRegion()) {
+     	  throw new CacheException("Failed to invalidate pending putFromLoad calls for region " + region.getName());
+       }
+        
+       Transaction tx = region.suspend();
+       try {        
+          region.ensureRegionRootExists();
+          
+          CacheHelper.sendEvictAllNotification(cache, regionFqn, region.getMemberId(), null);
+       }
+       finally {
+          region.resume(tx);
+       }        
+    }
+}
diff --git a/src/main/java/hibernate/cache/jbc/builder/JndiMultiplexingCacheInstanceManager.java b/src/main/java/hibernate/cache/jbc/builder/JndiMultiplexingCacheInstanceManager.java
new file mode 100644
index 0000000..0410fcc
--- /dev/null
+++ b/src/main/java/hibernate/cache/jbc/builder/JndiMultiplexingCacheInstanceManager.java
@@ -0,0 +1,103 @@
+/*
+ * 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.jbc.builder;
+
+import java.util.Properties;
+
+import javax.naming.Context;
+import javax.naming.InitialContext;
+import javax.naming.NamingException;
+
+import org.hibernate.cache.CacheException;
+import org.hibernate.cfg.Settings;
+import org.hibernate.util.NamingHelper;
+import org.hibernate.util.PropertiesHelper;
+import org.jboss.cache.CacheManager;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * A {@link MultiplexingCacheInstanceManager} that finds its cache factory
+ * in JNDI rather than creating one itself.
+ * 
+ * @author <a href="brian.stansberry at jboss.com">Brian Stansberry</a>
+ * @version $Revision: 1 $
+ */
+public class JndiMultiplexingCacheInstanceManager extends MultiplexingCacheInstanceManager {
+    
+    private static final Logger log = LoggerFactory.getLogger(JndiMultiplexingCacheInstanceManager.class);
+    
+    /**
+     * Specifies the JNDI name under which the {@link CacheManager} to use is bound.
+     * There is no default value -- the user must specify the property.
+     */
+    public static final String CACHE_FACTORY_RESOURCE_PROP = "hibernate.cache.region.jbc2.cachefactory";
+
+    /**
+     * Create a new JndiMultiplexingCacheInstanceManager.
+     */
+    public JndiMultiplexingCacheInstanceManager() {
+        super();
+    }
+
+    @Override
+    public void start(Settings settings, Properties properties) throws CacheException {
+        
+        String name = PropertiesHelper.getString(CACHE_FACTORY_RESOURCE_PROP, properties, null);
+        if (name == null)
+            throw new CacheException("Configuration property " + CACHE_FACTORY_RESOURCE_PROP + " not set");
+        
+        CacheManager cf = locateCacheFactory( name, NamingHelper.getJndiProperties( properties ) );
+        setCacheFactory( cf );        
+        
+        super.start(settings, properties);
+    }
+
+    private CacheManager locateCacheFactory(String jndiNamespace, Properties jndiProperties) {
+
+        Context ctx = null;
+        try {
+            ctx = new InitialContext( jndiProperties );
+            return (CacheManager) ctx.lookup( jndiNamespace );
+        }
+        catch (NamingException ne) {
+            String msg = "Unable to retreive Cache from JNDI [" + jndiNamespace + "]";
+            log.info( msg, ne );
+            throw new CacheException( msg );
+        }
+        finally {
+            if ( ctx != null ) {
+                try {
+                    ctx.close();
+                }
+                catch( NamingException ne ) {
+                    log.info( "Unable to release initial context", ne );
+                }
+            }
+        }
+    }
+
+    
+}
diff --git a/src/main/java/hibernate/cache/jbc/builder/JndiSharedCacheInstanceManager.java b/src/main/java/hibernate/cache/jbc/builder/JndiSharedCacheInstanceManager.java
new file mode 100644
index 0000000..d635a7d
--- /dev/null
+++ b/src/main/java/hibernate/cache/jbc/builder/JndiSharedCacheInstanceManager.java
@@ -0,0 +1,112 @@
+/*
+ * 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.jbc.builder;
+
+import java.util.Properties;
+
+import javax.naming.Context;
+import javax.naming.InitialContext;
+import javax.naming.NamingException;
+
+import org.hibernate.cache.CacheException;
+import org.hibernate.cfg.Settings;
+import org.hibernate.util.NamingHelper;
+import org.hibernate.util.PropertiesHelper;
+import org.jboss.cache.Cache;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A {@link SharedCacheInstanceManager} that finds the shared cache in JNDI 
+ * rather than instantiating one from an XML config file.
+ * 
+ * @author <a href="brian.stansberry at jboss.com">Brian Stansberry</a>
+ * @version $Revision: 1 $
+ */
+public class JndiSharedCacheInstanceManager extends SharedCacheInstanceManager {
+    
+    private static final Logger log = LoggerFactory.getLogger(JndiSharedCacheInstanceManager.class);
+
+    /**
+     * Specifies the JNDI name under which the {@link Cache} to use is bound.
+     * <p>
+     * Note that although this configuration property has the same name as that by
+     * in {@link SharedCacheInstanceManager#CACHE_RESOURCE_PROP the superclass}, 
+     * the meaning here is different. Note also that in this class' usage
+     * of the property, there is no default value -- the user must specify
+     * the property.
+     */
+    public static final String CACHE_RESOURCE_PROP = "hibernate.cache.region.jbc2.cfg.shared";
+    
+    /**
+     * Create a new JndiSharedCacheInstanceManager.
+     * 
+     */
+    public JndiSharedCacheInstanceManager() {
+        super();
+    }
+
+    @Override
+    protected Cache createSharedCache(Settings settings, Properties properties) {
+        
+        String name = PropertiesHelper.getString(CACHE_RESOURCE_PROP, properties, null);
+        if (name == null)
+            throw new CacheException("Configuration property " + CACHE_RESOURCE_PROP + " not set");
+        
+        return locateCache( name, NamingHelper.getJndiProperties( properties ) );
+    }
+
+    /**
+     * No-op; we don't own the cache so we shouldn't stop it.
+     */
+    @Override
+    protected void stopSharedCache(Cache cache) {
+        // no-op. We don't own the cache so we shouldn't stop it.
+    }
+
+    private Cache locateCache(String jndiNamespace, Properties jndiProperties) {
+
+        Context ctx = null;
+        try {
+            ctx = new InitialContext( jndiProperties );
+            return (Cache) ctx.lookup( jndiNamespace );
+        }
+        catch (NamingException ne) {
+            String msg = "Unable to retreive Cache from JNDI [" + jndiNamespace + "]";
+            log.info( msg, ne );
+            throw new CacheException( msg );
+        }
+        finally {
+            if ( ctx != null ) {
+                try {
+                    ctx.close();
+                }
+                catch( NamingException ne ) {
+                    log.info( "Unable to release initial context", ne );
+                }
+            }
+        }
+    }
+
+}
diff --git a/src/main/java/hibernate/cache/jbc/builder/MultiplexingCacheInstanceManager.java b/src/main/java/hibernate/cache/jbc/builder/MultiplexingCacheInstanceManager.java
new file mode 100644
index 0000000..38b5c21
--- /dev/null
+++ b/src/main/java/hibernate/cache/jbc/builder/MultiplexingCacheInstanceManager.java
@@ -0,0 +1,555 @@
+/*
+ * 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.jbc.builder;
+
+import java.util.Properties;
+import javax.transaction.TransactionManager;
+
+import org.jboss.cache.Cache;
+import org.jboss.cache.CacheManager;
+import org.jboss.cache.CacheManagerImpl;
+import org.jboss.cache.CacheStatus;
+import org.jboss.cache.config.Configuration;
+import org.jgroups.ChannelFactory;
+import org.jgroups.JChannelFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.hibernate.cache.CacheException;
+import org.hibernate.cache.jbc.CacheInstanceManager;
+import org.hibernate.cache.jbc.util.CacheHelper;
+import org.hibernate.cfg.Settings;
+import org.hibernate.transaction.TransactionManagerLookup;
+import org.hibernate.util.PropertiesHelper;
+
+/**
+ * Allows building separate {@link Cache} instances for each type of region,
+ * with the expectation that a single multiplexed JGroups resource (i.e. a 
+ * multiplexed channel or a shared transport channel) will be shared between 
+ * the caches.<p/>
+ * 
+ * @author Steve Ebersole
+ * @author Brian Stansberry
+ */
+public class MultiplexingCacheInstanceManager implements CacheInstanceManager {
+
+    private static final Logger log = LoggerFactory.getLogger(MultiplexingCacheInstanceManager.class);
+    
+    /** 
+     * Classpath or filesystem resource containing JBoss Cache 
+     * configurations the factory should use.
+     * 
+     * @see #DEF_CACHE_FACTORY_RESOURCE
+     */
+    public static final String CACHE_FACTORY_RESOURCE_PROP = "hibernate.cache.jbc.configs";
+    /** 
+     * Legacy name for configuration property {@link #CACHE_FACTORY_RESOURCE_PROP}.
+     * 
+     * @see #DEF_CACHE_FACTORY_RESOURCE
+     */
+    public static final String LEGACY_CACHE_FACTORY_RESOURCE_PROP = "hibernate.cache.region.jbc2.configs";
+    /**
+     * Classpath or filesystem resource containing JGroups protocol
+     * stack configurations the <code>org.jgroups.ChannelFactory</code>
+     * should use.
+     * 
+     * @see #DEF_JGROUPS_RESOURCE
+     */
+    public static final String CHANNEL_FACTORY_RESOURCE_PROP = "hibernate.cache.jbc.jgroups.stacks";
+    /**
+     * Legacy name for configuration property {@link #CHANNEL_FACTORY_RESOURCE_PROP}.
+     * 
+     * @see #DEF_JGROUPS_RESOURCE
+     */
+    public static final String LEGACY_CHANNEL_FACTORY_RESOURCE_PROP = "hibernate.cache.region.jbc2.cfg.jgroups.stacks";
+    
+    /**
+     * Name of the configuration that should be used for entity caches.
+     * 
+     * @see #DEF_ENTITY_RESOURCE
+     */
+    public static final String ENTITY_CACHE_RESOURCE_PROP = "hibernate.cache.jbc.cfg.entity";
+    /**
+     * Legacy name for configuration property {@link #ENTITY_CACHE_RESOURCE_PROP}.
+     * 
+     * @see #DEF_ENTITY_RESOURCE
+     */
+    public static final String LEGACY_ENTITY_CACHE_RESOURCE_PROP = "hibernate.cache.region.jbc2.cfg.entity";
+    /**
+     * Name of the configuration that should be used for collection caches.
+     * No default value, as by default we try to use the same JBoss Cache
+     * instance we use for entity caching.
+     * 
+     * @see #ENTITY_CACHE_RESOURCE_PROP
+     * @see #DEF_ENTITY_RESOURCE
+     */
+    public static final String COLLECTION_CACHE_RESOURCE_PROP = "hibernate.cache.jbc.cfg.collection";
+    /**
+     * Legacy name for configuration property {@link #COLLECTION_CACHE_RESOURCE_PROP}.
+     * 
+     * @see #ENTITY_CACHE_RESOURCE_PROP
+     * @see #DEF_ENTITY_RESOURCE
+     */
+    public static final String LEGACY_COLLECTION_CACHE_RESOURCE_PROP = "hibernate.cache.region.jbc2.cfg.collection";
+    /**
+     * Name of the configuration that should be used for timestamp caches.
+     * 
+     * @see #DEF_TS_RESOURCE
+     */
+    public static final String TIMESTAMP_CACHE_RESOURCE_PROP = "hibernate.cache.jbc.cfg.timestamps";
+    /**
+     * Legacy name for configuration property {@link #TIMESTAMP_CACHE_RESOURCE_PROP}.
+     * 
+     * @see #DEF_TS_RESOURCE
+     */
+    public static final String LEGACY_TIMESTAMP_CACHE_RESOURCE_PROP = "hibernate.cache.region.jbc2.cfg.ts";
+    /**
+     * Name of the configuration that should be used for query caches.
+     * 
+     * @see #DEF_QUERY_RESOURCE
+     */
+    public static final String QUERY_CACHE_RESOURCE_PROP = "hibernate.cache.jbc.cfg.query";
+
+    /**
+     * Legacy name for configuration property {@link #QUERY_CACHE_RESOURCE_PROP}.
+     * 
+     * @see #DEF_QUERY_RESOURCE
+     */
+    public static final String LEGACY_QUERY_CACHE_RESOURCE_PROP = "hibernate.cache.region.jbc2.cfg.query";
+
+    /**
+     * Default value for {@link #CACHE_FACTORY_RESOURCE_PROP}. Specifies
+     * the "jbc2-configs.xml" file in this package.
+     */
+    public static final String DEF_CACHE_FACTORY_RESOURCE = "org/hibernate/cache/jbc/builder/jbc-configs.xml";    
+    /**
+     * Default value for {@link #CHANNEL_FACTORY_RESOURCE_PROP}. Specifies
+     * the "jgroups-stacks.xml" file in this package.
+     */
+    public static final String DEF_JGROUPS_RESOURCE = "org/hibernate/cache/jbc/builder/jgroups-stacks.xml";
+    /**
+     * Default value for {@link #ENTITY_CACHE_RESOURCE_PROP}.
+     */
+    public static final String DEF_ENTITY_RESOURCE = "optimistic-entity";
+    /**
+     * Default value for {@link #TIMESTAMP_CACHE_RESOURCE_PROP}.
+     */
+    public static final String DEF_TS_RESOURCE = "timestamps-cache";
+    /**
+     * Default value for {@link #ENTITY_CACHE_RESOURCE_PROP}.
+     */
+    public static final String DEF_QUERY_RESOURCE = "local-query";
+
+    /** Cache for entities */
+    private Cache jbcEntityCache;
+    /** Cache for collections */
+    private Cache jbcCollectionCache;
+    /** Cache for timestamps */
+    private Cache jbcTsCache;
+    /** Cache for queries */
+    private Cache jbcQueryCache;
+    /** Name of config used for entities. */
+    private String entityConfig = null;
+    /** Name of config used for collections. */
+    private String collectionConfig = null;
+    /** Name of config used for queries. */
+    private String queryConfig = null;
+    /** Name of config used for timestamps. */
+    private String tsConfig = null;
+    
+    /** Our cache factory */
+    private CacheManager jbcFactory;
+    /** Our channel factory */
+    private ChannelFactory channelFactory;
+    /** 
+     * Did we create the factory ourself and thus can assume we are not
+     * sharing it (and the caches) with other users?
+     */
+    private boolean selfCreatedFactory;
+
+    /**
+     * Create a new MultiplexingCacheInstanceManager.
+     */
+    public MultiplexingCacheInstanceManager() {
+    }
+    
+    /**
+     * Create a new MultiplexingCacheInstanceManager using the provided {@link Cache}s.
+     * <p/>
+     * If this constructor is used, the {@link #start(Settings, Properties)}
+     * method will make no attempt to create a cache factory or obtain caches
+     * from it.  Only the <code>Cache</code>s passed as arguments to this
+     * constructor will be available.
+     *
+	 * @param jbcEntityCache The entity cache
+	 * @param jbcCollectionCache the collection cache
+	 * @param jbcTsCache The timestamps cache
+	 * @param jbcQueryCache The query cache
+     */
+    public MultiplexingCacheInstanceManager(
+			Cache jbcEntityCache,
+			Cache jbcCollectionCache,
+			Cache jbcTsCache,
+			Cache jbcQueryCache) {
+        this.jbcEntityCache = jbcEntityCache;
+        this.jbcCollectionCache = jbcCollectionCache;
+        this.jbcTsCache = jbcTsCache;
+        this.jbcQueryCache = jbcQueryCache;
+    }
+
+    /**
+	 * Getter for property 'cacheFactory'.
+	 * @see #setCacheFactory
+	 *
+	 * @return Value for property 'cacheFactory'.
+	 */
+	public CacheManager getCacheFactory() {
+        return jbcFactory;
+    }
+
+    /**
+	 * Setter for property 'cacheFactory'.
+	 * @see #getCacheFactory
+	 *
+	 * @param factory Value to set for property 'cacheFactory'.
+	 */
+	public void setCacheFactory(CacheManager factory) {
+        this.jbcFactory = factory;
+    }
+
+    /**
+	 * Getter for property 'channelFactory'.
+	 * @see #setChannelFactory
+	 *
+	 * @return Value for property 'channelFactory'.
+	 */
+	public ChannelFactory getChannelFactory() {
+        return channelFactory;
+    }
+
+    /**
+	 * Setter for property 'channelFactory'.
+	 * @see #getChannelFactory
+	 *
+	 * @param factory Value to set for property 'channelFactory'.
+	 */
+	public void setChannelFactory(ChannelFactory factory) {
+        this.channelFactory = factory;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Cache getEntityCacheInstance() {
+        return jbcEntityCache;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Cache getCollectionCacheInstance() {
+        return jbcCollectionCache;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Cache getQueryCacheInstance() {
+       
+        if (jbcQueryCache != null && jbcTsCache == null) {
+            // This should only be possible if the caches are constructor injected 
+            throw new CacheException("Timestamps cache must be configured if a query cache is used");   
+        }
+
+        return jbcQueryCache;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Cache getTimestampsCacheInstance() {
+       
+       if (jbcTsCache != null && CacheHelper.isClusteredInvalidation(jbcTsCache)) {
+          throw new CacheException("Clustered invalidation not supported for timestamps cache");
+       }
+       return jbcTsCache;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void start(Settings settings, Properties properties) throws CacheException {
+        try {
+            // We need our tm, so get it now and avoid doing other work
+            // if there is a problem
+            TransactionManagerLookup tml = settings.getTransactionManagerLookup();
+            TransactionManager tm =  (tml == null ? null : tml.getTransactionManager(properties));
+
+            // We only build caches if *none* were passed in.  Passing in
+            // caches counts as a clear statement of exactly what is wanted
+            boolean buildCaches = jbcEntityCache == null
+                                  && jbcCollectionCache == null
+                                  && jbcTsCache == null
+                                  && jbcQueryCache == null;
+                                  
+            // Set up the cache factory
+            if (buildCaches && jbcFactory == null) {
+                // See if the user configured a multiplexer stack
+                if (channelFactory == null) {
+                    String muxStacks = PropertiesHelper.getString(CHANNEL_FACTORY_RESOURCE_PROP, properties, null);
+                    if (muxStacks == null) {
+                    	muxStacks = PropertiesHelper.getString(LEGACY_CHANNEL_FACTORY_RESOURCE_PROP, properties, DEF_JGROUPS_RESOURCE);
+                    }
+                    if (muxStacks != null) {
+                        channelFactory = new JChannelFactory();
+                        channelFactory.setMultiplexerConfig(muxStacks);
+                    }
+                }
+                
+                String factoryRes = PropertiesHelper.getString(CACHE_FACTORY_RESOURCE_PROP, properties, null);
+                if (factoryRes == null) {
+                	factoryRes = PropertiesHelper.getString(LEGACY_CACHE_FACTORY_RESOURCE_PROP, properties, DEF_CACHE_FACTORY_RESOURCE);
+                }
+                jbcFactory = new CacheManagerImpl(factoryRes, channelFactory);
+                ((CacheManagerImpl) jbcFactory).start();
+                selfCreatedFactory = true;
+            }
+            
+            if (settings.isSecondLevelCacheEnabled()) {
+
+                if (buildCaches) {
+                    entityConfig = PropertiesHelper
+                            .getString(ENTITY_CACHE_RESOURCE_PROP, properties, null);
+                    if (entityConfig == null) {
+                    	entityConfig = PropertiesHelper.getString(LEGACY_ENTITY_CACHE_RESOURCE_PROP, 
+                    			properties, DEF_ENTITY_RESOURCE);
+                    }
+                    jbcEntityCache = jbcFactory.getCache(entityConfig, true);
+                
+                    // Default to collections sharing entity cache if there is one
+                    collectionConfig = PropertiesHelper.getString(COLLECTION_CACHE_RESOURCE_PROP, properties, null);
+                    if (collectionConfig == null) {
+                    	collectionConfig = PropertiesHelper.getString(LEGACY_COLLECTION_CACHE_RESOURCE_PROP, properties, entityConfig);
+                    }
+                    if (entityConfig.equals(collectionConfig)) {
+                        jbcCollectionCache = jbcEntityCache;
+                    }
+                    else {
+                        jbcCollectionCache = jbcFactory.getCache(collectionConfig, true);
+                    }
+                }
+                
+                if (jbcEntityCache != null) {
+                    configureTransactionManager(jbcEntityCache, tm, false);
+                    jbcEntityCache.start();
+                }
+                if (jbcCollectionCache != null) {
+                    configureTransactionManager(jbcCollectionCache, tm, false);
+                    jbcCollectionCache.start();
+                }
+                
+            } 
+            else {
+                jbcEntityCache = null;
+                jbcCollectionCache = null;
+            }
+
+            if (settings.isQueryCacheEnabled()) {
+
+                if (buildCaches) {
+                    // Default to sharing the entity cache if there is one
+                    String dfltQueryResource = (entityConfig == null ? DEF_QUERY_RESOURCE : entityConfig);
+                    queryConfig = PropertiesHelper.getString(QUERY_CACHE_RESOURCE_PROP, properties, null);
+                    if (queryConfig == null) {
+                    	queryConfig = PropertiesHelper.getString(LEGACY_QUERY_CACHE_RESOURCE_PROP, properties, dfltQueryResource);
+                    }
+                    if (queryConfig.equals(entityConfig)) {
+                        jbcQueryCache = jbcEntityCache;
+                    } else if (queryConfig.equals(collectionConfig)) {
+                        jbcQueryCache = jbcCollectionCache;
+                    } else {
+                        jbcQueryCache = jbcFactory.getCache(queryConfig, true);
+                    }
+    
+                    // For Timestamps, we default to a separate config
+                    tsConfig = PropertiesHelper.getString(TIMESTAMP_CACHE_RESOURCE_PROP, properties, null);
+                    if (tsConfig == null) {
+                    	tsConfig = PropertiesHelper.getString(LEGACY_TIMESTAMP_CACHE_RESOURCE_PROP, properties, DEF_TS_RESOURCE);
+                    }
+                    if (tsConfig.equals(queryConfig)) {
+                        jbcTsCache = jbcQueryCache;
+                    }
+                    else if (tsConfig.equals(entityConfig)) {
+                        jbcTsCache = jbcEntityCache;
+                    } 
+                    else if (tsConfig.equals(collectionConfig)) {
+                        jbcTsCache = jbcCollectionCache;
+                    } 
+                    else {
+                        jbcTsCache = jbcFactory.getCache(tsConfig, true);
+                    }
+                }
+                
+                if (jbcQueryCache != null) {
+                   configureTransactionManager(jbcQueryCache, tm, false);
+                   jbcQueryCache.start();
+                   // TODO: I considered validating the presence of the TS cache here,
+                   // but decided to defer unti getQueryCacheInstance() in case the 
+                   // cache is never actually used
+                }                
+                if (jbcTsCache != null) {
+                   configureTransactionManager(jbcTsCache, tm, true);
+                   jbcTsCache.start();
+                   // TODO: I considered validating TS cache config here,
+                   // but decided to defer unti getTimestampsCacheInstance() in case the 
+                   // cache is never actually used
+                }
+            } 
+            else {
+                jbcTsCache = null;
+                jbcQueryCache = null;
+            }
+        } 
+        catch (CacheException ce) {
+            throw ce;
+        }
+        catch (Throwable t) {
+            throw new CacheException("Unable to start region factory", t);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void stop() {
+        releaseCaches();
+        if (selfCreatedFactory) {
+            ((CacheManagerImpl) jbcFactory).stop();
+        }
+    }
+
+    /**
+     * Injects the given TransactionManager into the cache.
+     * 
+     * @param cache    the cache. cannot be <code>null</code>
+     * @param tm        the transaction manager Hibernate recognizes
+     *                  May be <code>null</code>
+     * @param allowNull whether we accept a null transaction manager in the cache
+     *                  if <code>tm</code> is not <code>null</code>
+     * 
+     * @throws CacheException if <code>cache</code> is already started and is 
+     *                        configured with a different TransactionManager
+     *                        than the one we would inject
+     */
+    private void configureTransactionManager(Cache cache, TransactionManager tm, boolean allowNull) {
+        Configuration cacheConfig = cache.getConfiguration();
+        TransactionManager cacheTm = cacheConfig.getRuntimeConfig().getTransactionManager();
+        if (!safeEquals(tm, cacheTm)) {
+            if (cache.getCacheStatus() != CacheStatus.INSTANTIATED) {
+                // We can't change the TM on a running cache; just check
+                // if the cache has no TM and we're OK with that
+                if (!allowNull && cacheTm == null) {
+                    throw new CacheException("JBoss Cache is already started with no transaction manager configured");
+                } else {
+                   log.debug("JBoss Cache is already started with a transaction manager ("
+                         + cacheTm + ") that is not equal to our own (" + tm + ")");                   
+                }                
+            } else {
+                // Configure the cache to use our TM
+                cacheConfig.getRuntimeConfig().setTransactionManager(tm);
+                if (tm == null) {
+                    // Make sure JBC doesn't look one up
+                    cacheConfig.setTransactionManagerLookupClass(null);
+                }
+            }
+        }
+    }
+
+    /**
+     * Notify cache factory that we are no longer using the caches.  
+     */
+    private void releaseCaches() {
+        
+        // This method should be implemented assuming it's valid to 
+        // do start/stop/start -- leave state appropriate for another start
+        
+        if (jbcEntityCache != null  && entityConfig != null) {
+            try {
+                jbcFactory.releaseCache(entityConfig);
+                jbcEntityCache = null;
+                
+                // Make sure we don't re-release the same cache
+                if (entityConfig.equals(collectionConfig))
+                    collectionConfig = null;
+                if (entityConfig.equals(queryConfig))
+                    queryConfig = null;
+                if (entityConfig.equals(tsConfig))
+                    tsConfig = null;
+                entityConfig = null;
+            } catch (Throwable t) {
+                log.info("Unable to release entity cache instance", t);
+            }
+        }
+        if (jbcCollectionCache != null && collectionConfig != null) {
+            try {
+                jbcFactory.releaseCache(collectionConfig);
+                jbcCollectionCache = null;
+                
+                if (collectionConfig.equals(queryConfig))
+                    queryConfig = null;
+                if (collectionConfig.equals(tsConfig))
+                    tsConfig = null;
+                collectionConfig = null;
+            } catch (Throwable t) {
+                log.info("Unable to stop collection cache instance", t);
+            }
+        }
+        if (jbcQueryCache != null && queryConfig != null) {
+            try {
+                jbcFactory.releaseCache(queryConfig);
+                jbcQueryCache = null;
+                
+                if (queryConfig.equals(tsConfig))
+                    tsConfig = null;
+                queryConfig = null;
+            } catch (Throwable t) {
+                log.info("Unable to stop query cache instance", t);
+            }
+        }
+        if (jbcTsCache != null && tsConfig != null) {
+            try {
+                jbcFactory.releaseCache(tsConfig);
+                jbcTsCache = null;
+                
+                tsConfig = null;
+            } catch (Throwable t) {
+                log.info("Unable to stop timestamp cache instance", t);
+            }
+        }
+    }
+
+    private boolean safeEquals(Object a, Object b) {
+        return (a == b || (a != null && a.equals(b)));
+    }
+}
diff --git a/src/main/java/hibernate/cache/jbc/builder/SharedCacheInstanceManager.java b/src/main/java/hibernate/cache/jbc/builder/SharedCacheInstanceManager.java
new file mode 100644
index 0000000..5180340
--- /dev/null
+++ b/src/main/java/hibernate/cache/jbc/builder/SharedCacheInstanceManager.java
@@ -0,0 +1,274 @@
+/*
+ * 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.jbc.builder;
+
+import java.util.Properties;
+import javax.transaction.TransactionManager;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.jboss.cache.Cache;
+import org.jboss.cache.CacheStatus;
+import org.jboss.cache.DefaultCacheFactory;
+import org.jboss.cache.config.Configuration;
+import org.jgroups.ChannelFactory;
+import org.jgroups.JChannelFactory;
+
+import org.hibernate.cache.CacheException;
+import org.hibernate.cache.jbc.CacheInstanceManager;
+import org.hibernate.cache.jbc.util.CacheHelper;
+import org.hibernate.cfg.Settings;
+import org.hibernate.util.PropertiesHelper;
+
+/**
+ * A {@link CacheInstanceManager} implementation where we use a single JBoss Cache
+ * instance for each type of region. If operating on a cluster, the cache must
+ * be configured for REPL_SYNC if query caching is enabled. If query caching
+ * is not used, REPL_SYNC or INVALIDATION_SYNC are valid, with 
+ * INVALIDATION_SYNC preferred.
+ * 
+ * @author Steve Ebersole
+ * @author Brian Stansberry
+ */
+public class SharedCacheInstanceManager implements CacheInstanceManager {
+    
+    private static final Logger log = LoggerFactory.getLogger(SharedCacheInstanceManager.class);
+
+    /**
+     * Classpath or filesystem resource containing JBoss Cache 
+     * configuration settings the {@link Cache} should use.
+     * 
+     * @see #DEFAULT_CACHE_RESOURCE
+     */
+    public static final String CACHE_RESOURCE_PROP = "hibernate.cache.jbc.cfg.shared";
+    
+    /**
+     * Legacy name for configuration property {@link #CACHE_RESOURCE_PROP}.
+     * 
+     * @see #DEFAULT_CACHE_RESOURCE
+     */
+    public static final String LEGACY_CACHE_RESOURCE_PROP = "hibernate.cache.region.jbc2.cfg.shared";
+    
+    /**
+     * Default name for the JBoss Cache configuration file.
+     */
+    public static final String DEFAULT_CACHE_RESOURCE = "treecache.xml";
+    /**
+     * Classpath or filesystem resource containing JGroups protocol
+     * stack configurations the <code>org.jgroups.ChannelFactory</code>
+     * should use.
+     * 
+     * @see #DEF_JGROUPS_RESOURCE
+     */
+    public static final String CHANNEL_FACTORY_RESOURCE_PROP = "hibernate.cache.jbc.cfg.jgroups.stacks";
+    /**
+     * Legacy name for configuration property {@link #CHANNEL_FACTORY_RESOURCE_PROP}.
+     * 
+     * @see #DEF_JGROUPS_RESOURCE
+     */
+    public static final String LEGACY_CHANNEL_FACTORY_RESOURCE_PROP = "hibernate.cache.region.jbc2.cfg.jgroups.stacks";
+    /**
+     * Default value for {@link #CHANNEL_FACTORY_RESOURCE_PROP}.  Specifies
+     * the "jgroups-stacks.xml" file in this package.
+     */
+    public static final String DEF_JGROUPS_RESOURCE = "org/hibernate/cache/jbc/builder/jgroups-stacks.xml";
+
+    private Cache cache;
+    private ChannelFactory channelFactory;
+    private boolean use2ndLevel;
+    private boolean useQuery;
+    
+    public SharedCacheInstanceManager() {
+    }
+
+    public SharedCacheInstanceManager(ChannelFactory channelFactory) {
+        this.channelFactory = channelFactory;
+    }
+    
+    public SharedCacheInstanceManager(Cache cache) {
+        this.cache = cache;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Cache getEntityCacheInstance() {
+        return use2ndLevel ? cache : null;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Cache getCollectionCacheInstance() {
+        return use2ndLevel ? cache : null;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Cache getQueryCacheInstance() {
+        
+        if (!useQuery)
+            return null;
+        
+        if (CacheHelper.isClusteredInvalidation(cache)) {
+            throw new CacheException("Query cache not supported for clustered invalidation");
+        }
+        return cache;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void start(Settings settings, Properties properties) throws CacheException {
+
+        use2ndLevel = settings.isSecondLevelCacheEnabled();
+        useQuery = settings.isQueryCacheEnabled();
+        
+        if (cache == null) {
+            
+            if (channelFactory == null) {
+                String muxStacks = PropertiesHelper.getString(CHANNEL_FACTORY_RESOURCE_PROP, properties, null);
+                if (muxStacks == null) {
+                	PropertiesHelper.getString(LEGACY_CHANNEL_FACTORY_RESOURCE_PROP, properties, DEF_JGROUPS_RESOURCE);
+                }
+                if (muxStacks != null) {
+                    channelFactory = new JChannelFactory();
+                    try {
+                        channelFactory.setMultiplexerConfig(muxStacks);
+                    }
+                    catch (Exception e) {
+                        throw new CacheException("Problem setting ChannelFactory config", e);
+                    }
+                }
+            }
+            cache = createSharedCache(settings, properties);
+            configureTransactionManager(cache, settings, properties);
+            if (cache.getConfiguration().getMultiplexerStack() != null
+                    && cache.getConfiguration().getRuntimeConfig().getMuxChannelFactory() == null) {
+                cache.getConfiguration().getRuntimeConfig().setMuxChannelFactory(channelFactory);
+            }
+        }
+        cache.start();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Cache getTimestampsCacheInstance() {
+        
+        if (!useQuery)
+            return null;
+        
+        if (CacheHelper.isClusteredInvalidation(cache)) {
+            throw new CacheException("Query cache not supported for clustered invalidation");
+        }
+        return cache;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public void stop() {
+        if (cache != null) {
+            stopSharedCache(cache);
+        }
+    }
+
+    /**
+     * Create a cache using the given settings and properties.
+     *
+     * @param settings The Hibernate settings
+     * @param properties The configuration properties
+     * @return The created cache
+     */
+    protected Cache createSharedCache(Settings settings, Properties properties)
+    {
+        String configResource = PropertiesHelper.getString(CACHE_RESOURCE_PROP, properties, null);
+        if (configResource == null) {
+        	configResource = PropertiesHelper.getString(LEGACY_CACHE_RESOURCE_PROP, properties, DEFAULT_CACHE_RESOURCE);
+        }
+        return new DefaultCacheFactory().createCache(configResource, false);
+    }
+    
+    /**
+     * Injects the TransactionManager found via {@link Settings#getTransactionManagerLookup()}
+     * into the cache.
+     * 
+     * @param cache The cache instance
+     * @param settings The Hibernate settings
+     * @param properties The configuration properties
+     * 
+     * @throws CacheException if <code>cache</code> is already started and is 
+     *                        configured with a different TransactionManager
+     *                        than the one we would inject
+     */
+    protected void configureTransactionManager(Cache cache, Settings settings, Properties properties) {
+        
+        TransactionManager tm = null;
+        if (settings.getTransactionManagerLookup() != null) {
+            tm = settings.getTransactionManagerLookup().getTransactionManager(properties);
+        }
+        
+        Configuration cacheConfig = cache.getConfiguration();
+        TransactionManager cacheTm = cacheConfig.getRuntimeConfig().getTransactionManager();
+        
+        if (!safeEquals(tm, cacheTm)) {            
+            if (cache.getCacheStatus() != CacheStatus.INSTANTIATED
+                    && cache.getCacheStatus() != CacheStatus.DESTROYED) {
+               log.debug("JBoss Cache is already started with a transaction manager ("
+                     + cacheTm + ") that is not equal to our own (" + tm + ")");    
+            } else {
+                // Configure the cache to use our TM
+                cacheConfig.getRuntimeConfig().setTransactionManager(tm);
+                if (tm == null) {
+                    // Make sure JBC doesn't look one up
+                    cacheConfig.setTransactionManagerLookupClass(null);
+                }
+            }
+        }
+    }
+
+    private boolean safeEquals(Object a, Object b) {
+        return (a == b || (a != null && a.equals(b)));
+    }
+
+    /**
+     * Stops the shared cache.
+     * @param cache the shared cache
+     */
+    protected void stopSharedCache(Cache cache) {
+        try {
+            if (cache.getCacheStatus() == CacheStatus.STARTED) {
+                cache.stop();
+            }
+            if (cache.getCacheStatus() != CacheStatus.DESTROYED
+                    && cache.getCacheStatus() != CacheStatus.INSTANTIATED) {
+                cache.destroy();
+            }
+        } catch (Throwable t) {
+            log.warn("Unable to stop cache instance", t);
+        }
+    }
+}
diff --git a/src/main/java/hibernate/cache/jbc/builder/jbc-configs.xml b/src/main/java/hibernate/cache/jbc/builder/jbc-configs.xml
new file mode 100644
index 0000000..baad4f9
--- /dev/null
+++ b/src/main/java/hibernate/cache/jbc/builder/jbc-configs.xml
@@ -0,0 +1,1143 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+  ~ 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
+  -->
+<cache-configs>
+
+    <!-- 
+     Various JBoss Cache configurations, suitable for different caching
+     uses (e.g. entities vs. queries).
+     
+     In all cases, TransactionManager configuration not required.
+     Hibernate will plug in its own transaction manager integration. 
+    -->
+    
+    
+    <!-- A config appropriate for entity/collection caching. -->
+    <cache-config name="optimistic-entity">
+
+        <!-- Node locking scheme -->
+        <attribute name="NodeLockingScheme">OPTIMISTIC</attribute>
+
+        <!-- Mode of communication with peer caches.
+        
+             INVALIDATION_SYNC is highly recommended as the mode for use
+             with entity and collection caches.
+        -->
+        <attribute name="CacheMode">INVALIDATION_SYNC</attribute>
+
+        <!-- Name of cluster. Needs to be the same for all members, in order
+             to find each other -->
+        <attribute name="ClusterName">optimistic-entity</attribute>
+        
+        <!-- Use a UDP (multicast) based stack. A udp-sync stack might be
+             slightly better (no JGroups FC) but we stick with udp to
+             help ensure this cache and others like timestamps-cache
+             that require FC can use the same underlying JGroups resources. -->
+        <attribute name="MultiplexerStack">udp</attribute>
+
+        <!-- Whether or not to fetch state on joining a cluster. -->
+        <attribute name="FetchInMemoryState">false</attribute>
+
+        <!--
+          The max amount of time (in milliseconds) we wait until the
+          state (ie. the contents of the cache) are retrieved from
+          existing members at startup. Ignored if FetchInMemoryState=false.
+        -->
+        <attribute name="StateRetrievalTimeout">20000</attribute>
+
+        <!--
+            Number of milliseconds to wait until all responses for a
+            synchronous call have been received.
+        -->
+        <attribute name="SyncReplTimeout">20000</attribute>
+
+        <!-- Max number of milliseconds to wait for a lock acquisition -->
+        <attribute name="LockAcquisitionTimeout">15000</attribute>
+        
+        <!--  Lock Striping can lead to deadlocks -->
+        <attribute name="UseLockStriping">false</attribute>
+
+        <!--
+           Indicate whether to use marshalling or not. Set this to true if you 
+           are running under a scoped class loader, e.g., inside an application 
+           server.
+        -->
+        <attribute name="UseRegionBasedMarshalling">true</attribute>
+        <!-- Must match the value of "useRegionBasedMarshalling" -->
+        <attribute name="InactiveOnStartup">true</attribute>
+
+        <!-- For now. disable asynchronous RPC marshalling/sending -->
+        <attribute name="SerializationExecutorPoolSize">0</attribute>
+
+      <!--  Eviction policy configurations. -->
+      <attribute name="EvictionPolicyConfig">
+        <config>
+          <attribute name="wakeUpIntervalSeconds">5</attribute>
+          <!-- Name of the DEFAULT eviction policy class. -->
+          <attribute name="policyClass">org.jboss.cache.eviction.LRUPolicy</attribute>
+          <!--  Cache wide default -->
+          <region name="/_default_">
+            <!-- Evict LRU node once we have more than this number of nodes -->
+            <attribute name="maxNodes">10000</attribute>
+            <!-- And, evict any node that hasn't been accessed in this many seconds -->
+            <attribute name="timeToLiveSeconds">1000</attribute>
+            <!-- Don't evict a node that's been accessed within this many seconds. 
+                 Set this to a value greater than your max expected transaction length. -->
+            <attribute name="minTimeToLiveSeconds">120</attribute>
+          </region>
+          <!--  Don't ever evict modification timestamps -->
+          <region name="/TS" policyClass="org.jboss.cache.eviction.NullEvictionPolicy"/>
+        </config>
+     </attribute>
+
+    </cache-config>   
+    
+    
+    <!-- A config appropriate for entity/collection caching that
+         uses pessimistic locking -->
+    <cache-config name="pessimistic-entity">
+
+        <!-- Node locking scheme -->
+        <attribute name="NodeLockingScheme">PESSIMISTIC</attribute>
+
+        <!--
+            READ_COMMITTED is as strong as necessary for most 
+            2nd Level Cache use cases.
+        -->
+        <attribute name="IsolationLevel">READ_COMMITTED</attribute>
+
+        <!-- Mode of communication with peer caches.
+        
+             INVALIDATION_SYNC is highly recommended as the mode for use
+             with entity and collection caches.
+        -->
+        <attribute name="CacheMode">INVALIDATION_SYNC</attribute>
+
+        <!-- Name of cluster. Needs to be the same for all members, in order
+             to find each other -->
+        <attribute name="ClusterName">pessimistic-entity</attribute>
+        
+        <!-- Use a UDP (multicast) based stack. A udp-sync stack might be
+             slightly better (no JGroups FC) but we stick with udp to
+             help ensure this cache and others like timestamps-cache
+             that require FC can use the same underlying JGroups resources. -->
+        <attribute name="MultiplexerStack">udp</attribute>
+
+        <!-- Whether or not to fetch state on joining a cluster. -->
+        <attribute name="FetchInMemoryState">false</attribute>
+
+        <!--
+          The max amount of time (in milliseconds) we wait until the
+          state (ie. the contents of the cache) are retrieved from
+          existing members at startup. Ignored if FetchInMemoryState=false.
+        -->
+        <attribute name="StateRetrievalTimeout">20000</attribute>
+
+        <!--
+            Number of milliseconds to wait until all responses for a
+            synchronous call have been received.
+        -->
+        <attribute name="SyncReplTimeout">20000</attribute>
+
+        <!-- Max number of milliseconds to wait for a lock acquisition -->
+        <attribute name="LockAcquisitionTimeout">15000</attribute>
+        
+        <!--  Lock Striping can lead to deadlocks -->
+        <attribute name="UseLockStriping">false</attribute>
+
+       <!--
+          Indicate whether to use marshalling or not. Set this to true if you 
+          are running under a scoped class loader, e.g., inside an application 
+          server.
+       -->
+       <attribute name="UseRegionBasedMarshalling">true</attribute>
+       <!-- Must match the value of "useRegionBasedMarshalling" -->
+       <attribute name="InactiveOnStartup">true</attribute>
+
+       <!-- For now. disable asynchronous RPC marshalling/sending -->
+       <attribute name="SerializationExecutorPoolSize">0</attribute>
+
+       <!--  Eviction policy configurations. -->
+       <attribute name="EvictionPolicyConfig">
+        <config>
+          <attribute name="wakeUpIntervalSeconds">5</attribute>
+          <!-- Name of the DEFAULT eviction policy class. -->
+          <attribute name="policyClass">org.jboss.cache.eviction.LRUPolicy</attribute>
+          <!--  Cache wide default -->
+          <region name="/_default_">
+            <!-- Evict LRU node once we have more than this number of nodes -->
+            <attribute name="maxNodes">10000</attribute>
+            <!-- And, evict any node that hasn't been accessed in this many seconds -->
+            <attribute name="timeToLiveSeconds">1000</attribute>
+            <!-- Don't evict a node that's been accessed within this many seconds. 
+                 Set this to a value greater than your max expected transaction length. -->
+            <attribute name="minTimeToLiveSeconds">120</attribute>
+          </region>
+          <!--  Don't ever evict modification timestamps -->
+          <region name="/TS" policyClass="org.jboss.cache.eviction.NullEvictionPolicy"/>
+        </config>
+     </attribute>
+
+    </cache-config>      
+
+    <!-- A config appropriate for entity/collection caching that
+         uses mvcc locking -->
+    <cache-config name="mvcc-entity">
+
+        <!-- Node locking scheme -->
+        <attribute name="NodeLockingScheme">MVCC</attribute>
+
+        <!--
+            READ_COMMITTED is as strong as necessary for most 
+            2nd Level Cache use cases.
+        -->
+        <attribute name="IsolationLevel">READ_COMMITTED</attribute>
+
+        <!-- Mode of communication with peer caches.
+        
+             INVALIDATION_SYNC is highly recommended as the mode for use
+             with entity and collection caches.
+        -->
+        <attribute name="CacheMode">INVALIDATION_SYNC</attribute>
+
+        <!-- Name of cluster. Needs to be the same for all members, in order
+             to find each other -->
+        <attribute name="ClusterName">mvcc-entity</attribute>
+        
+        <!-- Use a UDP (multicast) based stack. A udp-sync stack might be
+             slightly better (no JGroups FC) but we stick with udp to
+             help ensure this cache and others like timestamps-cache
+             that require FC can use the same underlying JGroups resources. -->
+        <attribute name="MultiplexerStack">udp</attribute>
+
+        <!-- Whether or not to fetch state on joining a cluster. -->
+        <attribute name="FetchInMemoryState">false</attribute>
+
+        <!--
+          The max amount of time (in milliseconds) we wait until the
+          state (ie. the contents of the cache) are retrieved from
+          existing members at startup. Ignored if FetchInMemoryState=false.
+        -->
+        <attribute name="StateRetrievalTimeout">20000</attribute>
+
+        <!--
+            Number of milliseconds to wait until all responses for a
+            synchronous call have been received.
+        -->
+        <attribute name="SyncReplTimeout">20000</attribute>
+
+        <!-- Max number of milliseconds to wait for a lock acquisition -->
+        <attribute name="LockAcquisitionTimeout">15000</attribute>
+        
+        <!--  Lock Striping can lead to deadlocks -->
+        <attribute name="UseLockStriping">false</attribute>
+
+       <!--
+          Indicate whether to use marshalling or not. Set this to true if you 
+          are running under a scoped class loader, e.g., inside an application 
+          server.
+       -->
+       <attribute name="UseRegionBasedMarshalling">true</attribute>
+       <!-- Must match the value of "useRegionBasedMarshalling" -->
+       <attribute name="InactiveOnStartup">true</attribute>
+
+       <!-- For now. disable asynchronous RPC marshalling/sending -->
+       <attribute name="SerializationExecutorPoolSize">0</attribute>
+
+       <!--  Eviction policy configurations. -->
+       <attribute name="EvictionPolicyConfig">
+        <config>
+          <attribute name="wakeUpIntervalSeconds">5</attribute>
+          <!-- Name of the DEFAULT eviction policy class. -->
+          <attribute name="policyClass">org.jboss.cache.eviction.LRUPolicy</attribute>
+          <!--  Cache wide default -->
+          <region name="/_default_">
+            <!-- Evict LRU node once we have more than this number of nodes -->
+            <attribute name="maxNodes">10000</attribute>
+            <!-- And, evict any node that hasn't been accessed in this many seconds -->
+            <attribute name="timeToLiveSeconds">1000</attribute>
+            <!-- Don't evict a node that's been accessed within this many seconds. 
+                 Set this to a value greater than your max expected transaction length. -->
+            <attribute name="minTimeToLiveSeconds">120</attribute>
+          </region>
+          <!--  Don't ever evict modification timestamps -->
+          <region name="/TS" policyClass="org.jboss.cache.eviction.NullEvictionPolicy"/>
+        </config>
+     </attribute>
+
+    </cache-config>      
+    
+    
+
+    <!-- Same as "pessimistic-entity" but here we use REPEATABLE_READ
+         instead of READ_COMMITTED. REPEATABLE_READ is only useful if the 
+         application evicts/clears entities from the Hibernate Session and 
+         then expects to repeatably re-read them in the same transaction.
+         Otherwise, the Session's internal cache provides a repeatable-read 
+         semantic. Before choosing this config, carefully read the docs
+         and make sure you really need REPEATABLE_READ.
+    -->
+    <cache-config name="pessimistic-entity-repeatable">
+
+        <!-- Node locking scheme -->
+        <attribute name="NodeLockingScheme">PESSIMISTIC</attribute>
+
+        <!-- Here we  use REPEATABLE_READ. -->
+        <attribute name="IsolationLevel">REPEATABLE_READ</attribute>
+
+        <!-- Mode of communication with peer caches.
+        
+             INVALIDATION_SYNC is highly recommended as the mode for use
+             with entity and collection caches.
+        -->
+        <attribute name="CacheMode">INVALIDATION_SYNC</attribute>
+
+        <!-- Name of cluster. Needs to be the same for all members, in order
+             to find each other -->
+        <attribute name="ClusterName">pessimistic-entity-rr</attribute>
+        
+        <!-- Use a UDP (multicast) based stack. A udp-sync stack might be
+             slightly better (no JGroups FC) but we stick with udp to
+             help ensure this cache and others like timestamps-cache
+             that require FC can use the same underlying JGroups resources. -->
+        <attribute name="MultiplexerStack">udp</attribute>
+
+        <!-- Whether or not to fetch state on joining a cluster. -->
+        <attribute name="FetchInMemoryState">false</attribute>
+
+        <!--
+          The max amount of time (in milliseconds) we wait until the
+          state (ie. the contents of the cache) are retrieved from
+          existing members at startup. Ignored if FetchInMemoryState=false.
+        -->
+        <attribute name="StateRetrievalTimeout">20000</attribute>
+
+        <!--
+            Number of milliseconds to wait until all responses for a
+            synchronous call have been received.
+        -->
+        <attribute name="SyncReplTimeout">20000</attribute>
+
+        <!-- Max number of milliseconds to wait for a lock acquisition -->
+        <attribute name="LockAcquisitionTimeout">15000</attribute>
+        
+        <!--  Lock Striping can lead to deadlocks -->
+        <attribute name="UseLockStriping">false</attribute>
+
+        <!--
+           Indicate whether to use marshalling or not. Set this to true if you 
+           are running under a scoped class loader, e.g., inside an application 
+           server.
+        -->
+        <attribute name="UseRegionBasedMarshalling">true</attribute>
+        <!-- Must match the value of "useRegionBasedMarshalling" -->
+        <attribute name="InactiveOnStartup">true</attribute>
+
+        <!-- For now. disable asynchronous RPC marshalling/sending -->
+        <attribute name="SerializationExecutorPoolSize">0</attribute>
+
+       <!--  Eviction policy configurations. -->
+       <attribute name="EvictionPolicyConfig">
+        <config>
+          <attribute name="wakeUpIntervalSeconds">5</attribute>
+          <!-- Name of the DEFAULT eviction policy class. -->
+          <attribute name="policyClass">org.jboss.cache.eviction.LRUPolicy</attribute>
+          <!--  Cache wide default -->
+          <region name="/_default_">
+            <!-- Evict LRU node once we have more than this number of nodes -->
+            <attribute name="maxNodes">10000</attribute>
+            <!-- And, evict any node that hasn't been accessed in this many seconds -->
+            <attribute name="timeToLiveSeconds">1000</attribute>
+            <!-- Don't evict a node that's been accessed within this many seconds. 
+                 Set this to a value greater than your max expected transaction length. -->
+            <attribute name="minTimeToLiveSeconds">120</attribute>
+          </region>
+          <!--  Don't ever evict modification timestamps -->
+          <region name="/TS" policyClass="org.jboss.cache.eviction.NullEvictionPolicy"/>
+        </config>
+     </attribute>
+
+    </cache-config>    
+
+
+    <!-- Same as "mvcc-entity" but here we use REPEATABLE_READ
+         instead of READ_COMMITTED. REPEATABLE_READ is only useful if the 
+         application evicts/clears entities from the Hibernate Session and 
+         then expects to repeatably re-read them in the same transaction.
+         Otherwise, the Session's internal cache provides a repeatable-read 
+         semantic. Before choosing this config, carefully read the docs
+         and make sure you really need REPEATABLE_READ.
+    -->
+    <cache-config name="mvcc-entity-repeatable">
+
+        <!-- Node locking scheme -->
+        <attribute name="NodeLockingScheme">MVCC</attribute>
+
+        <!-- Here we  use REPEATABLE_READ. -->
+        <attribute name="IsolationLevel">REPEATABLE_READ</attribute>
+
+        <!-- Mode of communication with peer caches.
+        
+             INVALIDATION_SYNC is highly recommended as the mode for use
+             with entity and collection caches.
+        -->
+        <attribute name="CacheMode">INVALIDATION_SYNC</attribute>
+
+        <!-- Name of cluster. Needs to be the same for all members, in order
+             to find each other -->
+        <attribute name="ClusterName">mvcc-entity-rr</attribute>
+        
+        <!-- Use a UDP (multicast) based stack. A udp-sync stack might be
+             slightly better (no JGroups FC) but we stick with udp to
+             help ensure this cache and others like timestamps-cache
+             that require FC can use the same underlying JGroups resources. -->
+        <attribute name="MultiplexerStack">udp</attribute>
+
+        <!-- Whether or not to fetch state on joining a cluster. -->
+        <attribute name="FetchInMemoryState">false</attribute>
+
+        <!--
+          The max amount of time (in milliseconds) we wait until the
+          state (ie. the contents of the cache) are retrieved from
+          existing members at startup. Ignored if FetchInMemoryState=false.
+        -->
+        <attribute name="StateRetrievalTimeout">20000</attribute>
+
+        <!--
+            Number of milliseconds to wait until all responses for a
+            synchronous call have been received.
+        -->
+        <attribute name="SyncReplTimeout">20000</attribute>
+
+        <!-- Max number of milliseconds to wait for a lock acquisition -->
+        <attribute name="LockAcquisitionTimeout">15000</attribute>
+        
+        <!--  Lock Striping can lead to deadlocks -->
+        <attribute name="UseLockStriping">false</attribute>
+
+        <!--
+           Indicate whether to use marshalling or not. Set this to true if you 
+           are running under a scoped class loader, e.g., inside an application 
+           server.
+        -->
+        <attribute name="UseRegionBasedMarshalling">true</attribute>
+        <!-- Must match the value of "useRegionBasedMarshalling" -->
+        <attribute name="InactiveOnStartup">true</attribute>
+
+        <!-- For now. disable asynchronous RPC marshalling/sending -->
+        <attribute name="SerializationExecutorPoolSize">0</attribute>
+
+       <!--  Eviction policy configurations. -->
+       <attribute name="EvictionPolicyConfig">
+        <config>
+          <attribute name="wakeUpIntervalSeconds">5</attribute>
+          <!-- Name of the DEFAULT eviction policy class. -->
+          <attribute name="policyClass">org.jboss.cache.eviction.LRUPolicy</attribute>
+          <!--  Cache wide default -->
+          <region name="/_default_">
+            <!-- Evict LRU node once we have more than this number of nodes -->
+            <attribute name="maxNodes">10000</attribute>
+            <!-- And, evict any node that hasn't been accessed in this many seconds -->
+            <attribute name="timeToLiveSeconds">1000</attribute>
+            <!-- Don't evict a node that's been accessed within this many seconds. 
+                 Set this to a value greater than your max expected transaction length. -->
+            <attribute name="minTimeToLiveSeconds">120</attribute>
+          </region>
+          <!--  Don't ever evict modification timestamps -->
+          <region name="/TS" policyClass="org.jboss.cache.eviction.NullEvictionPolicy"/>
+        </config>
+     </attribute>
+
+    </cache-config>    
+
+    <!-- A config appropriate for query caching. Does not replicate
+         queries. DO NOT STORE TIMESTAMPS IN THIS CACHE.
+    -->
+    <cache-config name="local-query">
+
+        <!-- Node locking scheme -->
+        <attribute name="NodeLockingScheme">OPTIMISTIC</attribute>
+
+        <!-- Mode of communication with peer caches.
+        
+             LOCAL means don't communicate with other caches.
+        -->
+        <attribute name="CacheMode">LOCAL</attribute>
+
+        <!-- Max number of milliseconds to wait for a lock acquisition -->
+        <attribute name="LockAcquisitionTimeout">15000</attribute>
+        
+        <!--  Lock Striping can lead to deadlocks -->
+        <attribute name="UseLockStriping">false</attribute>
+
+        <!--  Eviction policy configurations. -->
+        <attribute name="EvictionPolicyConfig">
+          <config>
+            <attribute name="wakeUpIntervalSeconds">5</attribute>
+            <!-- Name of the DEFAULT eviction policy class. -->
+            <attribute name="policyClass">org.jboss.cache.eviction.LRUPolicy</attribute>
+            <!--  Cache wide default -->
+            <region name="/_default_">
+               <!-- Evict LRU node once we have more than this number of nodes -->
+               <attribute name="maxNodes">10000</attribute>
+               <!-- And, evict any node that hasn't been accessed in this many seconds -->
+               <attribute name="timeToLiveSeconds">1000</attribute>
+               <!-- Don't evict a node that's been accessed within this many seconds. 
+                    Set this to a value greater than your max expected transaction length. -->
+               <attribute name="minTimeToLiveSeconds">120</attribute>
+            </region>
+            <!--  Don't ever evict modification timestamps -->
+            <region name="/TS" policyClass="org.jboss.cache.eviction.NullEvictionPolicy"/>
+          </config>
+       </attribute>
+
+    </cache-config>   
+    
+    
+
+    <!-- A query cache that replicates queries. Replication is asynchronous.
+         DO NOT STORE TIMESTAMPS IN THIS CACHE as no initial state transfer
+         is performed.
+    -->
+    <cache-config name="replicated-query">
+
+        <!-- Node locking scheme -->
+        <attribute name="NodeLockingScheme">OPTIMISTIC</attribute>
+
+        <!-- Mode of communication with peer caches.
+        
+             REPL_ASYNC means replicate but sender does not block waiting for
+             peers to acknowledge applying the change. Valid for queries as
+             the timestamp cache mechanism will allow Hibernate to discard
+             out-of-date queries.
+        -->
+        <attribute name="CacheMode">REPL_ASYNC</attribute>
+
+        <!-- Name of cluster. Needs to be the same for all members, in order
+             to find each other -->
+        <attribute name="ClusterName">replicated-query</attribute>
+        
+        <!-- Use a UDP (multicast) based stack -->
+        <attribute name="MultiplexerStack">udp</attribute>
+
+        <!-- Whether or not to fetch state on joining a cluster. -->
+        <attribute name="FetchInMemoryState">false</attribute>
+
+        <!--
+          The max amount of time (in milliseconds) we wait until the
+          state (ie. the contents of the cache) are retrieved from
+          existing members at startup. Ignored if FetchInMemoryState=false.
+        -->
+        <attribute name="StateRetrievalTimeout">20000</attribute>
+
+        <!--
+            Number of milliseconds to wait until all responses for a
+            synchronous call have been received.
+        -->
+        <attribute name="SyncReplTimeout">20000</attribute>
+
+        <!-- Max number of milliseconds to wait for a lock acquisition -->
+        <attribute name="LockAcquisitionTimeout">15000</attribute>
+        
+        <!--  Lock Striping can lead to deadlocks -->
+        <attribute name="UseLockStriping">false</attribute>
+
+        <!--
+           Indicate whether to use marshalling or not. Set this to true if you 
+           are running under a scoped class loader, e.g., inside an application 
+           server. Default is "false".
+        -->
+        <attribute name="UseRegionBasedMarshalling">true</attribute>
+        <!-- Must match the value of "useRegionBasedMarshalling" -->
+        <attribute name="InactiveOnStartup">true</attribute>
+
+        <!-- For now. disable asynchronous RPC marshalling/sending -->
+        <attribute name="SerializationExecutorPoolSize">0</attribute>
+
+       <!--  Eviction policy configurations. -->
+       <attribute name="EvictionPolicyConfig">
+        <config>
+          <attribute name="wakeUpIntervalSeconds">5</attribute>
+          <!-- Name of the DEFAULT eviction policy class. -->
+          <attribute name="policyClass">org.jboss.cache.eviction.LRUPolicy</attribute>
+          <!--  Cache wide default -->
+          <region name="/_default_">
+            <!-- Evict LRU node once we have more than this number of nodes -->
+            <attribute name="maxNodes">10000</attribute>
+            <!-- And, evict any node that hasn't been accessed in this many seconds -->
+            <attribute name="timeToLiveSeconds">1000</attribute>
+            <!-- Don't evict a node that's been accessed within this many seconds. 
+                 Set this to a value greater than your max expected transaction length. -->
+            <attribute name="minTimeToLiveSeconds">120</attribute>
+          </region>
+          <!--  Don't ever evict modification timestamps -->
+          <region name="/TS" policyClass="org.jboss.cache.eviction.NullEvictionPolicy"/>
+        </config>
+     </attribute>
+
+    </cache-config>     
+    
+    
+
+    <!-- Optimized for timestamp caching. A clustered timestamp cache
+         is required if query caching is used, even if the query cache
+         itself is configured with CacheMode=LOCAL.
+    -->
+    <cache-config name="timestamps-cache">
+
+        <!-- Node locking scheme -->
+        <attribute name="NodeLockingScheme">MVCC</attribute>
+
+        <!--
+            READ_COMMITTED is as strong as necessary.
+        -->
+        <attribute name="IsolationLevel">READ_COMMITTED</attribute>
+
+        <!-- Cannot be INVALIDATION. ASYNC for improved performance. -->
+        <attribute name="CacheMode">REPL_ASYNC</attribute>
+
+        <!-- Name of cluster. Needs to be the same for all members, in order
+             to find each other -->
+        <attribute name="ClusterName">timestamp-cache</attribute>
+        
+        <!-- Use a UDP (multicast) based stack -->
+        <attribute name="MultiplexerStack">udp</attribute>
+
+        <!-- Used for timestamps, so must fetch state. -->
+        <attribute name="FetchInMemoryState">true</attribute>
+
+        <!--
+          The max amount of time (in milliseconds) we wait until the
+          state (ie. the contents of the cache) are retrieved from
+          existing members at startup. Ignored if FetchInMemoryState=false.
+        -->
+        <attribute name="StateRetrievalTimeout">20000</attribute>
+
+        <!--
+            Number of milliseconds to wait until all responses for a
+            synchronous call have been received.
+        -->
+        <attribute name="SyncReplTimeout">20000</attribute>
+
+        <!-- Max number of milliseconds to wait for a lock acquisition -->
+        <attribute name="LockAcquisitionTimeout">15000</attribute>
+        
+        <!--  Lock Striping can lead to deadlocks -->
+        <attribute name="UseLockStriping">false</attribute>
+
+        <!--
+           Indicate whether to use marshalling or not. Set this to true if you 
+           are running under a scoped class loader, e.g., inside an application 
+           server. Default is "false".
+        -->
+        <attribute name="UseRegionBasedMarshalling">true</attribute>
+        <!-- Must match the value of "useRegionBasedMarshalling" -->
+        <attribute name="InactiveOnStartup">true</attribute>
+
+        <!-- For now. disable asynchronous RPC marshalling/sending -->
+        <attribute name="SerializationExecutorPoolSize">0</attribute>
+
+      <!--  Eviction policy configurations. -->
+      <attribute name="EvictionPolicyConfig">
+        <config>
+          <attribute name="wakeUpIntervalSeconds">5</attribute>
+          <!-- Name of the DEFAULT eviction policy class. -->
+          <attribute name="policyClass">org.jboss.cache.eviction.LRUPolicy</attribute>
+          <!--  Cache wide default -->
+          <region name="/_default_">
+            <!-- Evict LRU node once we have more than this number of nodes -->
+            <attribute name="maxNodes">10000</attribute>
+            <!-- And, evict any node that hasn't been accessed in this many seconds -->
+            <attribute name="timeToLiveSeconds">1000</attribute>
+            <!-- Don't evict a node that's been accessed within this many seconds. 
+                 Set this to a value greater than your max expected transaction length. -->
+            <attribute name="minTimeToLiveSeconds">120</attribute>
+          </region>
+          <!--  Don't ever evict modification timestamps -->
+          <region name="/TS" policyClass="org.jboss.cache.eviction.NullEvictionPolicy"/>
+        </config>
+     </attribute>
+
+    </cache-config>  
+    
+    
+
+    <!-- A config appropriate for a cache that's shared for
+         entity, collection, query and timestamp caching. Not an advised
+         configuration, since it requires cache mode REPL_SYNC, which is the 
+         least efficient mode. Also requires a full state transfer at startup,
+         which can be expensive. Uses optimistic locking -->
+    <cache-config name="optimistic-shared">
+
+        <!-- Node locking scheme:
+                OPTIMISTIC
+                MVCC (default)
+        -->
+        <attribute name="NodeLockingScheme">OPTIMISTIC</attribute>
+
+        <!-- Must use REPL since used for timestamp caching. 
+             Must use SYNC to maintain cache coherency for entities.
+        -->
+        <attribute name="CacheMode">REPL_SYNC</attribute>
+        
+        <!-- With OPTIMISTIC  with replication we need to use synchronous commits. -->
+        <attribute name="SyncCommitPhase">true</attribute>
+        <attribute name="SyncRollbackPhase">true</attribute>
+        
+        <!-- Name of cluster. Needs to be the same for all members, in order
+             to find each other -->
+        <attribute name="ClusterName">optimistic-shared</attribute>
+        
+        <!-- Use a UDP (multicast) based stack. Need JGroups flow control (FC)
+             because timestamp communication will not require a synchronous response.
+        -->
+        <attribute name="MultiplexerStack">udp</attribute>
+
+        <!-- Used for timestamps, so must fetch state. -->
+        <attribute name="FetchInMemoryState">true</attribute>
+
+        <!--
+          The max amount of time (in milliseconds) we wait until the
+          state (ie. the contents of the cache) are retrieved from
+          existing members at startup. Ignored if FetchInMemoryState=false.
+        -->
+        <attribute name="StateRetrievalTimeout">20000</attribute>
+
+        <!--
+            Number of milliseconds to wait until all responses for a
+            synchronous call have been received.
+        -->
+        <attribute name="SyncReplTimeout">20000</attribute>
+
+        <!-- Max number of milliseconds to wait for a lock acquisition -->
+        <attribute name="LockAcquisitionTimeout">15000</attribute>
+        
+        <!--  Lock Striping can lead to deadlocks -->
+        <attribute name="UseLockStriping">false</attribute>
+
+        <!--
+          Indicate whether to use marshalling or not. Set this to true if you are running under a scoped
+          class loader, e.g., inside an application server. Default is "false".
+        -->
+        <attribute name="UseRegionBasedMarshalling">true</attribute>
+        <!-- Must match the value of "useRegionBasedMarshalling" -->
+        <attribute name="InactiveOnStartup">true</attribute>
+
+        <!-- For now. disable asynchronous RPC marshalling/sending -->
+        <attribute name="SerializationExecutorPoolSize">0</attribute>
+
+      <!--  Eviction policy configurations. -->
+      <attribute name="EvictionPolicyConfig">
+        <config>
+          <attribute name="wakeUpIntervalSeconds">5</attribute>
+          <!-- Name of the DEFAULT eviction policy class. -->
+          <attribute name="policyClass">org.jboss.cache.eviction.LRUPolicy</attribute>
+          <!--  Cache wide default -->
+          <region name="/_default_">
+            <!-- Evict LRU node once we have more than this number of nodes -->
+            <attribute name="maxNodes">10000</attribute>
+            <!-- And, evict any node that hasn't been accessed in this many seconds -->
+            <attribute name="timeToLiveSeconds">1000</attribute>
+            <!-- Don't evict a node that's been accessed within this many seconds. 
+                 Set this to a value greater than your max expected transaction length. -->
+            <attribute name="minTimeToLiveSeconds">120</attribute>
+          </region>
+          <!--  Don't ever evict modification timestamps -->
+          <region name="/TS" policyClass="org.jboss.cache.eviction.NullEvictionPolicy"/>
+        </config>
+     </attribute>
+
+    </cache-config>   
+    
+    
+
+    <!-- A config appropriate for a cache that's shared for
+         entity, collection, query and timestamp caching. Not an advised
+         configuration, since it requires cache mode REPL_SYNC, which is the 
+         least efficient mode. Also requires a full state transfer at startup,
+         which can be expensive. Uses pessmistic locking.
+    -->
+    <cache-config name="pessimistic-shared">
+
+        <!-- TransactionManager configuration not required for Hibernate!
+             Hibernate will plug in its own transaction manager integration. 
+        -->
+
+        <!-- Node locking scheme -->
+        <attribute name="NodeLockingScheme">PESSIMISTIC</attribute>
+
+        <!--
+            READ_COMMITTED is as strong as necessary for most 
+            2nd Level Cache use cases.
+        -->
+        <attribute name="IsolationLevel">READ_COMMITTED</attribute>
+
+        <!-- Must use REPL since used for timestamp caching. 
+             Must use SYNC to maintain cache coherency for entities.
+        -->
+        <attribute name="CacheMode">REPL_SYNC</attribute>
+
+        <!-- Name of cluster. Needs to be the same for all members, in order
+             to find each other -->
+        <attribute name="ClusterName">pessimistic-shared</attribute>
+        
+        <!-- Use a UDP (multicast) based stack. Need JGroups flow control (FC)
+             because timestamp communication will not require a synchronous response.
+        -->
+        <attribute name="MultiplexerStack">udp</attribute>
+
+        <!-- Used for timestamps, so must fetch state. -->
+        <attribute name="FetchInMemoryState">true</attribute>
+
+        <!--
+          The max amount of time (in milliseconds) we wait until the
+          state (ie. the contents of the cache) are retrieved from
+          existing members at startup.
+        -->
+        <attribute name="StateRetrievalTimeout">20000</attribute>
+
+        <!--
+            Number of milliseconds to wait until all responses for a
+            synchronous call have been received.
+        -->
+        <attribute name="SyncReplTimeout">20000</attribute>
+
+        <!-- Max number of milliseconds to wait for a lock acquisition -->
+        <attribute name="LockAcquisitionTimeout">15000</attribute>
+        
+        <!--  Lock Striping can lead to deadlocks -->
+        <attribute name="UseLockStriping">false</attribute>
+
+        <!--
+           Indicate whether to use marshalling or not. Set this to true if you 
+           are running under a scoped class loader, e.g., inside an application 
+           server.
+        -->
+        <attribute name="UseRegionBasedMarshalling">true</attribute>
+        <!-- Must match the value of "useRegionBasedMarshalling" -->
+        <attribute name="InactiveOnStartup">true</attribute>
+
+        <!-- For now. disable asynchronous RPC marshalling/sending -->
+        <attribute name="SerializationExecutorPoolSize">0</attribute>
+
+       <!--  Eviction policy configurations. -->
+       <attribute name="EvictionPolicyConfig">
+        <config>
+          <attribute name="wakeUpIntervalSeconds">5</attribute>
+          <!-- Name of the DEFAULT eviction policy class. -->
+          <attribute name="policyClass">org.jboss.cache.eviction.LRUPolicy</attribute>
+          <!--  Cache wide default -->
+          <region name="/_default_">
+            <!-- Evict LRU node once we have more than this number of nodes -->
+            <attribute name="maxNodes">10000</attribute>
+            <!-- And, evict any node that hasn't been accessed in this many seconds -->
+            <attribute name="timeToLiveSeconds">1000</attribute>
+            <!-- Don't evict a node that's been accessed within this many seconds. 
+                 Set this to a value greater than your max expected transaction length. -->
+            <attribute name="minTimeToLiveSeconds">120</attribute>
+          </region>
+          <!--  Don't ever evict modification timestamps -->
+          <region name="/TS" policyClass="org.jboss.cache.eviction.NullEvictionPolicy"/>
+        </config>
+     </attribute>
+
+    </cache-config>   
+    
+    <!-- A config appropriate for a cache that's shared for
+         entity, collection, query and timestamp caching. Not an advised
+         configuration, since it requires cache mode REPL_SYNC, which is the 
+         least efficient mode. Also requires a full state transfer at startup,
+         which can be expensive. Uses mvcc locking.
+    -->
+    <cache-config name="mvcc-shared">
+
+        <!-- TransactionManager configuration not required for Hibernate!
+             Hibernate will plug in its own transaction manager integration. 
+        -->
+
+        <!-- Node locking scheme -->
+        <attribute name="NodeLockingScheme">MVCC</attribute>
+
+        <!--
+            READ_COMMITTED is as strong as necessary for most 
+            2nd Level Cache use cases.
+        -->
+        <attribute name="IsolationLevel">READ_COMMITTED</attribute>
+
+        <!-- Must use REPL since used for timestamp caching. 
+             Must use SYNC to maintain cache coherency for entities.
+        -->
+        <attribute name="CacheMode">REPL_SYNC</attribute>
+        <attribute name="SyncCommitPhase">true</attribute>
+
+        <!-- Name of cluster. Needs to be the same for all members, in order
+             to find each other -->
+        <attribute name="ClusterName">mvcc-shared</attribute>
+        
+        <!-- Use a UDP (multicast) based stack. Need JGroups flow control (FC)
+             because timestamp communication will not require a synchronous response.
+        -->
+        <attribute name="MultiplexerStack">udp</attribute>
+
+        <!-- Used for timestamps, so must fetch state. -->
+        <attribute name="FetchInMemoryState">true</attribute>
+
+        <!--
+          The max amount of time (in milliseconds) we wait until the
+          state (ie. the contents of the cache) are retrieved from
+          existing members at startup.
+        -->
+        <attribute name="StateRetrievalTimeout">20000</attribute>
+
+        <!--
+            Number of milliseconds to wait until all responses for a
+            synchronous call have been received.
+        -->
+        <attribute name="SyncReplTimeout">20000</attribute>
+
+        <!-- Max number of milliseconds to wait for a lock acquisition -->
+        <attribute name="LockAcquisitionTimeout">15000</attribute>
+        
+        <!--  Lock Striping can lead to deadlocks -->
+        <attribute name="UseLockStriping">false</attribute>
+
+        <!--
+           Indicate whether to use marshalling or not. Set this to true if you 
+           are running under a scoped class loader, e.g., inside an application 
+           server.
+        -->
+        <attribute name="UseRegionBasedMarshalling">true</attribute>
+        <!-- Must match the value of "useRegionBasedMarshalling" -->
+        <attribute name="InactiveOnStartup">true</attribute>
+
+        <!-- For now. disable asynchronous RPC marshalling/sending -->
+        <attribute name="SerializationExecutorPoolSize">0</attribute>
+
+       <!--  Eviction policy configurations. -->
+       <attribute name="EvictionPolicyConfig">
+        <config>
+          <attribute name="wakeUpIntervalSeconds">5</attribute>
+          <!-- Name of the DEFAULT eviction policy class. -->
+          <attribute name="policyClass">org.jboss.cache.eviction.LRUPolicy</attribute>
+          <!--  Cache wide default -->
+          <region name="/_default_">
+            <!-- Evict LRU node once we have more than this number of nodes -->
+            <attribute name="maxNodes">10000</attribute>
+            <!-- And, evict any node that hasn't been accessed in this many seconds -->
+            <attribute name="timeToLiveSeconds">1000</attribute>
+            <!-- Don't evict a node that's been accessed within this many seconds. 
+                 Set this to a value greater than your max expected transaction length. -->
+            <attribute name="minTimeToLiveSeconds">120</attribute>
+          </region>
+          <!--  Don't ever evict modification timestamps -->
+          <region name="/TS" policyClass="org.jboss.cache.eviction.NullEvictionPolicy"/>
+        </config>
+     </attribute>
+
+    </cache-config>   
+
+    <!-- Same as "pessimistic-shared" but here we use REPEATABLE_READ
+         instead of READ_COMMITTED. REPEATABLE_READ is only useful if the 
+         application evicts/clears entities from the Hibernate Session and 
+         then expects to repeatably re-read them in the same transaction.
+         Otherwise, the Session's internal cache provides a repeatable-read 
+         semantic. Before choosing this config, carefully read the docs
+         and make sure you really need REPEATABLE_READ.
+    -->
+    <cache-config name="pessimistic-shared-repeatable">
+
+        <!-- TransactionManager configuration not required for Hibernate!
+             Hibernate will plug in its own transaction manager integration. 
+        -->
+
+        <!-- Node locking scheme -->
+        <attribute name="NodeLockingScheme">PESSIMISTIC</attribute>
+
+        <!-- Here we  use REPEATABLE_READ. -->
+        <attribute name="IsolationLevel">REPEATABLE_READ</attribute>
+
+        <!-- Must use REPL since used for timestamp caching. 
+             Must use SYNC to maintain cache coherency for entities.
+        -->
+        <attribute name="CacheMode">REPL_SYNC</attribute>
+
+        <!-- Name of cluster. Needs to be the same for all members, in order
+             to find each other -->
+        <attribute name="ClusterName">pessimistic-shared-rr</attribute>
+        
+        <!-- Use a UDP (multicast) based stack. Need JGroups flow control (FC)
+             because timestamp communication will not require a synchronous response.
+        -->
+        <attribute name="MultiplexerStack">udp</attribute>
+
+        <!-- Used for timestamps, so must fetch state. -->
+        <attribute name="FetchInMemoryState">true</attribute>
+
+        <!--
+          The max amount of time (in milliseconds) we wait until the
+          state (ie. the contents of the cache) are retrieved from
+          existing members at startup.
+        -->
+        <attribute name="StateRetrievalTimeout">20000</attribute>
+
+        <!--
+            Number of milliseconds to wait until all responses for a
+            synchronous call have been received.
+        -->
+        <attribute name="SyncReplTimeout">20000</attribute>
+
+        <!-- Max number of milliseconds to wait for a lock acquisition -->
+        <attribute name="LockAcquisitionTimeout">15000</attribute>
+        
+        <!--  Lock Striping can lead to deadlocks -->
+        <attribute name="UseLockStriping">false</attribute>
+
+        <!--
+          Indicate whether to use marshalling or not. Set this to true if you 
+          are running under a scoped class loader, e.g., inside an application 
+          server.
+        -->
+        <attribute name="UseRegionBasedMarshalling">true</attribute>
+        <!-- Must match the value of "useRegionBasedMarshalling" -->
+        <attribute name="InactiveOnStartup">true</attribute>
+
+        <!-- For now. disable asynchronous RPC marshalling/sending -->
+        <attribute name="SerializationExecutorPoolSize">0</attribute>
+
+       <!--  Eviction policy configurations. -->
+       <attribute name="EvictionPolicyConfig">
+        <config>
+          <attribute name="wakeUpIntervalSeconds">5</attribute>
+          <!-- Name of the DEFAULT eviction policy class. -->
+          <attribute name="policyClass">org.jboss.cache.eviction.LRUPolicy</attribute>
+          <!--  Cache wide default -->
+          <region name="/_default_">
+            <!-- Evict LRU node once we have more than this number of nodes -->
+            <attribute name="maxNodes">10000</attribute>
+            <!-- And, evict any node that hasn't been accessed in this many seconds -->
+            <attribute name="timeToLiveSeconds">1000</attribute>
+            <!-- Don't evict a node that's been accessed within this many seconds. 
+                 Set this to a value greater than your max expected transaction length. -->
+            <attribute name="minTimeToLiveSeconds">120</attribute>
+          </region>
+          <!--  Don't ever evict modification timestamps -->
+          <region name="/TS" policyClass="org.jboss.cache.eviction.NullEvictionPolicy"/>
+        </config>
+     </attribute>
+
+    </cache-config>
+    
+    <!-- Same as "mvcc-shared" but here we use REPEATABLE_READ
+         instead of READ_COMMITTED. REPEATABLE_READ is only useful if the 
+         application evicts/clears entities from the Hibernate Session and 
+         then expects to repeatably re-read them in the same transaction.
+         Otherwise, the Session's internal cache provides a repeatable-read 
+         semantic. Before choosing this config, carefully read the docs
+         and make sure you really need REPEATABLE_READ.
+    -->
+    <cache-config name="mvcc-shared-repeatable">
+
+        <!-- TransactionManager configuration not required for Hibernate!
+             Hibernate will plug in its own transaction manager integration. 
+        -->
+
+        <!-- Node locking scheme -->
+        <attribute name="NodeLockingScheme">MVCC</attribute>
+
+        <!-- Here we  use REPEATABLE_READ. -->
+        <attribute name="IsolationLevel">REPEATABLE_READ</attribute>
+
+        <!-- Must use REPL since used for timestamp caching. 
+             Must use SYNC to maintain cache coherency for entities.
+        -->
+        <attribute name="CacheMode">REPL_SYNC</attribute>
+        <attribute name="SyncCommitPhase">true</attribute>
+
+        <!-- Name of cluster. Needs to be the same for all members, in order
+             to find each other -->
+        <attribute name="ClusterName">mvcc-shared-rr</attribute>
+        
+        <!-- Use a UDP (multicast) based stack. Need JGroups flow control (FC)
+             because timestamp communication will not require a synchronous response.
+        -->
+        <attribute name="MultiplexerStack">udp</attribute>
+
+        <!-- Used for timestamps, so must fetch state. -->
+        <attribute name="FetchInMemoryState">true</attribute>
+
+        <!--
+          The max amount of time (in milliseconds) we wait until the
+          state (ie. the contents of the cache) are retrieved from
+          existing members at startup.
+        -->
+        <attribute name="StateRetrievalTimeout">20000</attribute>
+
+        <!--
+            Number of milliseconds to wait until all responses for a
+            synchronous call have been received.
+        -->
+        <attribute name="SyncReplTimeout">20000</attribute>
+
+        <!-- Max number of milliseconds to wait for a lock acquisition -->
+        <attribute name="LockAcquisitionTimeout">15000</attribute>
+        
+        <!--  Lock Striping can lead to deadlocks -->
+        <attribute name="UseLockStriping">false</attribute>
+
+        <!--
+          Indicate whether to use marshalling or not. Set this to true if you 
+          are running under a scoped class loader, e.g., inside an application 
+          server.
+        -->
+        <attribute name="UseRegionBasedMarshalling">true</attribute>
+        <!-- Must match the value of "useRegionBasedMarshalling" -->
+        <attribute name="InactiveOnStartup">true</attribute>
+
+        <!-- For now. disable asynchronous RPC marshalling/sending -->
+        <attribute name="SerializationExecutorPoolSize">0</attribute>
+
+       <!--  Eviction policy configurations. -->
+       <attribute name="EvictionPolicyConfig">
+        <config>
+          <attribute name="wakeUpIntervalSeconds">5</attribute>
+          <!-- Name of the DEFAULT eviction policy class. -->
+          <attribute name="policyClass">org.jboss.cache.eviction.LRUPolicy</attribute>
+          <!--  Cache wide default -->
+          <region name="/_default_">
+            <!-- Evict LRU node once we have more than this number of nodes -->
+            <attribute name="maxNodes">10000</attribute>
+            <!-- And, evict any node that hasn't been accessed in this many seconds -->
+            <attribute name="timeToLiveSeconds">1000</attribute>
+            <!-- Don't evict a node that's been accessed within this many seconds. 
+                 Set this to a value greater than your max expected transaction length. -->
+            <attribute name="minTimeToLiveSeconds">120</attribute>
+          </region>
+          <!--  Don't ever evict modification timestamps -->
+          <region name="/TS" policyClass="org.jboss.cache.eviction.NullEvictionPolicy"/>
+        </config>
+     </attribute>
+
+    </cache-config>
+</cache-configs>
diff --git a/src/main/java/hibernate/cache/jbc/builder/jgroups-stacks.xml b/src/main/java/hibernate/cache/jbc/builder/jgroups-stacks.xml
new file mode 100644
index 0000000..1b871d0
--- /dev/null
+++ b/src/main/java/hibernate/cache/jbc/builder/jgroups-stacks.xml
@@ -0,0 +1,327 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+  ~ 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
+  -->
+
+<!--
+  Sample file that defines a number of stacks, used by the multiplexer
+  Author: Bela Ban
+  Version: $Id$
+-->
+<protocol_stacks>
+    <stack name="udp"
+           description="Default: IP multicast based stack, with flow control and message bundling">
+        <config>
+            <UDP
+                 mcast_addr="${jgroups.udp.mcast_addr:228.10.10.10}"
+                 mcast_port="${jgroups.udp.mcast_port:45588}"
+                 tos="8"
+                 ucast_recv_buf_size="20000000"
+                 ucast_send_buf_size="640000"
+                 mcast_recv_buf_size="25000000"
+                 mcast_send_buf_size="640000"
+                 loopback="true"
+                 discard_incompatible_packets="true"
+                 max_bundle_size="64000"
+                 max_bundle_timeout="30"
+                 use_incoming_packet_handler="true"
+                 ip_ttl="${jgroups.udp.ip_ttl:2}"
+                 enable_bundling="${jgroup.udp.enable_bundling:true}"
+                 
+                 use_concurrent_stack="true"
+
+		         thread_pool.enabled="true"
+		         thread_pool.min_threads="1"
+		         thread_pool.max_threads="25"
+		         thread_pool.keep_alive_time="5000"
+		         thread_pool.queue_enabled="false"
+		         thread_pool.queue_max_size="100"
+		         thread_pool.rejection_policy="Run"
+		
+		         oob_thread_pool.enabled="true"
+		         oob_thread_pool.min_threads="1"
+		         oob_thread_pool.max_threads="8"
+		         oob_thread_pool.keep_alive_time="5000"
+		         oob_thread_pool.queue_enabled="false"
+		         oob_thread_pool.queue_max_size="100"
+		         oob_thread_pool.rejection_policy="Run"/>		         
+            <PING timeout="${jgroups.ping.timeout:2000}"
+                    num_initial_members="${jgroups.ping.num_initial_members:3}"/>
+            <MERGE2 max_interval="100000"
+                      min_interval="20000"/>
+            <FD_SOCK/>
+            <FD timeout="10000" max_tries="5" shun="true"/>
+            <VERIFY_SUSPECT timeout="1500"  />
+            <pbcast.NAKACK
+                           use_mcast_xmit="false" gc_lag="0"
+                           retransmit_timeout="300,600,1200,2400,4800"
+                           discard_delivered_msgs="false"/>
+            <UNICAST timeout="300,600,1200,2400,3600"/>
+            <pbcast.STABLE stability_delay="1000" desired_avg_gossip="50000"
+                           max_bytes="400000"/>
+            <pbcast.GMS print_local_addr="true" 
+                        join_timeout="3000"  
+                        shun="false"
+                        view_bundling="true"
+                        view_ack_collection_timeout="5000"/>
+            <FC max_credits="2000000"
+                min_threshold="0.10"/>
+            <FRAG2 frag_size="60000"  />
+			<pbcast.STREAMING_STATE_TRANSFER/>
+	        <!-- <pbcast.STATE_TRANSFER/> -->
+	        <pbcast.FLUSH timeout="0"/>        
+	    </config>
+    </stack>
+
+
+
+    <stack name="udp-sync"
+           description="IP multicast based stack, without flow control and without message bundling. This should be used
+           instead of udp if (1) synchronous calls are used and (2) the message volume (rate and size)
+            is not that large. Don't use this configuration if you send messages at a high sustained rate, or you might
+            run out of memory">
+        <config>
+            <UDP
+                 mcast_addr="${jgroups.udp.mcast_addr:229.10.10.10}"
+                 mcast_port="${jgroups.udp.mcast_port:45599}"
+                 tos="8"
+                 ucast_recv_buf_size="20000000"
+                 ucast_send_buf_size="640000"
+                 mcast_recv_buf_size="25000000"
+                 mcast_send_buf_size="640000"
+                 loopback="true"
+                 discard_incompatible_packets="true"
+                 max_bundle_size="64000"
+                 max_bundle_timeout="30"
+                 use_incoming_packet_handler="true"
+                 ip_ttl="${jgroups.udp.ip_ttl:2}"
+                 enable_bundling="${jgroup.udp.enable_bundling:true}"
+                 
+                 use_concurrent_stack="true"
+
+		         thread_pool.enabled="true"
+		         thread_pool.min_threads="1"
+		         thread_pool.max_threads="25"
+		         thread_pool.keep_alive_time="5000"
+		         thread_pool.queue_enabled="false"
+		         thread_pool.queue_max_size="100"
+		         thread_pool.rejection_policy="Run"
+		
+		         oob_thread_pool.enabled="true"
+		         oob_thread_pool.min_threads="1"
+		         oob_thread_pool.max_threads="8"
+		         oob_thread_pool.keep_alive_time="5000"
+		         oob_thread_pool.queue_enabled="false"
+		         oob_thread_pool.queue_max_size="100"
+		         oob_thread_pool.rejection_policy="Run"/> 		         
+            <PING timeout="${jgroups.ping.timeout:2000}"
+                    num_initial_members="${jgroups.ping.num_initial_members:3}"/>
+            <MERGE2 max_interval="100000"
+                      min_interval="20000"/>
+            <FD_SOCK/>
+            <FD timeout="10000" max_tries="5" shun="true"/>
+            <VERIFY_SUSPECT timeout="1500"  />
+            <pbcast.NAKACK
+                           use_mcast_xmit="false" gc_lag="0"
+                           retransmit_timeout="300,600,1200,2400,4800"
+                           discard_delivered_msgs="false"/>
+            <UNICAST timeout="300,600,1200,2400,3600"/>
+            <pbcast.STABLE stability_delay="1000" desired_avg_gossip="50000"
+                           max_bytes="400000"/>
+            <pbcast.GMS print_local_addr="true" 
+                        join_timeout="3000" 
+                        shun="false"
+                        view_bundling="true"/>
+            <FRAG2 frag_size="60000"  />
+            <pbcast.STREAMING_STATE_TRANSFER/>
+	        <!-- <pbcast.STATE_TRANSFER/> -->
+	        <pbcast.FLUSH timeout="0"/>
+        </config>
+    </stack>
+
+
+    <stack name="tcp"
+           description="TCP based stack, with flow control and message bundling. This is usually used when IP
+           multicasting cannot be used in a network, e.g. because it is disabled (routers discard multicast).
+           Note that TCP.bind_addr and TCPPING.initial_hosts should be set, possibly via system properties, e.g.
+           -Djgroups.bind_addr=192.168.5.2 and -Djgroups.tcpping.initial_hosts=192.168.5.2[7800]">
+        <config>
+            <TCP start_port="7800"
+                 loopback="true"
+                 recv_buf_size="20000000"
+                 send_buf_size="640000"
+                 discard_incompatible_packets="true"
+                 max_bundle_size="64000"
+                 max_bundle_timeout="30"
+                 use_incoming_packet_handler="true"
+                 enable_bundling="true"
+                 use_send_queues="false"
+                 sock_conn_timeout="300"
+                 skip_suspected_members="true"
+                 
+                 use_concurrent_stack="true"
+	
+		         thread_pool.enabled="true"
+		         thread_pool.min_threads="1"
+		         thread_pool.max_threads="25"
+		         thread_pool.keep_alive_time="5000"
+		         thread_pool.queue_enabled="false"
+		         thread_pool.queue_max_size="100"
+		         thread_pool.rejection_policy="run"
+		
+		         oob_thread_pool.enabled="true"
+		         oob_thread_pool.min_threads="1"
+		         oob_thread_pool.max_threads="8"
+		         oob_thread_pool.keep_alive_time="5000"
+		         oob_thread_pool.queue_enabled="false"
+		         oob_thread_pool.queue_max_size="100"
+		         oob_thread_pool.rejection_policy="run"/>
+		         
+            <TCPPING timeout="3000"
+                     initial_hosts="${jgroups.tcpping.initial_hosts:localhost[7800],localhost[7801]}"
+                     port_range="1"
+                     num_initial_members="3"/>
+            <MERGE2 max_interval="100000"
+                      min_interval="20000"/>
+            <FD_SOCK/>
+            <FD timeout="10000" max_tries="5"   shun="true"/>
+            <VERIFY_SUSPECT timeout="1500"  />
+            <pbcast.NAKACK
+                           use_mcast_xmit="false" gc_lag="0"
+                           retransmit_timeout="300,600,1200,2400,4800"
+                           discard_delivered_msgs="false"/>
+            <pbcast.STABLE stability_delay="1000" desired_avg_gossip="50000"
+                           max_bytes="400000"/>
+            <pbcast.GMS print_local_addr="true" 
+                        join_timeout="3000" 
+                        shun="false"
+                        view_bundling="true"/>
+            <FC max_credits="2000000"
+                min_threshold="0.10"/>
+            <FRAG2 frag_size="60000"  />
+            <pbcast.STREAMING_STATE_TRANSFER/>
+	        <!-- <pbcast.STATE_TRANSFER/> -->
+	        <pbcast.FLUSH timeout="0"/>
+        </config>
+    </stack>
+
+
+    <stack name="tcp-sync"
+           description="TCP based stack, without flow control and without message bundling. This is usually used when IP
+           multicasting cannot be used in a network, e.g. because it is disabled (routers discard multicast). This
+           configuration should be used instead of tcp when (1) synchronous calls are used and (2) the message volume
+           (rate and size) is not that large">
+        <config>
+            <TCP start_port="7900"
+                 loopback="true"
+                 recv_buf_size="20000000"
+                 send_buf_size="640000"
+                 discard_incompatible_packets="true"
+                 max_bundle_size="64000"
+                 max_bundle_timeout="30"
+                 use_incoming_packet_handler="true"
+                 enable_bundling="true"
+                 use_send_queues="false"
+                 sock_conn_timeout="300"
+                 skip_suspected_members="true"
+                 
+                 thread_pool.enabled="true"
+		         thread_pool.min_threads="1"
+		         thread_pool.max_threads="25"
+		         thread_pool.keep_alive_time="5000"
+		         thread_pool.queue_enabled="false"
+		         thread_pool.queue_max_size="100"
+		         thread_pool.rejection_policy="run"
+		
+		         oob_thread_pool.enabled="true"
+		         oob_thread_pool.min_threads="1"
+		         oob_thread_pool.max_threads="8"
+		         oob_thread_pool.keep_alive_time="5000"
+		         oob_thread_pool.queue_enabled="false"
+		         oob_thread_pool.queue_max_size="100"
+		         oob_thread_pool.rejection_policy="run"/>
+		         
+            <TCPPING timeout="3000"
+                     initial_hosts="${jgroups.tcpping.initial_hosts:localhost[7900],localhost[7901]}"
+                     port_range="1"
+                     num_initial_members="3"/>
+            <MERGE2 max_interval="100000"
+                      min_interval="20000"/>
+            <FD_SOCK/>
+            <FD timeout="10000" max_tries="5"   shun="true"/>
+            <VERIFY_SUSPECT timeout="1500"  />
+            <pbcast.NAKACK
+                           use_mcast_xmit="false" gc_lag="0"
+                           retransmit_timeout="300,600,1200,2400,4800"
+                           discard_delivered_msgs="false"/>
+            <pbcast.STABLE stability_delay="1000" desired_avg_gossip="50000"
+                           max_bytes="400000"/>
+            <pbcast.GMS print_local_addr="true" 
+                        join_timeout="3000" 
+                        shun="false"
+                        view_bundling="true"/>
+            <pbcast.STREAMING_STATE_TRANSFER/>
+	        <!-- <pbcast.STATE_TRANSFER/> -->
+	        <pbcast.FLUSH timeout="0"/>
+        </config>
+    </stack>
+
+    <stack name="tunnel"
+           description="Used with a GossipRouter">
+        <config>
+            <TUNNEL router_port="12001" router_host="127.0.0.1"/>
+            <PING timeout="2000"
+                    num_initial_members="3"
+                  gossip_refresh="10000"
+                  gossip_host="127.0.0.1"
+                  gossip_port="12001"/>
+            <MERGE2 max_interval="20000"
+                      min_interval="5000"/>            
+            <FD timeout="2000" max_tries="3" shun="true"/>
+            <VERIFY_SUSPECT timeout="1500"  />
+            <pbcast.NAKACK
+                           use_mcast_xmit="false" gc_lag="0"
+                           retransmit_timeout="300,600,1200,2400,4800"
+                           discard_delivered_msgs="false"/>
+            <UNICAST timeout="300,600,1200,2400,3600"/>
+            <pbcast.STABLE stability_delay="1000" desired_avg_gossip="5000"
+                           max_bytes="400000"/>
+            <pbcast.GMS print_local_addr="true" 
+                        join_timeout="3000"
+                        shun="false"
+                        view_bundling="true"
+                        view_ack_collection_timeout="5000"/>
+            <FC max_credits="2000000"
+                min_threshold="0.10"/>
+            <FRAG2 frag_size="60000"  />
+            <!-- <pbcast.STREAMING_STATE_TRANSFER/> -->
+	        <pbcast.STATE_TRANSFER/>
+	        <pbcast.FLUSH timeout="0"/>
+        </config>
+    </stack>
+
+
+</protocol_stacks>
+
+
diff --git a/src/main/java/hibernate/cache/jbc/collection/CollectionRegionImpl.java b/src/main/java/hibernate/cache/jbc/collection/CollectionRegionImpl.java
new file mode 100644
index 0000000..ed75135
--- /dev/null
+++ b/src/main/java/hibernate/cache/jbc/collection/CollectionRegionImpl.java
@@ -0,0 +1,76 @@
+/*
+ * 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.jbc.collection;
+
+import org.jboss.cache.Cache;
+import org.jboss.cache.Fqn;
+import org.jboss.cache.config.Configuration.NodeLockingScheme;
+import org.jboss.cache.notifications.annotation.CacheListener;
+
+import org.hibernate.cache.CacheDataDescription;
+import org.hibernate.cache.CacheException;
+import org.hibernate.cache.CollectionRegion;
+import org.hibernate.cache.access.AccessType;
+import org.hibernate.cache.access.CollectionRegionAccessStrategy;
+import org.hibernate.cache.jbc.TransactionalDataRegionAdapter;
+import org.hibernate.cache.jbc.access.PutFromLoadValidator;
+
+/**
+ * Defines the behavior of the collection cache regions for JBossCache 2.x.
+ * 
+ * @author Steve Ebersole
+ */
+ at CacheListener
+public class CollectionRegionImpl extends TransactionalDataRegionAdapter implements CollectionRegion {
+
+    public static final String TYPE = "COLL";
+    private boolean optimistic;
+
+    public CollectionRegionImpl(Cache jbcCache, String regionName, String regionPrefix, CacheDataDescription metadata) {
+        super(jbcCache, regionName, regionPrefix, metadata);
+        optimistic = (jbcCache.getConfiguration().getNodeLockingScheme() == NodeLockingScheme.OPTIMISTIC);
+    }
+
+    public CollectionRegionAccessStrategy buildAccessStrategy(AccessType accessType) throws CacheException {
+        if (AccessType.READ_ONLY.equals(accessType)) {
+            return optimistic ? new OptimisticReadOnlyAccess(this) : new ReadOnlyAccess(this);
+        }
+        if (AccessType.TRANSACTIONAL.equals(accessType)) {
+            return optimistic ? new OptimisticTransactionalAccess(this) : new TransactionalAccess(this);
+        }
+
+        // todo : add support for READ_WRITE ( + NONSTRICT_READ_WRITE ??? )
+
+        throw new CacheException("unsupported access type [" + accessType.getName() + "]");
+    }
+
+    @Override
+    protected Fqn<String> createRegionFqn(String regionName, String regionPrefix) {
+        return getTypeLastRegionFqn(regionName, regionPrefix, TYPE);
+    }
+    
+    public PutFromLoadValidator getPutFromLoadValidator() {
+       return new PutFromLoadValidator(transactionManager);
+    }
+}
diff --git a/src/main/java/hibernate/cache/jbc/collection/OptimisticReadOnlyAccess.java b/src/main/java/hibernate/cache/jbc/collection/OptimisticReadOnlyAccess.java
new file mode 100644
index 0000000..a4b3ded
--- /dev/null
+++ b/src/main/java/hibernate/cache/jbc/collection/OptimisticReadOnlyAccess.java
@@ -0,0 +1,71 @@
+/*
+ * 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.jbc.collection;
+
+import org.hibernate.cache.CacheException;
+import org.hibernate.cache.access.SoftLock;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This defines the strategy for transactional access to collection data in an
+ * optimistic-locking JBossCache using its 2.x APIs. <p/> The read-only access
+ * to a JBossCache really is still transactional, just with the extra semantic
+ * or guarantee that we will not update data.
+ * 
+ * @author Brian Stansberry
+ */
+public class OptimisticReadOnlyAccess extends OptimisticTransactionalAccess {
+
+    private static final Logger log = LoggerFactory.getLogger(OptimisticReadOnlyAccess.class);
+
+    /**
+     * Create a new OptimisticReadOnlyAccess.
+     * 
+     * @param region The region to which this is providing access
+     */
+    public OptimisticReadOnlyAccess(CollectionRegionImpl region) {
+        super(region);
+    }
+
+    @Override
+    public SoftLock lockItem(Object key, Object version) throws CacheException {
+        throw new UnsupportedOperationException("Illegal attempt to edit read only item");
+    }
+
+    @Override
+    public SoftLock lockRegion() throws CacheException {
+        throw new UnsupportedOperationException("Illegal attempt to edit read only region");
+    }
+
+    @Override
+    public void unlockItem(Object key, SoftLock lock) throws CacheException {
+        log.error("Illegal attempt to edit read only item");
+    }
+
+    @Override
+    public void unlockRegion(SoftLock lock) throws CacheException {
+        log.error("Illegal attempt to edit read only region");
+    }
+}
diff --git a/src/test/java/org/hibernate/cache/PessimisticTreeCacheTest.java b/src/main/java/hibernate/cache/jbc/collection/OptimisticTransactionalAccess.java
similarity index 54%
copy from src/test/java/org/hibernate/cache/PessimisticTreeCacheTest.java
copy to src/main/java/hibernate/cache/jbc/collection/OptimisticTransactionalAccess.java
index a16245b..86f5011 100644
--- a/src/test/java/org/hibernate/cache/PessimisticTreeCacheTest.java
+++ b/src/main/java/hibernate/cache/jbc/collection/OptimisticTransactionalAccess.java
@@ -1,64 +1,48 @@
-/*
- * 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;
-
-import junit.framework.Test;
-
-import org.hibernate.cfg.Environment;
-import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
-import org.hibernate.test.cache.BaseCacheProviderTestCase;
-
-/**
- * @author Steve Ebersole
- */
-public class PessimisticTreeCacheTest extends BaseCacheProviderTestCase {
-	public PessimisticTreeCacheTest(String x) {
-		super( x );
-	}
-
-	public static Test suite() {
-		return new FunctionalTestClassTestSuite( PessimisticTreeCacheTest.class );
-	}
-
-	public String getCacheConcurrencyStrategy() {
-		return "transactional";
-	}
-
-	protected Class getCacheProvider() {
-		return TreeCacheProvider.class;
-	}
-
-	protected String getConfigResourceKey() {
-		return Environment.CACHE_PROVIDER_CONFIG;
-	}
-
-	protected String getConfigResourceLocation() {
-		return "treecache-pessimistic.xml";
-	}
-
-	protected boolean useTransactionManager() {
-		return true;
-	}
-
-}
+/*
+ * 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.jbc.collection;
+
+import org.hibernate.cache.jbc.access.OptimisticTransactionalAccessDelegate;
+
+/**
+ * Defines the strategy for transactional access to entity data in an
+ * optimistic-locking JBoss Cache using its 2.x APIs
+ * 
+ * @author Brian Stansberry
+ * @version $Revision: 1 $
+ */
+public class OptimisticTransactionalAccess extends TransactionalAccess {
+
+    /**
+     * Create a new OptimisticTransactionalAccess.
+     * 
+     * @param region The region to which this is providing access
+     */
+    public OptimisticTransactionalAccess(CollectionRegionImpl region) {
+        
+        // We use a different delegate than the non-optimistic superclass default
+        super(region, new OptimisticTransactionalAccessDelegate(region, region.getPutFromLoadValidator()));
+    }
+
+}
diff --git a/src/main/java/hibernate/cache/jbc/collection/ReadOnlyAccess.java b/src/main/java/hibernate/cache/jbc/collection/ReadOnlyAccess.java
new file mode 100644
index 0000000..82b342a
--- /dev/null
+++ b/src/main/java/hibernate/cache/jbc/collection/ReadOnlyAccess.java
@@ -0,0 +1,83 @@
+/*
+ * 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.jbc.collection;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.hibernate.cache.access.SoftLock;
+import org.hibernate.cache.CacheException;
+
+/**
+ * This defines the strategy for transactional access to collection data in a
+ * pessimistic-locking JBossCache using its 2.x APIs. <p/> The read-only access
+ * to a JBossCache really is still transactional, just with the extra semantic
+ * or guarantee that we will not update data.
+ * 
+ * @author Steve Ebersole
+ */
+public class ReadOnlyAccess extends TransactionalAccess {
+    private static final Logger log = LoggerFactory.getLogger(ReadOnlyAccess.class);
+
+	/**
+	 * Create a provider of read-only access to the specific region.
+	 *
+	 * @param region The region to which this provides access.
+	 */
+	public ReadOnlyAccess(CollectionRegionImpl region) {
+        super(region);
+    }
+
+    /**
+	 * {@inheritDoc}
+	 */
+	@Override
+    public SoftLock lockItem(Object key, Object version) throws CacheException {
+        throw new UnsupportedOperationException("Illegal attempt to edit read only item");
+    }
+
+    /**
+	 * {@inheritDoc}
+	 */
+	@Override
+    public SoftLock lockRegion() throws CacheException {
+        throw new UnsupportedOperationException("Illegal attempt to edit read only region");
+    }
+
+    /**
+	 * {@inheritDoc}
+	 */
+	@Override
+    public void unlockItem(Object key, SoftLock lock) throws CacheException {
+        log.error("Illegal attempt to edit read only item");
+    }
+
+    /**
+	 * {@inheritDoc}
+	 */
+	@Override
+    public void unlockRegion(SoftLock lock) throws CacheException {
+        log.error("Illegal attempt to edit read only region");
+    }
+}
diff --git a/src/main/java/hibernate/cache/jbc/collection/TransactionalAccess.java b/src/main/java/hibernate/cache/jbc/collection/TransactionalAccess.java
new file mode 100644
index 0000000..edc07cc
--- /dev/null
+++ b/src/main/java/hibernate/cache/jbc/collection/TransactionalAccess.java
@@ -0,0 +1,155 @@
+/*
+ * 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.jbc.collection;
+
+import org.hibernate.cache.CacheException;
+import org.hibernate.cache.CollectionRegion;
+import org.hibernate.cache.access.CollectionRegionAccessStrategy;
+import org.hibernate.cache.access.SoftLock;
+import org.hibernate.cache.jbc.access.TransactionalAccessDelegate;
+
+/**
+ * This defines the strategy for transactional access to collection data in a
+ * pessimistic-locking JBossCache using its 2.x APIs
+ * 
+ * @author Steve Ebersole
+ * @author Brian Stansberry
+ */
+public class TransactionalAccess implements CollectionRegionAccessStrategy {
+
+    private final CollectionRegionImpl region;
+
+    /**
+     * Most of our logic is shared between this and entity regions, so we
+     * delegate to a class that encapsulates it
+     */
+    private final TransactionalAccessDelegate delegate;
+
+    /**
+     * Create a new TransactionalAccess.
+     * 
+     * @param region the region to which this provides access
+     */
+    public TransactionalAccess(CollectionRegionImpl region) {
+        this(region, new TransactionalAccessDelegate(region, region.getPutFromLoadValidator()));
+    }
+
+    /**
+     * Allow subclasses to define the delegate.
+     *
+     * @param region the region to which this provides access
+     * @param delegate type of transactional access
+     */
+    protected TransactionalAccess(CollectionRegionImpl region, TransactionalAccessDelegate delegate) {
+        this.region = region;
+        this.delegate = delegate;
+    }
+
+    /**
+	 * {@inheritDoc}
+	 */
+	public CollectionRegion getRegion() {
+        return region;
+    }
+
+    /**
+	 * {@inheritDoc}
+	 */
+	public Object get(Object key, long txTimestamp) throws CacheException {
+
+        return delegate.get(key, txTimestamp);
+    }
+
+    /**
+	 * {@inheritDoc}
+	 */
+	public boolean putFromLoad(Object key, Object value, long txTimestamp, Object version) throws CacheException {
+
+        return delegate.putFromLoad(key, value, txTimestamp, version);
+    }
+
+    /**
+	 * {@inheritDoc}
+	 */
+	public boolean putFromLoad(Object key, Object value, long txTimestamp, Object version, boolean minimalPutOverride)
+            throws CacheException {
+
+        return delegate.putFromLoad(key, value, txTimestamp, version, minimalPutOverride);
+    }
+
+    /**
+	 * {@inheritDoc}
+	 */
+	public void remove(Object key) throws CacheException {
+
+        delegate.remove(key);
+    }
+
+    /**
+	 * {@inheritDoc}
+	 */
+	public void removeAll() throws CacheException {
+        delegate.removeAll();
+    }
+
+    /**
+	 * {@inheritDoc}
+	 */
+	public void evict(Object key) throws CacheException {
+        delegate.evict(key);
+    }
+
+    /**
+	 * {@inheritDoc}
+	 */
+	public void evictAll() throws CacheException {
+        delegate.evictAll();
+    }
+
+    /**
+	 * {@inheritDoc}
+	 */
+	public SoftLock lockItem(Object key, Object version) throws CacheException {
+        return null;
+    }
+
+    /**
+	 * {@inheritDoc}
+	 */
+	public SoftLock lockRegion() throws CacheException {
+        return null;
+    }
+
+    /**
+	 * {@inheritDoc}
+	 */
+	public void unlockItem(Object key, SoftLock lock) throws CacheException {
+    }
+
+    /**
+	 * {@inheritDoc}
+	 */
+	public void unlockRegion(SoftLock lock) throws CacheException {
+    }
+}
diff --git a/src/main/java/hibernate/cache/jbc/entity/EntityRegionImpl.java b/src/main/java/hibernate/cache/jbc/entity/EntityRegionImpl.java
new file mode 100644
index 0000000..12e3073
--- /dev/null
+++ b/src/main/java/hibernate/cache/jbc/entity/EntityRegionImpl.java
@@ -0,0 +1,81 @@
+/*
+ * 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.jbc.entity;
+
+import org.jboss.cache.Cache;
+import org.jboss.cache.Fqn;
+import org.jboss.cache.config.Configuration.NodeLockingScheme;
+import org.jboss.cache.notifications.annotation.CacheListener;
+
+import org.hibernate.cache.CacheDataDescription;
+import org.hibernate.cache.CacheException;
+import org.hibernate.cache.EntityRegion;
+import org.hibernate.cache.access.AccessType;
+import org.hibernate.cache.access.EntityRegionAccessStrategy;
+import org.hibernate.cache.jbc.TransactionalDataRegionAdapter;
+import org.hibernate.cache.jbc.access.PutFromLoadValidator;
+
+/**
+ * Defines the behavior of the entity cache regions for JBossCache.
+ * 
+ * @author Steve Ebersole
+ */
+ at CacheListener
+public class EntityRegionImpl extends TransactionalDataRegionAdapter implements EntityRegion {
+
+    public static final String TYPE = "ENTITY";
+    
+    private boolean optimistic;
+
+    public EntityRegionImpl(Cache jbcCache, String regionName, String regionPrefix, CacheDataDescription metadata) {
+        super(jbcCache, regionName, regionPrefix, metadata);
+        optimistic = (jbcCache.getConfiguration().getNodeLockingScheme() == NodeLockingScheme.OPTIMISTIC);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public EntityRegionAccessStrategy buildAccessStrategy(AccessType accessType) throws CacheException {
+        if (AccessType.READ_ONLY.equals(accessType)) {
+            return optimistic ? new OptimisticReadOnlyAccess(this) : new ReadOnlyAccess(this);
+        }
+        if (AccessType.TRANSACTIONAL.equals(accessType)) {
+            return optimistic ? new OptimisticTransactionalAccess(this) : new TransactionalAccess(this);
+        }
+
+        // todo : add support for READ_WRITE ( + NONSTRICT_READ_WRITE ??? )
+
+        throw new CacheException("unsupported access type [" + accessType.getName() + "]");
+    }
+
+    @Override
+    protected Fqn<String> createRegionFqn(String regionName, String regionPrefix) {
+        return getTypeLastRegionFqn(regionName, regionPrefix, TYPE);
+    }
+    
+    public PutFromLoadValidator getPutFromLoadValidator() {
+       return new PutFromLoadValidator(transactionManager);
+    }
+
+}
diff --git a/src/main/java/hibernate/cache/jbc/entity/OptimisticReadOnlyAccess.java b/src/main/java/hibernate/cache/jbc/entity/OptimisticReadOnlyAccess.java
new file mode 100644
index 0000000..957805f
--- /dev/null
+++ b/src/main/java/hibernate/cache/jbc/entity/OptimisticReadOnlyAccess.java
@@ -0,0 +1,78 @@
+/*
+ * 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.jbc.entity;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.hibernate.cache.access.SoftLock;
+import org.hibernate.cache.CacheException;
+
+/**
+ * This defines the strategy for read-only access to enity data in an
+ * optimistic-locking JBossCache using its 2.x APIs <p/> The read-only access to
+ * a JBossCache really is still transactional, just with the extra semantic or
+ * guarantee that we will not update data.
+ * 
+ * @author Brian Stansberry
+ */
+public class OptimisticReadOnlyAccess extends OptimisticTransactionalAccess {
+    private static final Logger log = LoggerFactory.getLogger(OptimisticReadOnlyAccess.class);
+
+    public OptimisticReadOnlyAccess(EntityRegionImpl region) {
+        super(region);
+    }
+
+    @Override
+    public SoftLock lockItem(Object key, Object version) throws CacheException {
+        throw new UnsupportedOperationException("Illegal attempt to edit read only item");
+    }
+
+    @Override
+    public SoftLock lockRegion() throws CacheException {
+        throw new UnsupportedOperationException("Illegal attempt to edit read only region");
+    }
+
+    @Override
+    public void unlockItem(Object key, SoftLock lock) throws CacheException {
+        log.error("Illegal attempt to edit read only item");
+    }
+
+    @Override
+    public void unlockRegion(SoftLock lock) throws CacheException {
+        log.error("Illegal attempt to edit read only region");
+    }
+
+    @Override
+    public boolean update(Object key, Object value, Object currentVersion, Object previousVersion)
+            throws CacheException {
+        throw new UnsupportedOperationException("Illegal attempt to edit read only item");
+    }
+
+    @Override
+    public boolean afterUpdate(Object key, Object value, Object currentVersion, Object previousVersion, SoftLock lock)
+            throws CacheException {
+        throw new UnsupportedOperationException("Illegal attempt to edit read only item");
+    }
+}
diff --git a/src/test/java/org/hibernate/cache/PessimisticTreeCacheTest.java b/src/main/java/hibernate/cache/jbc/entity/OptimisticTransactionalAccess.java
similarity index 54%
copy from src/test/java/org/hibernate/cache/PessimisticTreeCacheTest.java
copy to src/main/java/hibernate/cache/jbc/entity/OptimisticTransactionalAccess.java
index a16245b..7097102 100644
--- a/src/test/java/org/hibernate/cache/PessimisticTreeCacheTest.java
+++ b/src/main/java/hibernate/cache/jbc/entity/OptimisticTransactionalAccess.java
@@ -1,64 +1,46 @@
-/*
- * 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;
-
-import junit.framework.Test;
-
-import org.hibernate.cfg.Environment;
-import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
-import org.hibernate.test.cache.BaseCacheProviderTestCase;
-
-/**
- * @author Steve Ebersole
- */
-public class PessimisticTreeCacheTest extends BaseCacheProviderTestCase {
-	public PessimisticTreeCacheTest(String x) {
-		super( x );
-	}
-
-	public static Test suite() {
-		return new FunctionalTestClassTestSuite( PessimisticTreeCacheTest.class );
-	}
-
-	public String getCacheConcurrencyStrategy() {
-		return "transactional";
-	}
-
-	protected Class getCacheProvider() {
-		return TreeCacheProvider.class;
-	}
-
-	protected String getConfigResourceKey() {
-		return Environment.CACHE_PROVIDER_CONFIG;
-	}
-
-	protected String getConfigResourceLocation() {
-		return "treecache-pessimistic.xml";
-	}
-
-	protected boolean useTransactionManager() {
-		return true;
-	}
-
-}
+/*
+ * 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.jbc.entity;
+
+import org.hibernate.cache.jbc.access.OptimisticTransactionalAccessDelegate;
+
+/**
+ * Defines the strategy for transactional access to entity data in an
+ * optimistic-locking JBoss Cache using its 2.x APIs
+ * 
+ * @author Brian Stansberry
+ * @version $Revision: 1 $
+ */
+public class OptimisticTransactionalAccess extends TransactionalAccess {
+
+    /**
+     * Create a new OptimisticTransactionalAccess.
+     * 
+     * @param region The region\ to which this is providing access
+     */
+    public OptimisticTransactionalAccess(EntityRegionImpl region) {
+        super(region, new OptimisticTransactionalAccessDelegate(region, region.getPutFromLoadValidator()));
+    }
+}
diff --git a/src/main/java/hibernate/cache/jbc/entity/ReadOnlyAccess.java b/src/main/java/hibernate/cache/jbc/entity/ReadOnlyAccess.java
new file mode 100644
index 0000000..f51467a
--- /dev/null
+++ b/src/main/java/hibernate/cache/jbc/entity/ReadOnlyAccess.java
@@ -0,0 +1,78 @@
+/*
+ * 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.jbc.entity;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.hibernate.cache.access.SoftLock;
+import org.hibernate.cache.CacheException;
+
+/**
+ * This defines the strategy for transactional access to enity data in
+ * JBossCache using its 2.x APIs <p/> read-only access to a JBossCache really is
+ * still transactional, just with the extra semantic or guarentee that we will
+ * not update data.
+ * 
+ * @author Steve Ebersole
+ */
+public class ReadOnlyAccess extends TransactionalAccess {
+    private static final Logger log = LoggerFactory.getLogger(ReadOnlyAccess.class);
+
+    public ReadOnlyAccess(EntityRegionImpl region) {
+        super(region);
+    }
+
+    @Override
+    public SoftLock lockItem(Object key, Object version) throws CacheException {
+        throw new UnsupportedOperationException("Illegal attempt to edit read only item");
+    }
+
+    @Override
+    public SoftLock lockRegion() throws CacheException {
+        throw new UnsupportedOperationException("Illegal attempt to edit read only region");
+    }
+
+    @Override
+    public void unlockItem(Object key, SoftLock lock) throws CacheException {
+        log.error("Illegal attempt to edit read only item");
+    }
+
+    @Override
+    public void unlockRegion(SoftLock lock) throws CacheException {
+        log.error("Illegal attempt to edit read only region");
+    }
+
+    @Override
+    public boolean update(Object key, Object value, Object currentVersion, Object previousVersion)
+            throws CacheException {
+        throw new UnsupportedOperationException("Illegal attempt to edit read only item");
+    }
+
+    @Override
+    public boolean afterUpdate(Object key, Object value, Object currentVersion, Object previousVersion, SoftLock lock)
+            throws CacheException {
+        throw new UnsupportedOperationException("Illegal attempt to edit read only item");
+    }
+}
diff --git a/src/main/java/hibernate/cache/jbc/entity/TransactionalAccess.java b/src/main/java/hibernate/cache/jbc/entity/TransactionalAccess.java
new file mode 100644
index 0000000..06a8a74
--- /dev/null
+++ b/src/main/java/hibernate/cache/jbc/entity/TransactionalAccess.java
@@ -0,0 +1,130 @@
+/*
+ * 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.jbc.entity;
+
+import org.hibernate.cache.access.EntityRegionAccessStrategy;
+import org.hibernate.cache.access.SoftLock;
+import org.hibernate.cache.jbc.access.TransactionalAccessDelegate;
+import org.hibernate.cache.EntityRegion;
+import org.hibernate.cache.CacheException;
+
+/**
+ * Defines the strategy for transactional access to entity data in a
+ * pessimistic-locking JBossCache using its 2.x APIs
+ * 
+ * @author Steve Ebersole
+ */
+public class TransactionalAccess implements EntityRegionAccessStrategy {
+
+    protected final EntityRegionImpl region;
+
+    /**
+     * Most of our logic is shared between this and entity regions, so we
+     * delegate to a class that encapsulates it
+     */
+    private final TransactionalAccessDelegate delegate;
+
+    public TransactionalAccess(EntityRegionImpl region) {
+        this(region, new TransactionalAccessDelegate(region, region.getPutFromLoadValidator()));
+    }
+
+    protected TransactionalAccess(EntityRegionImpl region, TransactionalAccessDelegate delegate) {
+        this.region = region;
+        this.delegate = delegate;
+    }
+
+    public EntityRegion getRegion() {
+        return region;
+    }
+
+    public Object get(Object key, long txTimestamp) throws CacheException {
+
+        return delegate.get(key, txTimestamp);
+    }
+
+    public boolean putFromLoad(Object key, Object value, long txTimestamp, Object version) throws CacheException {
+
+        return delegate.putFromLoad(key, value, txTimestamp, version);
+    }
+
+    public boolean putFromLoad(Object key, Object value, long txTimestamp, Object version, boolean minimalPutOverride)
+            throws CacheException {
+
+        return delegate.putFromLoad(key, value, txTimestamp, version, minimalPutOverride);
+    }
+
+    public boolean insert(Object key, Object value, Object version) throws CacheException {
+
+        return delegate.insert(key, value, version);
+    }
+
+    public boolean update(Object key, Object value, Object currentVersion, Object previousVersion)
+            throws CacheException {
+
+        return delegate.update(key, value, currentVersion, previousVersion);
+    }
+
+    public void remove(Object key) throws CacheException {
+
+        delegate.remove(key);
+    }
+
+    public void removeAll() throws CacheException {
+        delegate.removeAll();
+    }
+
+    public void evict(Object key) throws CacheException {
+        delegate.evict(key);
+    }
+
+    public void evictAll() throws CacheException {
+        delegate.evictAll();
+    }
+
+    // Following methods we don't delegate since they have so little logic
+    // it's clearer to just implement them here
+
+    public SoftLock lockItem(Object key, Object version) throws CacheException {
+        return null;
+    }
+
+    public SoftLock lockRegion() throws CacheException {
+        return null;
+    }
+
+    public void unlockItem(Object key, SoftLock lock) throws CacheException {
+    }
+
+    public void unlockRegion(SoftLock lock) throws CacheException {
+    }
+
+    public boolean afterInsert(Object key, Object value, Object version) throws CacheException {
+        return false;
+    }
+
+    public boolean afterUpdate(Object key, Object value, Object currentVersion, Object previousVersion, SoftLock lock)
+            throws CacheException {
+        return false;
+    }
+}
diff --git a/src/main/java/hibernate/cache/jbc/query/QueryResultsRegionImpl.java b/src/main/java/hibernate/cache/jbc/query/QueryResultsRegionImpl.java
new file mode 100644
index 0000000..5c706d4
--- /dev/null
+++ b/src/main/java/hibernate/cache/jbc/query/QueryResultsRegionImpl.java
@@ -0,0 +1,159 @@
+/*
+ * 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.jbc.query;
+
+import java.util.Properties;
+
+import javax.transaction.Transaction;
+
+import org.hibernate.cache.CacheException;
+import org.hibernate.cache.QueryResultsRegion;
+import org.hibernate.cache.jbc.TransactionalDataRegionAdapter;
+import org.hibernate.cache.jbc.util.CacheHelper;
+import org.hibernate.util.PropertiesHelper;
+import org.jboss.cache.Cache;
+import org.jboss.cache.Fqn;
+import org.jboss.cache.config.Option;
+import org.jboss.cache.notifications.annotation.CacheListener;
+
+/**
+ * Defines the behavior of the query cache regions for JBossCache 2.x.
+ * 
+ * @author Brian Stansberry
+ * @version $Revision$
+ */
+ at CacheListener
+public class QueryResultsRegionImpl extends TransactionalDataRegionAdapter implements QueryResultsRegion {
+
+    public static final String QUERY_CACHE_LOCAL_ONLY_PROP = "hibernate.cache.jbc.query.localonly";
+    public static final String LEGACY_QUERY_CACHE_LOCAL_ONLY_PROP = "hibernate.cache.region.jbc2.query.localonly";
+    public static final String TYPE = "QUERY";
+    
+    /**
+     * Whether we should set an option to disable propagation of changes around
+     * cluster.
+     */
+    private boolean localOnly;
+
+    /**
+     * Create a new QueryResultsRegionImpl.
+     * 
+     * @param jbcCache The JBC cache instance to use to store the query results
+     * @param regionName The name of the region (within the JBC cache)
+     * @param regionPrefix Any region prefix to apply
+	 * @param properties The configuration properties.
+     */
+    public QueryResultsRegionImpl(Cache jbcCache, String regionName, String regionPrefix, Properties properties) {
+        super(jbcCache, regionName, regionPrefix, null);
+
+        // If JBC is using INVALIDATION, we don't want to propagate changes.
+        // We use the Timestamps cache to manage invalidation
+        localOnly = CacheHelper.isClusteredInvalidation(jbcCache);
+        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
+        	if (CacheHelper.isClusteredReplication(jbcCache)) {
+        		if (properties.containsKey(QUERY_CACHE_LOCAL_ONLY_PROP)) {
+        			localOnly = PropertiesHelper.getBoolean(QUERY_CACHE_LOCAL_ONLY_PROP, properties, false);
+        		}
+        		else {
+        			localOnly = PropertiesHelper.getBoolean(LEGACY_QUERY_CACHE_LOCAL_ONLY_PROP, properties, false);
+        		}
+        	}
+        }
+    }
+
+    public void evict(Object key) throws CacheException {
+       
+        ensureRegionRootExists();
+        
+        Option opt = getNonLockingDataVersionOption(false);
+        if (localOnly)
+            opt.setCacheModeLocal(true);
+        CacheHelper.removeNode(getCacheInstance(), getRegionFqn(), key, opt);
+    }
+
+    public void evictAll() throws CacheException {
+          Transaction tx = suspend();
+          try {        
+             ensureRegionRootExists();
+             Option opt = getNonLockingDataVersionOption(true);
+             CacheHelper.sendEvictAllNotification(jbcCache, regionFqn, getMemberId(), opt);
+          }
+          finally {
+             resume(tx);
+          }        
+    }
+
+    public Object get(Object key) throws CacheException {
+       
+        if (!checkValid())
+           return null;
+       
+        ensureRegionRootExists();
+
+        // 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
+        Option opt = new Option();
+        opt.setLockAcquisitionTimeout(0);
+        return suspendAndGet(key, opt, true);
+    }
+
+    public void put(Object key, Object value) throws CacheException {
+       
+        if (checkValid()) {
+           ensureRegionRootExists();
+   
+           // 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.
+           Option opt = getNonLockingDataVersionOption(false);
+           opt.setLockAcquisitionTimeout(2);
+           if (localOnly)
+               opt.setCacheModeLocal(true);
+           CacheHelper.putAllowingTimeout(getCacheInstance(), getRegionFqn(), key, value, opt);
+        }
+    }
+
+    @Override
+    protected Fqn<String> createRegionFqn(String regionName, String regionPrefix) {
+        return getTypeLastRegionFqn(regionName, regionPrefix, TYPE);
+    }
+
+}
diff --git a/src/main/java/hibernate/cache/jbc/timestamp/ClusteredConcurrentTimestampsRegionImpl.java b/src/main/java/hibernate/cache/jbc/timestamp/ClusteredConcurrentTimestampsRegionImpl.java
new file mode 100644
index 0000000..9c59a06
--- /dev/null
+++ b/src/main/java/hibernate/cache/jbc/timestamp/ClusteredConcurrentTimestampsRegionImpl.java
@@ -0,0 +1,361 @@
+/*
+ * Copyright (c) 2007, Red Hat Middleware, LLC. All rights reserved.
+ *
+ * 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, v. 2.1. This program is distributed in the
+ * hope that it will be useful, but WITHOUT A 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, v.2.1 along with this
+ * distribution; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Red Hat Author(s): Brian Stansberry
+ */
+
+package org.hibernate.cache.jbc.timestamp;
+
+import java.util.Properties;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.Semaphore;
+
+import javax.transaction.Transaction;
+
+import org.hibernate.cache.CacheException;
+import org.hibernate.cache.TimestampsRegion;
+import org.hibernate.cache.jbc.TransactionalDataRegionAdapter;
+import org.hibernate.cache.jbc.util.CacheHelper;
+import org.jboss.cache.Cache;
+import org.jboss.cache.Fqn;
+import org.jboss.cache.config.Option;
+import org.jboss.cache.notifications.annotation.CacheListener;
+import org.jboss.cache.notifications.annotation.NodeModified;
+import org.jboss.cache.notifications.annotation.NodeRemoved;
+import org.jboss.cache.notifications.event.NodeModifiedEvent;
+import org.jboss.cache.notifications.event.NodeRemovedEvent;
+
+/**
+ * Prototype of a clustered timestamps cache region impl usable if the
+ * TimestampsRegion API is changed.
+ * <p>
+ * Maintains a local (authoritative) cache of timestamps along with the
+ * distributed cache held in JBoss Cache. Listens for changes in the distributed
+ * cache and updates the local cache accordingly. Ensures that any changes in
+ * the local cache represent either 1) an increase in the timestamp or 
+ * 2) a stepback in the timestamp by the caller that initially increased
+ * it as part of a pre-invalidate call. This approach allows
+ * timestamp changes to be replicated asynchronously by JBoss Cache while still
+ * preventing invalid backward changes in timestamps.
+ * </p>
+ * 
+ * NOTE: This is just a prototype!!! Only useful if we change the 
+ * TimestampsRegion API.
+ * 
+ * @author Brian Stansberry
+ * @version $Revision: 14106 $
+ */
+ at CacheListener
+public class ClusteredConcurrentTimestampsRegionImpl extends TransactionalDataRegionAdapter implements TimestampsRegion {
+
+    public static final String TYPE = "TS";
+    
+    private final ConcurrentHashMap localCache = new ConcurrentHashMap();
+    
+    /**
+     * Create a new ClusteredConccurentTimestampsRegionImpl.
+     * 
+     * @param jbcCache
+     * @param regionName
+     * @param regionPrefix
+     *            TODO
+     * @param metadata
+     */
+    public ClusteredConcurrentTimestampsRegionImpl(Cache jbcCache, String regionName, String regionPrefix, Properties properties) {
+        super(jbcCache, regionName, regionPrefix, null);
+
+        jbcCache.addCacheListener(this);
+
+        populateLocalCache();
+    }
+
+    @Override
+    protected Fqn<String> createRegionFqn(String regionName, String regionPrefix) {
+        return getTypeFirstRegionFqn(regionName, regionPrefix, TYPE);
+    }
+
+    public void evict(Object key) throws CacheException {
+        Option opt = getNonLockingDataVersionOption(true);
+        CacheHelper.removeNode(getCacheInstance(), getRegionFqn(), key, opt);
+    }
+
+    public void evictAll() throws CacheException {
+        Option opt = getNonLockingDataVersionOption(true);
+        CacheHelper.removeAll(getCacheInstance(), getRegionFqn(), opt);
+    }
+
+    public Object get(Object key) throws CacheException {
+        Entry entry = getLocalEntry(key);
+        Object timestamp = entry.getCurrent();
+        if (timestamp == null) {
+            // Double check the distributed cache
+            Object[] vals = (Object[]) suspendAndGet(key, null, false);
+            if (vals != null) {
+                storeDataFromJBC(key, vals);
+                timestamp = entry.getCurrent();
+            }
+        }
+        return timestamp;
+    }
+
+    public void put(Object key, Object value) throws CacheException {
+        
+        throw new UnsupportedOperationException("Prototype only; Hibernate core must change the API before really using");
+    }
+    
+    public void preInvalidate(Object key, Object value) throws CacheException {
+        
+        Entry entry = getLocalEntry(key);
+        if (entry.preInvalidate(value)) {
+            putInJBossCache(key, entry);
+        }
+    }
+    
+    public void invalidate(Object key, Object value, Object preInvalidateValue) throws CacheException {
+        
+        Entry entry = getLocalEntry(key);
+        if (entry.invalidate(value, preInvalidateValue)) {
+            putInJBossCache(key, entry);
+        }
+    }
+    
+    private void putInJBossCache(Object key, Entry entry) {        
+    
+        // Get an exclusive right to update JBC for this key from this node.
+        boolean locked = false;
+        try {
+            entry.acquireJBCWriteMutex();
+            locked = true;
+            // We have the JBCWriteMutex, so no other *local* thread will 
+            // be trying to write this key. 
+            // It's possible here some remote thread has come in and
+            // changed the values again, but since we are reading the
+            // values to write to JBC right now, we know we are writing
+            // the latest values; i.e. we don't assume that what we cached
+            // in entry.update() above is what we should write to JBC *now*.
+            // Our write could be redundant, i.e. we are writing what
+            // some remote thread just came in an wrote.  There is a chance 
+            // that yet another remote thread will update us, and we'll then
+            // overwrite that later data in JBC.  But, all remote nodes will
+            // ignore that change in their localCache; the only place it 
+            // will live will be in JBC, where it can only effect the 
+            // initial state transfer values on newly joined nodes 
+            // (i.e. populateLocalCache()).
+            
+            // Don't hold the JBC node lock throughout the tx, as that
+            // prevents reads and other updates
+            Transaction tx = suspend();
+            try {
+                Option opt = getNonLockingDataVersionOption(false);
+                // We ensure ASYNC semantics (JBCACHE-1175)
+                opt.setForceAsynchronous(true);
+                CacheHelper.put(getCacheInstance(), getRegionFqn(), key, entry.getJBCUpdateValues(), opt);
+            } 
+            finally {
+                resume(tx);
+            }  
+        } 
+        catch (InterruptedException e) {
+            throw new CacheException("Interrupted while acquiring right to update " + key, e);
+        } 
+        finally {
+            if (locked) {
+                entry.releaseJBCWriteMutex();
+            }
+        }
+    }
+
+    @Override
+    public void destroy() throws CacheException {
+
+        getCacheInstance().removeCacheListener(this);
+        super.destroy();
+        localCache.clear();
+    }
+
+    /**
+     * Monitors cache events and updates the local cache
+     * 
+     * @param event
+     */
+    @NodeModified
+    public void nodeModified(NodeModifiedEvent event) {
+        if (event.isOriginLocal() || event.isPre())
+            return;
+
+        Fqn fqn = event.getFqn();
+        Fqn regFqn = getRegionFqn();
+        if (fqn.size() == regFqn.size() + 1 && fqn.isChildOf(regFqn)) {
+            Object key = fqn.get(regFqn.size());
+            Object[] vals = (Object[]) event.getData().get(ITEM);
+            storeDataFromJBC(key, vals);
+            // TODO consider this hack instead of the simple entry.update above:
+//            if (!entry.update(vals[0], vals[1])) {
+//                // Hack! Use the fact that the Object[] stored in JBC is
+//                // mutable to correct our local JBC state in this callback
+//                Object[] correct = entry.getJBCUpdateValues();
+//                vals[0] = correct[0];
+//                vals[1] = correct[1];
+//            }
+        }
+    }
+    
+    private void storeDataFromJBC(Object key, Object[] vals) {
+        Entry entry = getLocalEntry(key);
+        if (vals[0].equals(vals[1])) {
+            entry.preInvalidate(vals[0]);
+        }
+        else {
+            entry.invalidate(vals[0], vals[1]);
+        }
+    }
+
+    /**
+     * Monitors cache events and updates the local cache
+     * 
+     * @param event
+     */
+    @NodeRemoved
+    public void nodeRemoved(NodeRemovedEvent event) {
+        if (event.isOriginLocal() || event.isPre())
+            return;
+
+        Fqn fqn = event.getFqn();
+        Fqn regFqn = getRegionFqn();
+        if (fqn.isChildOrEquals(regFqn)) {
+            if (fqn.size() == regFqn.size()) {
+                localCache.clear();
+            }
+            else {
+                Object key = fqn.get(regFqn.size());
+                localCache.remove(key);
+            }
+        }
+    }
+
+    /**
+     * Brings all data from the distributed cache into our local cache.
+     */
+    private void populateLocalCache() {
+        Set children = CacheHelper.getChildrenNames(getCacheInstance(), getRegionFqn());
+        for (Object key : children) {
+            Object[] vals = (Object[]) suspendAndGet(key, null, false);
+            if (vals != null) {
+                storeDataFromJBC(key, vals);
+            }
+        }
+    }
+    
+    private Entry getLocalEntry(Object key) {
+        
+        Entry entry = new Entry();
+        Entry oldEntry = (Entry) localCache.putIfAbsent(key, entry);
+        return (oldEntry == null ? entry : oldEntry);
+    }
+    
+    private class Entry {
+        
+        private Semaphore writeMutex = new Semaphore(1);
+        private boolean preInvalidated = false;
+        private Object preInval  = null;
+        private Object current = null;
+        
+        void acquireJBCWriteMutex() throws InterruptedException {
+            writeMutex.acquire();
+        }
+        
+        void releaseJBCWriteMutex() {
+            writeMutex.release();
+        }
+        
+        synchronized boolean preInvalidate(Object newVal) {
+            
+            boolean result = false;
+            if (newVal instanceof Comparable) {
+                if (current == null || ((Comparable) newVal).compareTo(current) > 0) {
+                    preInval = current = newVal;
+                    preInvalidated = true;
+                    result = true;
+                }
+            }
+            else {
+                preInval = current = newVal;
+                result = true;
+            }
+            
+            return result;
+        }
+        
+        synchronized boolean invalidate(Object newVal, Object preInvalidateValue) {
+            
+            boolean result = false;
+            
+            if (current == null) {
+                // Initial load from JBC
+                current = newVal;
+                preInval = preInvalidateValue;
+                preInvalidated = false;
+                result = true;     
+            }
+            else if (preInvalidated) {
+                if (newVal instanceof Comparable) {
+                    if (safeEquals(preInvalidateValue, this.preInval)
+                            || ((Comparable) newVal).compareTo(preInval) > 0) {
+                        current = newVal;
+                        preInval = preInvalidateValue;
+                        preInvalidated = false;
+                        result =  true;                    
+                    }
+                }
+                else {
+                    current = newVal;
+                    preInval = preInvalidateValue;
+                    result =  true;
+                }
+            }
+            else if (newVal instanceof Comparable) {
+                // See if we had a 2nd invalidation from the same initial
+                // preinvalidation timestamp. If so, only increment
+                // if the new current value is an increase
+                if (safeEquals(preInvalidateValue, this.preInval)
+                        && ((Comparable) newVal).compareTo(current) > 0) {
+                    current = newVal;
+                    preInval = preInvalidateValue;
+                    result =  true;                    
+                }
+            }  
+            
+            return result;
+        }
+        
+        synchronized Object getCurrent() {
+            return current;
+        }
+        
+        synchronized Object getPreInval() {
+            return preInval;
+        }
+        
+        synchronized Object[] getJBCUpdateValues() {
+            return new Object[] {current, preInval};
+        }
+        
+        private boolean safeEquals(Object a, Object b) {
+            return (a == b || (a != null && a.equals(b)));
+        }
+    }
+    
+    
+
+}
diff --git a/src/main/java/hibernate/cache/jbc/timestamp/TimestampsRegionImpl.java b/src/main/java/hibernate/cache/jbc/timestamp/TimestampsRegionImpl.java
new file mode 100644
index 0000000..d98612b
--- /dev/null
+++ b/src/main/java/hibernate/cache/jbc/timestamp/TimestampsRegionImpl.java
@@ -0,0 +1,222 @@
+/*
+ * 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.jbc.timestamp;
+
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+
+import javax.transaction.Transaction;
+
+import org.hibernate.cache.CacheException;
+import org.hibernate.cache.TimestampsRegion;
+import org.hibernate.cache.jbc.TransactionalDataRegionAdapter;
+import org.hibernate.cache.jbc.util.CacheHelper;
+import org.jboss.cache.Cache;
+import org.jboss.cache.Fqn;
+import org.jboss.cache.config.Option;
+import org.jboss.cache.notifications.annotation.CacheListener;
+import org.jboss.cache.notifications.annotation.NodeModified;
+import org.jboss.cache.notifications.annotation.NodeRemoved;
+import org.jboss.cache.notifications.event.NodeInvalidatedEvent;
+import org.jboss.cache.notifications.event.NodeModifiedEvent;
+import org.jboss.cache.notifications.event.NodeRemovedEvent;
+
+/**
+ * Defines the behavior of the timestamps cache region for JBossCache 2.x.
+ * 
+ * TODO Need to define a way to ensure asynchronous replication events
+ * do not result in timestamps moving backward, while dealing with the fact
+ * that the normal sequence of UpdateTimestampsCache.preinvalidate() then
+ * UpdateTimestampsCache.invalidate() will result in 2 calls to put() with
+ * the latter call having an earlier timestamp.
+ * 
+ * @author Brian Stansberry
+ * @version $Revision$
+ */
+ at CacheListener
+public class TimestampsRegionImpl extends TransactionalDataRegionAdapter implements TimestampsRegion {
+
+    public static final String TYPE = "TS";
+
+    private Map localCache = new ConcurrentHashMap();
+    
+    /**
+     * Create a new TimestampsRegionImpl.
+	 *
+     * @param jbcCache The JBC cache instance to use to store the timestamps data
+     * @param regionName The name of the region (within the JBC cache)
+     * @param regionPrefix Any region prefix to apply
+	 * @param properties The configuration properties.
+     */
+    public TimestampsRegionImpl(Cache jbcCache, String regionName, String regionPrefix, Properties properties) {
+        super(jbcCache, regionName, regionPrefix, null);
+
+        jbcCache.addCacheListener(this);
+
+        populateLocalCache();
+    }
+
+    @Override
+    protected Fqn<String> createRegionFqn(String regionName, String regionPrefix) {
+        return getTypeFirstRegionFqn(regionName, regionPrefix, TYPE);
+    }
+
+    public void evict(Object key) throws CacheException {
+       
+        ensureRegionRootExists();
+        
+        // TODO Is this a valid operation on a timestamps cache?
+        Option opt = getNonLockingDataVersionOption(true);
+        CacheHelper.removeNode(getCacheInstance(), getRegionFqn(), key, opt);
+    }
+
+    public void evictAll() throws CacheException {
+        // TODO Is this a valid operation on a timestamps cache?
+        Transaction tx = suspend();
+        try {        
+           ensureRegionRootExists();
+           Option opt = getNonLockingDataVersionOption(true);
+           CacheHelper.sendEvictAllNotification(jbcCache, regionFqn, getMemberId(), opt);
+        }
+        finally {
+           resume(tx);
+        }        
+    }
+
+    public Object get(Object key) throws CacheException {
+
+        Object value = localCache.get(key);
+        if (value == null && checkValid()) {
+           
+            ensureRegionRootExists();
+            
+            value = suspendAndGet(key, null, false);
+            if (value != null)
+                localCache.put(key, value);
+        }
+        return value;
+    }
+
+    public void put(Object key, Object value) throws CacheException {
+       
+        ensureRegionRootExists();
+
+        // Don't hold the JBC node lock throughout the tx, as that
+        // prevents reads and other updates
+        Transaction tx = suspend();
+        try {
+            // TODO Why not use the timestamp in a DataVersion?
+            Option opt = getNonLockingDataVersionOption(false);
+            // We ensure ASYNC semantics (JBCACHE-1175)
+            opt.setForceAsynchronous(true);
+            CacheHelper.put(getCacheInstance(), getRegionFqn(), key, value, opt);
+        } catch (Exception e) {
+            throw new CacheException(e);
+        } finally {
+            resume(tx);
+        }
+    }
+
+    @Override
+    public void destroy() throws CacheException {
+        localCache.clear();
+        getCacheInstance().removeCacheListener(this);
+        super.destroy();
+    }
+
+    /**
+     * Monitors cache events and updates the local cache
+     * 
+     * @param event
+     */
+    @NodeModified
+    public void nodeModified(NodeModifiedEvent event) {
+       
+        if (!handleEvictAllModification(event) && !event.isPre()) {
+   
+           Fqn fqn = event.getFqn();
+           Fqn regFqn = getRegionFqn();
+           if (fqn.size() == regFqn.size() + 1 && fqn.isChildOf(regFqn)) {
+               Object key = fqn.get(regFqn.size());
+               localCache.put(key, event.getData().get(ITEM));
+           }
+        }
+    }
+
+    /**
+     * Monitors cache events and updates the local cache
+     * 
+     * @param event
+     */
+    @NodeRemoved
+    public void nodeRemoved(NodeRemovedEvent event) {
+        if (event.isPre())
+            return;
+
+        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();
+        }
+    }
+    
+    
+
+    @Override
+   protected boolean handleEvictAllInvalidation(NodeInvalidatedEvent event)
+   {
+      boolean result = super.handleEvictAllInvalidation(event);
+      if (result) {
+         localCache.clear();
+      }
+      return result;
+   }
+
+   @Override
+   protected boolean handleEvictAllModification(NodeModifiedEvent event)
+   {
+      boolean result = super.handleEvictAllModification(event);
+      if (result) {
+         localCache.clear();
+      }
+      return result;
+   }
+
+   /**
+     * Brings all data from the distributed cache into our local cache.
+     */
+    private void populateLocalCache() {
+        Set children = CacheHelper.getChildrenNames(getCacheInstance(), getRegionFqn());
+        for (Object key : children) {
+            get(key);
+        }
+    }
+}
diff --git a/src/main/java/hibernate/cache/jbc/util/CacheHelper.java b/src/main/java/hibernate/cache/jbc/util/CacheHelper.java
new file mode 100644
index 0000000..aaa13a8
--- /dev/null
+++ b/src/main/java/hibernate/cache/jbc/util/CacheHelper.java
@@ -0,0 +1,491 @@
+/*
+ * 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.jbc.util;
+
+import java.util.Collections;
+import java.util.Set;
+
+import org.hibernate.cache.CacheException;
+import org.jboss.cache.Cache;
+import org.jboss.cache.Fqn;
+import org.jboss.cache.InvocationContext;
+import org.jboss.cache.Node;
+import org.jboss.cache.config.Configuration;
+import org.jboss.cache.config.Option;
+import org.jboss.cache.lock.TimeoutException;
+import org.jboss.cache.optimistic.DataVersion;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Helper for dealing with JBossCache {@link Configuration.CacheMode}.
+ * 
+ * @author Steve Ebersole
+ * @author Brian Stansberry
+ */
+public class CacheHelper {
+
+    public static enum Internal { NODE, LOCAL };
+    
+    /** 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 getChildrenNames(Cache cache, Fqn fqn) {
+        Node node = cache.getRoot().getChild(fqn);
+        return (node != null) ? node.getChildrenNames() : Collections.emptySet();
+    }
+
+    /**
+     * 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, Fqn region, Object key) throws CacheException {
+        try {
+            return cache.get(new Fqn(region, key), ITEM);
+        } 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 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 getAllowingTimeout(Cache cache, Fqn region, Object key) throws CacheException {
+        try {
+            return cache.get(new Fqn(region, key), ITEM);        
+        } 
+        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, Fqn region, Object key, Object value) throws CacheException {
+
+        put(cache, region, 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, Fqn region, Object key, Object value, Option option) throws CacheException {
+        try {
+            setInvocationOption(cache, option);
+            cache.put(new Fqn(region, key), ITEM, value);
+        } 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, Fqn region, Object key, Object value, Option option) throws CacheException {
+        try {
+            setInvocationOption(cache, option);
+            cache.put(new Fqn(region, key), ITEM, value);
+        }
+        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, Fqn region, Object key, Object value) throws CacheException {
+
+        return putForExternalRead(cache, region, 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, Fqn region, Object key, Object value, Option option)
+            throws CacheException {
+        try {
+            setInvocationOption(cache, option);
+            cache.putForExternalRead(new Fqn(region, key), ITEM, value);
+            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, Fqn region, Object key) throws CacheException {
+
+        remove(cache, region, 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, Fqn region, Object key, Option option) throws CacheException {
+        try {
+            setInvocationOption(cache, option);
+            cache.removeNode(new Fqn(region, key));
+        } 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, Fqn region) throws CacheException {
+
+        removeAll(cache, region, null);
+    }
+
+    /**
+     * 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, Fqn region, Option option) throws CacheException {
+        try {
+            setInvocationOption(cache, option);
+            cache.removeNode(region);
+        } 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 removeNode(Cache cache, Fqn region, Object key, Option option) throws CacheException {
+        try {
+            setInvocationOption(cache, option);
+            cache.removeNode(new Fqn(region, key));
+        } catch (Exception e) {
+            throw new CacheException(e);
+        }
+    }
+    
+    public static Node addNode(Cache cache, Fqn fqn, boolean localOnly, boolean resident, DataVersion version)
+            throws CacheException {
+        try {
+            Option option = null;
+            if (localOnly || version != null) {
+                option = new Option();
+                option.setCacheModeLocal(localOnly);
+                option.setDataVersion(version);
+            }
+            
+            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);
+    }
+    
+    public static Fqn getInternalFqn(Fqn region)
+    {
+       return Fqn.fromRelativeElements(region, Internal.NODE);
+    }
+    
+    public static void sendEvictNotification(Cache cache, Fqn region, Object member, Object key, Option option)
+    {
+       setInvocationOption(cache, option);
+       Fqn f = Fqn.fromRelativeElements(region, Internal.NODE, member  == null ? Internal.LOCAL : member, key);
+       cache.put(f, ITEM, DUMMY);
+    }
+    
+    public static void sendEvictAllNotification(Cache cache, Fqn region, Object member, Option option)
+    {
+       setInvocationOption(cache, option);
+       Fqn f = Fqn.fromRelativeElements(region, Internal.NODE, member  == null ? Internal.LOCAL : member);
+       cache.put(f, ITEM, DUMMY);
+    }
+}
diff --git a/src/test/java/org/hibernate/cache/PessimisticTreeCacheTest.java b/src/main/java/hibernate/cache/jbc/util/CircumventChecksDataVersion.java
similarity index 50%
rename from src/test/java/org/hibernate/cache/PessimisticTreeCacheTest.java
rename to src/main/java/hibernate/cache/jbc/util/CircumventChecksDataVersion.java
index a16245b..8109258 100644
--- a/src/test/java/org/hibernate/cache/PessimisticTreeCacheTest.java
+++ b/src/main/java/hibernate/cache/jbc/util/CircumventChecksDataVersion.java
@@ -1,64 +1,54 @@
-/*
- * 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;
-
-import junit.framework.Test;
-
-import org.hibernate.cfg.Environment;
-import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
-import org.hibernate.test.cache.BaseCacheProviderTestCase;
-
-/**
- * @author Steve Ebersole
- */
-public class PessimisticTreeCacheTest extends BaseCacheProviderTestCase {
-	public PessimisticTreeCacheTest(String x) {
-		super( x );
-	}
-
-	public static Test suite() {
-		return new FunctionalTestClassTestSuite( PessimisticTreeCacheTest.class );
-	}
-
-	public String getCacheConcurrencyStrategy() {
-		return "transactional";
-	}
-
-	protected Class getCacheProvider() {
-		return TreeCacheProvider.class;
-	}
-
-	protected String getConfigResourceKey() {
-		return Environment.CACHE_PROVIDER_CONFIG;
-	}
-
-	protected String getConfigResourceLocation() {
-		return "treecache-pessimistic.xml";
-	}
-
-	protected boolean useTransactionManager() {
-		return true;
-	}
-
-}
+/*
+ * 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.jbc.util;
+
+import org.hibernate.cache.CacheException;
+import org.jboss.cache.config.Option;
+import org.jboss.cache.optimistic.DataVersion;
+
+/**
+ * Used to signal to a DataVersionAdapter to simply not perform any checks. This
+ * is currently needed for proper handling of remove() calls for entity cache
+ * regions (we do not know the version info...).
+ * 
+ * @author <a href="brian.stansberry at jboss.com">Brian Stansberry</a>
+ * @version $Revision: 1 $
+ */
+public class CircumventChecksDataVersion implements DataVersion {
+
+    private static final long serialVersionUID = 7996980646166032369L;
+
+    public static final DataVersion INSTANCE = new CircumventChecksDataVersion();
+
+    public static Option getInvocationOption() {
+        Option option = new Option();
+        option.setDataVersion(INSTANCE);
+        return option;
+    }
+
+    public boolean newerThan(DataVersion dataVersion) {
+        throw new CacheException("optimistic locking checks should never happen on CircumventChecksDataVersion");
+    }
+
+}
diff --git a/src/main/java/hibernate/cache/jbc/util/DataVersionAdapter.java b/src/main/java/hibernate/cache/jbc/util/DataVersionAdapter.java
new file mode 100644
index 0000000..a08f251
--- /dev/null
+++ b/src/main/java/hibernate/cache/jbc/util/DataVersionAdapter.java
@@ -0,0 +1,166 @@
+/*
+ * 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.jbc.util;
+
+import java.io.IOException;
+import java.util.Comparator;
+
+import org.hibernate.cache.jbc.entity.TransactionalAccess;
+import org.hibernate.util.CalendarComparator;
+import org.hibernate.util.ComparableComparator;
+import org.jboss.cache.optimistic.DataVersion;
+import org.jboss.cache.optimistic.DefaultDataVersion;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A DataVersionAdapter.
+ * 
+ * @author <a href="brian.stansberry at jboss.com">Brian Stansberry</a>
+ * @version $Revision: 1 $
+ */
+public class DataVersionAdapter implements DataVersion {
+
+    private static final Logger log = LoggerFactory.getLogger(TransactionalAccess.class);
+
+    private static final long serialVersionUID = 5564692336076405571L;
+
+    private final Object currentVersion;
+
+    private final Object previousVersion;
+
+    /** 
+     * Comparator does not extend Serializable and the std impls don't either,
+     * so we make the field transient to allow special handling
+     */
+    private transient Comparator versionComparator;
+
+    private final String sourceIdentifer;
+
+    public DataVersionAdapter(Object currentVersion, Object previousVersion, Comparator versionComparator,
+            String sourceIdentifer) {
+        this.currentVersion = currentVersion;
+        this.previousVersion = previousVersion;
+        this.versionComparator = versionComparator;
+        this.sourceIdentifer = sourceIdentifer;
+        log.trace("created " + this);
+    }
+
+    /**
+     * newerThan() call is dispatched against the DataVersion currently
+     * associated with the node; the passed dataVersion param is the DataVersion
+     * associated with the data we are trying to put into the node. <p/> we are
+     * expected to return true in the case where we (the current node
+     * DataVersion) are newer that then incoming value. Returning true here
+     * essentially means that a optimistic lock failure has occured (because
+     * conversely, the value we are trying to put into the node is "older than"
+     * the value already there...)
+     */
+    public boolean newerThan(DataVersion dataVersion) {
+        log.trace("checking [" + this + "] against [" + dataVersion + "]");
+        if (dataVersion instanceof CircumventChecksDataVersion) {
+            log.trace("skipping lock checks...");
+            return false;
+        } else if (dataVersion instanceof NonLockingDataVersion) {
+            // can happen because of the multiple ways Cache.remove()
+            // can be invoked :(
+            log.trace("skipping lock checks...");
+            return false;
+        } else if (dataVersion instanceof DefaultDataVersion) {
+            // JBC put a version in the node when it created as part of
+            // some internal operation. We are always newer, but if
+            // the JBC version is > 1 something odd has happened
+            if (((DefaultDataVersion) dataVersion).getRawVersion() > 1) {
+                log.warn("Unexpected comparison to " + dataVersion +
+                         " -- we are " + toString());
+            }
+            return true;
+        }
+        
+        DataVersionAdapter other = (DataVersionAdapter) dataVersion;
+        if (other.previousVersion == null) {
+            log.warn("Unexpected optimistic lock check on inserting data");
+            // work around the "feature" where tree cache is validating the
+            // inserted node during the next transaction. no idea...
+            if (this == dataVersion) {
+                log.trace("skipping lock checks due to same DV instance");
+                return false;
+            }
+        }
+
+        if (currentVersion == null) {
+            // If the workspace node has null as well, OK; if not we've
+            // been modified in a non-comparable manner, which we have to
+            // treat as us being newer
+            return (other.previousVersion != null);
+        }
+        
+        // Can't be newer than itself
+        if ( this == dataVersion ) {
+            return false;
+        }
+
+        return versionComparator.compare(currentVersion, other.previousVersion) >= 1;
+    }
+
+    public String toString() {
+        return super.toString() + " [current=" + currentVersion + ", previous=" + previousVersion + ", src="
+                + sourceIdentifer + "]";
+    }
+    
+    
+    private void writeObject(java.io.ObjectOutputStream out) throws IOException {
+        out.defaultWriteObject();
+        
+        // The standard comparator types are not Serializable but are singletons
+        if (versionComparator instanceof ComparableComparator)
+            out.writeByte(0);
+        else if (versionComparator instanceof CalendarComparator)
+            out.writeByte(1);
+        else {
+            out.writeByte(999);
+            out.writeObject(versionComparator);
+        }
+    }
+    
+    private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException  {
+        
+        in.defaultReadObject();
+        byte comparatorType = in.readByte();
+        switch (comparatorType) {
+            case 0:
+                versionComparator = ComparableComparator.INSTANCE;
+                break;
+            case 1:
+                versionComparator = CalendarComparator.INSTANCE;
+                break;
+            default:
+                versionComparator = (Comparator) in.readObject();
+        }
+    }
+    
+    
+
+}
diff --git a/src/main/java/hibernate/cache/jbc/util/NonLockingDataVersion.java b/src/main/java/hibernate/cache/jbc/util/NonLockingDataVersion.java
new file mode 100644
index 0000000..8551964
--- /dev/null
+++ b/src/main/java/hibernate/cache/jbc/util/NonLockingDataVersion.java
@@ -0,0 +1,65 @@
+/*
+ * 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.jbc.util;
+
+import org.hibernate.cache.jbc.entity.TransactionalAccess;
+import org.jboss.cache.config.Option;
+import org.jboss.cache.optimistic.DataVersion;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * {@link DataVersion} used in regions where no locking should ever occur. This
+ * includes query-caches, update-timestamps caches, collection caches, and
+ * entity caches where the entity is not versioned.
+ * 
+ * @author <a href="brian.stansberry at jboss.com">Brian Stansberry</a>
+ * @version $Revision: 1 $
+ */
+public class NonLockingDataVersion implements DataVersion {
+
+    private static final Logger log = LoggerFactory.getLogger(TransactionalAccess.class);
+
+    private static final long serialVersionUID = 7050722490368630553L;
+
+    public static final DataVersion INSTANCE = new NonLockingDataVersion();
+
+    public static Option getInvocationOption() {
+        Option option = new Option();
+        option.setDataVersion(INSTANCE);
+        return option;
+    }
+
+    public boolean newerThan(DataVersion dataVersion) {
+//        if (dataVersion instanceof DefaultDataVersion) {
+//            log.info("unexpectedly validating against a DefaultDataVersion", new Exception("Just a stack trace"));
+//            return true;
+//        }
+//        else {
+            log.trace("non locking lock check...");
+            return false;
+//        }
+    }
+
+}
diff --git a/src/main/java/hibernate/cache/jbc2/JBossCacheRegionFactory.java b/src/main/java/hibernate/cache/jbc2/JBossCacheRegionFactory.java
new file mode 100644
index 0000000..8121236
--- /dev/null
+++ b/src/main/java/hibernate/cache/jbc2/JBossCacheRegionFactory.java
@@ -0,0 +1,69 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2009, Red Hat, Inc. or third-party contributors as
+ * indicated by the @author tags or express copyright attribution
+ * statements applied by the authors.  All third-party contributions are
+ * distributed under license by Red Hat, Inc.
+ *
+ * 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.jbc2;
+
+import java.util.Properties;
+
+import org.hibernate.cache.jbc.CacheInstanceManager;
+
+/**
+ * Deprecated version of superclass maintained solely for forwards
+ * compatibility.
+ *  
+ * @deprecated use {@link org.hibernate.cache.jbc.JBossCacheRegionFactory}
+ * 
+ * @author Steve Ebersole
+ * @author Brian Stansberry
+ */
+ at Deprecated
+public class JBossCacheRegionFactory extends org.hibernate.cache.jbc.JBossCacheRegionFactory {
+
+    /**
+     * FIXME Per the RegionFactory class Javadoc, this constructor version
+     * should not be necessary.
+     * 
+     * @param props The configuration properties
+     */
+    public JBossCacheRegionFactory(Properties props) {
+        super(props);
+    }
+
+    /**
+     *  Create a new JBossCacheRegionFactory.
+     */
+    public JBossCacheRegionFactory() {
+    	super();
+    }
+
+    /**
+     * Create a new JBossCacheRegionFactory that uses the provided
+     * {@link CacheInstanceManager}.
+     * 
+     * @param cacheInstanceManager The contract for how we get JBC cache instances.
+     */
+    public JBossCacheRegionFactory(CacheInstanceManager cacheInstanceManager) {
+        super(cacheInstanceManager);
+    }
+
+}
diff --git a/src/main/java/hibernate/cache/jbc2/JndiMultiplexedJBossCacheRegionFactory.java b/src/main/java/hibernate/cache/jbc2/JndiMultiplexedJBossCacheRegionFactory.java
new file mode 100644
index 0000000..42f91f2
--- /dev/null
+++ b/src/main/java/hibernate/cache/jbc2/JndiMultiplexedJBossCacheRegionFactory.java
@@ -0,0 +1,58 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2009, Red Hat, Inc. or third-party contributors as
+ * indicated by the @author tags or express copyright attribution
+ * statements applied by the authors.  All third-party contributions are
+ * distributed under license by Red Hat, Inc.
+ *
+ * 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.jbc2;
+
+import java.util.Properties;
+
+/**
+ * Deprecated version of superclass maintained solely for forwards
+ * compatibility.
+ * 
+ * @deprecated use {@link org.hibernate.cache.jbc.JndiMultiplexedJBossCacheRegionFactory}
+ * 
+ * @author Brian Stansberry
+ * @version $Revision$
+ */
+ at Deprecated
+public class JndiMultiplexedJBossCacheRegionFactory extends org.hibernate.cache.jbc.JndiMultiplexedJBossCacheRegionFactory {
+
+    /**
+     * FIXME Per the RegionFactory class Javadoc, this constructor version
+     * should not be necessary.
+     * 
+     * @param props The configuration properties
+     */
+    public JndiMultiplexedJBossCacheRegionFactory(Properties props) {
+        super(props);
+    }
+
+    /**
+     * Create a new MultiplexedJBossCacheRegionFactory.
+     * 
+     */
+    public JndiMultiplexedJBossCacheRegionFactory() {
+        super();
+    }
+
+}
diff --git a/src/main/java/hibernate/cache/jbc2/JndiSharedJBossCacheRegionFactory.java b/src/main/java/hibernate/cache/jbc2/JndiSharedJBossCacheRegionFactory.java
new file mode 100644
index 0000000..7612ac1
--- /dev/null
+++ b/src/main/java/hibernate/cache/jbc2/JndiSharedJBossCacheRegionFactory.java
@@ -0,0 +1,58 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2009, Red Hat, Inc. or third-party contributors as
+ * indicated by the @author tags or express copyright attribution
+ * statements applied by the authors.  All third-party contributions are
+ * distributed under license by Red Hat, Inc.
+ *
+ * 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.jbc2;
+
+import java.util.Properties;
+
+/**
+ * Deprecated version of superclass maintained solely for forwards
+ * compatibility.
+ * 
+ * @deprecated use {@link org.hibernate.cache.jbc.JndiSharedJBossCacheRegionFactory}
+ * 
+ * @author Brian Stansberry
+ * @version $Revision$
+ */
+ at Deprecated
+public class JndiSharedJBossCacheRegionFactory extends org.hibernate.cache.jbc.JndiSharedJBossCacheRegionFactory {
+
+    /**
+     * FIXME Per the RegionFactory class Javadoc, this constructor version
+     * should not be necessary.
+     * 
+     * @param props The configuration properties
+     */
+    public JndiSharedJBossCacheRegionFactory(Properties props) {
+        super(props);
+    }
+
+    /**
+     * Create a new JndiSharedJBossCacheRegionFactory.
+     * 
+     */
+    public JndiSharedJBossCacheRegionFactory() {
+        super();
+    }
+
+}
diff --git a/src/main/java/hibernate/cache/jbc2/MultiplexedJBossCacheRegionFactory.java b/src/main/java/hibernate/cache/jbc2/MultiplexedJBossCacheRegionFactory.java
new file mode 100644
index 0000000..2285dbe
--- /dev/null
+++ b/src/main/java/hibernate/cache/jbc2/MultiplexedJBossCacheRegionFactory.java
@@ -0,0 +1,57 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2009, Red Hat, Inc. or third-party contributors as
+ * indicated by the @author tags or express copyright attribution
+ * statements applied by the authors.  All third-party contributions are
+ * distributed under license by Red Hat, Inc.
+ *
+ * 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.jbc2;
+
+import java.util.Properties;
+
+/**
+ * Deprecated version of superclass maintained solely for forwards
+ * compatibility.
+ * 
+ * @deprecated use {@link org.hibernate.cache.jbc.MultiplexedJBossCacheRegionFactory}
+ * 
+ * @author Brian Stansberry
+ * @version $Revision$
+ */
+public class MultiplexedJBossCacheRegionFactory extends org.hibernate.cache.jbc.MultiplexedJBossCacheRegionFactory {
+
+    /**
+     * FIXME Per the RegionFactory class Javadoc, this constructor version
+     * should not be necessary.
+     * 
+     * @param props The configuration properties
+     */
+    public MultiplexedJBossCacheRegionFactory(Properties props) {
+        super(props);
+    }
+
+    /**
+     * Create a new MultiplexedJBossCacheRegionFactory.
+     * 
+     */
+    public MultiplexedJBossCacheRegionFactory() {
+        super();
+    }
+
+}
diff --git a/src/main/java/hibernate/cache/jbc2/SharedJBossCacheRegionFactory.java b/src/main/java/hibernate/cache/jbc2/SharedJBossCacheRegionFactory.java
new file mode 100644
index 0000000..89bb9a0
--- /dev/null
+++ b/src/main/java/hibernate/cache/jbc2/SharedJBossCacheRegionFactory.java
@@ -0,0 +1,58 @@
+/*
+ * Hibernate, Relational Persistence for Idiomatic Java
+ *
+ * Copyright (c) 2009, Red Hat, Inc. or third-party contributors as
+ * indicated by the @author tags or express copyright attribution
+ * statements applied by the authors.  All third-party contributions are
+ * distributed under license by Red Hat, Inc.
+ *
+ * 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.jbc2;
+
+import java.util.Properties;
+
+/**
+ * Deprecated version of superclass maintained solely for forwards
+ * compatibility.
+ * 
+ * @deprecated use {@link org.hibernate.cache.jbc.SharedJBossCacheRegionFactory}
+ * 
+ * @author Brian Stansberry
+ * @version $Revision$
+ */
+ at Deprecated
+public class SharedJBossCacheRegionFactory extends org.hibernate.cache.jbc.SharedJBossCacheRegionFactory {
+
+    /**
+     * FIXME Per the RegionFactory class Javadoc, this constructor version
+     * should not be necessary.
+     * 
+     * @param props The configuration properties
+     */
+    public SharedJBossCacheRegionFactory(Properties props) {
+        super(props);
+    }
+
+    /**
+     * Create a new SharedJBossCacheRegionFactory.
+     * 
+     */
+    public SharedJBossCacheRegionFactory() {
+        super();
+    }
+
+}
diff --git a/src/main/java/org/hibernate/cache/JndiBoundTreeCacheProvider.java b/src/main/java/org/hibernate/cache/JndiBoundTreeCacheProvider.java
deleted file mode 100644
index 413b70a..0000000
--- a/src/main/java/org/hibernate/cache/JndiBoundTreeCacheProvider.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * 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;
-
-import java.util.Properties;
-
-import javax.transaction.TransactionManager;
-
-import org.hibernate.transaction.TransactionManagerLookup;
-import org.hibernate.transaction.TransactionManagerLookupFactory;
-
-/**
- * Support for JBossCache (TreeCache), where the cache instance is available
- * via JNDI lookup.
- *
- * @author Steve Ebersole
- */
-public class JndiBoundTreeCacheProvider extends AbstractJndiBoundCacheProvider {
-
-	private TransactionManager transactionManager;
-
-	/**
-	 * Construct a Cache representing the "region" within in the underlying cache
-	 * provider.
-	 *
-	 * @param regionName the name of the cache region
-	 * @param properties configuration settings
-	 *
-	 * @throws CacheException
-	 */
-	public Cache buildCache(String regionName, Properties properties) throws CacheException {
-		return new TreeCache( getTreeCacheInstance(), regionName, transactionManager );
-	}
-
-	public void prepare(Properties properties) throws CacheException {
-		TransactionManagerLookup transactionManagerLookup = TransactionManagerLookupFactory.getTransactionManagerLookup(properties);
-		if (transactionManagerLookup!=null) {
-			transactionManager = transactionManagerLookup.getTransactionManager(properties);
-		}
-	}
-	/**
-	 * Generate a timestamp
-	 */
-	public long nextTimestamp() {
-		return System.currentTimeMillis() / 100;
-	}
-
-	/**
-	 * By default, should minimal-puts mode be enabled when using this cache.
-	 * <p/>
-	 * Since TreeCache is a clusterable cache and we are only getting a
-	 * reference the instance from JNDI, safest to assume a clustered
-	 * setup and return true here.
-	 *
-	 * @return True.
-	 */
-	public boolean isMinimalPutsEnabledByDefault() {
-		return true;
-	}
-
-	public org.jboss.cache.TreeCache getTreeCacheInstance() {
-		return ( org.jboss.cache.TreeCache ) super.getCache();
-	}
-}
diff --git a/src/main/java/org/hibernate/cache/OptimisticTreeCache.java b/src/main/java/org/hibernate/cache/OptimisticTreeCache.java
deleted file mode 100644
index bfac53f..0000000
--- a/src/main/java/org/hibernate/cache/OptimisticTreeCache.java
+++ /dev/null
@@ -1,351 +0,0 @@
-/*
- * 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;
-
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Set;
-import java.util.Comparator;
-
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.jboss.cache.Fqn;
-import org.jboss.cache.optimistic.DataVersion;
-import org.jboss.cache.config.Option;
-import org.jboss.cache.lock.TimeoutException;
-
-/**
- * Represents a particular region within the given JBossCache TreeCache
- * utilizing TreeCache's optimistic locking capabilities.
- *
- * @see OptimisticTreeCacheProvider for more details
- *
- * @author Steve Ebersole
- */
-public class OptimisticTreeCache implements OptimisticCache, TransactionAwareCache {
-
-	// todo : eventually merge this with TreeCache and just add optional opt-lock support there.
-
-	private static final Logger log = LoggerFactory.getLogger( OptimisticTreeCache.class);
-
-	private static final String ITEM = "item";
-
-	private org.jboss.cache.TreeCache cache;
-	private final String regionName;
-	private final Fqn regionFqn;
-	private OptimisticCacheSource source;
-
-	public OptimisticTreeCache(org.jboss.cache.TreeCache cache, String regionName)
-	throws CacheException {
-		this.cache = cache;
-		this.regionName = regionName;
-		this.regionFqn = Fqn.fromString( regionName.replace( '.', '/' ) );
-	}
-
-
-	// OptimisticCache impl ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-	public void setSource(OptimisticCacheSource source) {
-		this.source = source;
-	}
-
-	public void writeInsert(Object key, Object value, Object currentVersion) {
-		writeUpdate( key, value, currentVersion, null );
-	}
-
-	public void writeUpdate(Object key, Object value, Object currentVersion, Object previousVersion) {
-		try {
-			Option option = new Option();
-			DataVersion dv = ( source != null && source.isVersioned() )
-			                 ? new DataVersionAdapter( currentVersion, previousVersion, source.getVersionComparator(), source.toString() )
-			                 : NonLockingDataVersion.INSTANCE;
-			option.setDataVersion( dv );
-			cache.put( new Fqn( regionFqn, key ), ITEM, value, option );
-		}
-		catch ( Exception e ) {
-			throw new CacheException( e );
-		}
-	}
-
-	public void writeLoad(Object key, Object value, Object currentVersion) {
-		try {
-			Option option = new Option();
-			option.setFailSilently( true );
-			option.setDataVersion( NonLockingDataVersion.INSTANCE );
-			cache.remove( new Fqn( regionFqn, key ), "ITEM", option );
-
-			option = new Option();
-			option.setFailSilently( true );
-			DataVersion dv = ( source != null && source.isVersioned() )
-			                 ? new DataVersionAdapter( currentVersion, currentVersion, source.getVersionComparator(), source.toString() )
-			                 : NonLockingDataVersion.INSTANCE;
-			option.setDataVersion( dv );
-			cache.put( new Fqn( regionFqn, key ), ITEM, value, option );
-		}
-		catch (Exception e) {
-			throw new CacheException(e);
-		}
-	}
-
-
-	// Cache impl ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-	public Object get(Object key) throws CacheException {
-		try {
-			Option option = new Option();
-			option.setFailSilently( true );
-//			option.setDataVersion( NonLockingDataVersion.INSTANCE );
-			return cache.get( new Fqn( regionFqn, key ), ITEM, option );
-		}
-		catch (Exception e) {
-			throw new CacheException(e);
-		}
-	}
-
-	public Object read(Object key) throws CacheException {
-		try {
-			return cache.get( new Fqn( regionFqn, key ), ITEM );
-		}
-		catch (Exception e) {
-			throw new CacheException(e);
-		}
-	}
-
-	public void update(Object key, Object value) throws CacheException {
-		try {
-			Option option = new Option();
-			option.setDataVersion( NonLockingDataVersion.INSTANCE );
-			cache.put( new Fqn( regionFqn, key ), ITEM, value, option );
-		}
-		catch (Exception e) {
-			throw new CacheException(e);
-		}
-	}
-
-	public void put(Object key, Object value) throws CacheException {
-		try {
-			log.trace( "performing put() into region [" + regionName + "]" );
-			// do the put outside the scope of the JTA txn
-			Option option = new Option();
-			option.setFailSilently( true );
-			option.setDataVersion( NonLockingDataVersion.INSTANCE );
-			cache.put( new Fqn( regionFqn, key ), ITEM, value, option );
-		}
-		catch (TimeoutException te) {
-			//ignore!
-			log.debug("ignoring write lock acquisition failure");
-		}
-		catch (Exception e) {
-			throw new CacheException(e);
-		}
-	}
-
-	public void remove(Object key) throws CacheException {
-		try {
-			// tree cache in optimistic mode seems to have as very difficult
-			// time with remove calls on non-existent nodes (NPEs)...
-			if ( cache.get( new Fqn( regionFqn, key ), ITEM ) != null ) {
-				Option option = new Option();
-				option.setDataVersion( NonLockingDataVersion.INSTANCE );
-				cache.remove( new Fqn( regionFqn, key ), option );
-			}
-			else {
-				log.trace( "skipping remove() call as the underlying node did not seem to exist" );
-			}
-		}
-		catch (Exception e) {
-			throw new CacheException(e);
-		}
-	}
-
-	public void clear() throws CacheException {
-		try {
-			Option option = new Option();
-			option.setDataVersion( NonLockingDataVersion.INSTANCE );
-			cache.remove( regionFqn, option );
-		}
-		catch (Exception e) {
-			throw new CacheException(e);
-		}
-	}
-
-	public void destroy() throws CacheException {
-		try {
-			Option option = new Option();
-			option.setCacheModeLocal( true );
-			option.setFailSilently( true );
-			option.setDataVersion( NonLockingDataVersion.INSTANCE );
-			cache.remove( regionFqn, option );
-		}
-		catch( Exception e ) {
-			throw new CacheException( e );
-		}
-	}
-
-	public void lock(Object key) throws CacheException {
-		throw new UnsupportedOperationException( "TreeCache is a fully transactional cache" + regionName );
-	}
-
-	public void unlock(Object key) throws CacheException {
-		throw new UnsupportedOperationException( "TreeCache is a fully transactional cache: " + regionName );
-	}
-
-	public long nextTimestamp() {
-		return System.currentTimeMillis() / 100;
-	}
-
-	public int getTimeout() {
-		return 600; //60 seconds
-	}
-
-	public String getRegionName() {
-		return regionName;
-	}
-
-	public long getSizeInMemory() {
-		return -1;
-	}
-
-	public long getElementCountInMemory() {
-		try {
-			Set children = cache.getChildrenNames( regionFqn );
-			return children == null ? 0 : children.size();
-		}
-		catch (Exception e) {
-			throw new CacheException(e);
-		}
-	}
-
-	public long getElementCountOnDisk() {
-		return 0;
-	}
-
-	public Map toMap() {
-		try {
-			Map result = new HashMap();
-			Set childrenNames = cache.getChildrenNames( regionFqn );
-			if (childrenNames != null) {
-				Iterator iter = childrenNames.iterator();
-				while ( iter.hasNext() ) {
-					Object key = iter.next();
-					result.put(
-							key,
-					        cache.get( new Fqn( regionFqn, key ), ITEM )
-						);
-				}
-			}
-			return result;
-		}
-		catch (Exception e) {
-			throw new CacheException(e);
-		}
-	}
-
-	public String toString() {
-		return "OptimisticTreeCache(" + regionName + ')';
-	}
-
-	public static class DataVersionAdapter implements DataVersion {
-		private final Object currentVersion;
-		private final Object previousVersion;
-		private final Comparator versionComparator;
-		private final String sourceIdentifer;
-
-		public DataVersionAdapter(Object currentVersion, Object previousVersion, Comparator versionComparator, String sourceIdentifer) {
-			this.currentVersion = currentVersion;
-			this.previousVersion = previousVersion;
-			this.versionComparator = versionComparator;
-			this.sourceIdentifer = sourceIdentifer;
-			log.trace( "created " + this );
-		}
-
-		/**
-		 * newerThan() call is dispatched against the DataVersion currently
-		 * associated with the node; the passed dataVersion param is the
-		 * DataVersion associated with the data we are trying to put into
-		 * the node.
-		 * <p/>
-		 * we are expected to return true in the case where we (the current
-		 * node DataVersion) are newer that then incoming value.  Returning
-		 * true here essentially means that a optimistic lock failure has
-		 * occured (because conversely, the value we are trying to put into
-		 * the node is "older than" the value already there...)
-		 */
-		public boolean newerThan(DataVersion dataVersion) {
-			log.trace( "checking [" + this + "] against [" + dataVersion + "]" );
-			if ( dataVersion instanceof CircumventChecksDataVersion ) {
-				log.trace( "skipping lock checks..." );
-				return false;
-			}
-			else if ( dataVersion instanceof NonLockingDataVersion ) {
-				// can happen because of the multiple ways Cache.remove()
-				// can be invoked :(
-				log.trace( "skipping lock checks..." );
-				return false;
-			}
-			DataVersionAdapter other = ( DataVersionAdapter ) dataVersion;
-			if ( other.previousVersion == null ) {
-				log.warn( "Unexpected optimistic lock check on inserting data" );
-				// work around the "feature" where tree cache is validating the
-				// inserted node during the next transaction.  no idea...
-				if ( this == dataVersion ) {
-					log.trace( "skipping lock checks due to same DV instance" );
-					return false;
-				}
-			}
-			return versionComparator.compare( currentVersion, other.previousVersion ) >= 1;
-		}
-
-		public String toString() {
-			return super.toString() + " [current=" + currentVersion + ", previous=" + previousVersion + ", src=" + sourceIdentifer + "]";
-		}
-	}
-
-	/**
-	 * Used in regions where no locking should ever occur.  This includes query-caches,
-	 * update-timestamps caches, collection caches, and entity caches where the entity
-	 * is not versioned.
-	 */
-	public static class NonLockingDataVersion implements DataVersion {
-		public static final DataVersion INSTANCE = new NonLockingDataVersion();
-		public boolean newerThan(DataVersion dataVersion) {
-			log.trace( "non locking lock check...");
-			return false;
-		}
-	}
-
-	/**
-	 * Used to signal to a DataVersionAdapter to simply not perform any checks.  This
-	 * is currently needed for proper handling of remove() calls for entity cache regions
-	 * (we do not know the version info...).
-	 */
-	public static class CircumventChecksDataVersion implements DataVersion {
-		public static final DataVersion INSTANCE = new CircumventChecksDataVersion();
-		public boolean newerThan(DataVersion dataVersion) {
-			throw new CacheException( "optimistic locking checks should never happen on CircumventChecksDataVersion" );
-		}
-	}
-}
diff --git a/src/main/java/org/hibernate/cache/OptimisticTreeCacheProvider.java b/src/main/java/org/hibernate/cache/OptimisticTreeCacheProvider.java
deleted file mode 100644
index 1da42c2..0000000
--- a/src/main/java/org/hibernate/cache/OptimisticTreeCacheProvider.java
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * 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;
-
-import java.util.Properties;
-import javax.transaction.TransactionManager;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.hibernate.cfg.Environment;
-import org.hibernate.transaction.TransactionManagerLookup;
-import org.hibernate.transaction.TransactionManagerLookupFactory;
-import org.jboss.cache.PropertyConfigurator;
-
-/**
- * Support for a standalone JBossCache TreeCache instance utilizing TreeCache's
- * optimistic locking capabilities.  This capability was added in JBossCache
- * version 1.3.0; as such this provider will only work with that version or
- * higher.
- * <p/>
- * The TreeCache instance is configured via a local config resource.  The
- * resource to be used for configuration can be controlled by specifying a value
- * for the {@link #CONFIG_RESOURCE} config property.
- *
- * @author Steve Ebersole
- */
-public class OptimisticTreeCacheProvider implements CacheProvider {
-
-	/**
-	 * @deprecated use {@link Environment#CACHE_PROVIDER_CONFIG}
-	 */
-	public static final String CONFIG_RESOURCE = "hibernate.cache.opt_tree_cache.config";
-	public static final String DEFAULT_CONFIG = "treecache-optimistic.xml";
-
-	private static final String NODE_LOCKING_SCHEME = "OPTIMISTIC";
-	private static final Logger log = LoggerFactory.getLogger( OptimisticTreeCacheProvider.class );
-
-	private org.jboss.cache.TreeCache cache;
-
-	/**
-	 * Construct and configure the Cache representation of a named cache region.
-	 *
-	 * @param regionName the name of the cache region
-	 * @param properties configuration settings
-	 * @return The Cache representation of the named cache region.
-	 * @throws CacheException
-	 *          Indicates an error building the cache region.
-	 */
-	public Cache buildCache(String regionName, Properties properties) throws CacheException {
-		return new OptimisticTreeCache( cache, regionName );
-	}
-
-	public long nextTimestamp() {
-		return System.currentTimeMillis() / 100;
-	}
-
-	/**
-	 * Prepare the underlying JBossCache TreeCache instance.
-	 *
-	 * @param properties All current config settings.
-	 * @throws CacheException
-	 *          Indicates a problem preparing cache for use.
-	 */
-	public void start(Properties properties) {
-		String resource = properties.getProperty( Environment.CACHE_PROVIDER_CONFIG );
-		if (resource == null) {
-			resource = properties.getProperty( CONFIG_RESOURCE );
-		}
-		if ( resource == null ) {
-			resource = DEFAULT_CONFIG;
-		}
-		log.debug( "Configuring TreeCache from resource [" + resource + "]" );
-		try {
-			cache = new org.jboss.cache.TreeCache();
-			PropertyConfigurator config = new PropertyConfigurator();
-			config.configure( cache, resource );
-			TransactionManagerLookup transactionManagerLookup =
-					TransactionManagerLookupFactory.getTransactionManagerLookup( properties );
-			if ( transactionManagerLookup == null ) {
-				throw new CacheException(
-						"JBossCache only supports optimisitc locking with a configured " +
-						"TransactionManagerLookup (" + Environment.TRANSACTION_MANAGER_STRATEGY + ")"
-				);
-			}
-			cache.setTransactionManagerLookup(
-					new TransactionManagerLookupAdaptor(
-							transactionManagerLookup,
-							properties
-					)
-			);
-			if ( ! NODE_LOCKING_SCHEME.equalsIgnoreCase( cache.getNodeLockingScheme() ) ) {
-				log.info( "Overriding node-locking-scheme to : " + NODE_LOCKING_SCHEME );
-				cache.setNodeLockingScheme( NODE_LOCKING_SCHEME );
-			}
-			cache.start();
-		}
-		catch ( Exception e ) {
-			throw new CacheException( e );
-		}
-	}
-
-	public void stop() {
-		if ( cache != null ) {
-			cache.stop();
-			cache.destroy();
-			cache = null;
-		}
-	}
-
-	public boolean isMinimalPutsEnabledByDefault() {
-		return true;
-	}
-
-	static final class TransactionManagerLookupAdaptor implements org.jboss.cache.TransactionManagerLookup {
-		private final TransactionManagerLookup tml;
-		private final Properties props;
-
-		TransactionManagerLookupAdaptor(TransactionManagerLookup tml, Properties props) {
-			this.tml = tml;
-			this.props = props;
-		}
-
-		public TransactionManager getTransactionManager() throws Exception {
-			return tml.getTransactionManager( props );
-		}
-	}
-
-	public org.jboss.cache.TreeCache getUnderlyingCache() {
-		return cache;
-	}
-}
diff --git a/src/main/java/org/hibernate/cache/TreeCache.java b/src/main/java/org/hibernate/cache/TreeCache.java
deleted file mode 100644
index 581ad65..0000000
--- a/src/main/java/org/hibernate/cache/TreeCache.java
+++ /dev/null
@@ -1,227 +0,0 @@
-/*
- * 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;
-
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Set;
-
-import javax.transaction.SystemException;
-import javax.transaction.Transaction;
-import javax.transaction.TransactionManager;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.jboss.cache.Fqn;
-import org.jboss.cache.lock.TimeoutException;
-
-/**
- * Represents a particular region within the given JBossCache TreeCache.
- *
- * @author Gavin King
- */
-public class TreeCache implements Cache, TransactionAwareCache {
-	
-	private static final Logger log = LoggerFactory.getLogger(TreeCache.class);
-
-	private static final String ITEM = "item";
-
-	private org.jboss.cache.TreeCache cache;
-	private final String regionName;
-	private final Fqn regionFqn;
-	private final TransactionManager transactionManager;
-
-	public TreeCache(org.jboss.cache.TreeCache cache, String regionName, TransactionManager transactionManager) 
-	throws CacheException {
-		this.cache = cache;
-		this.regionName = regionName;
-		this.regionFqn = Fqn.fromString( regionName.replace( '.', '/' ) );
-		this.transactionManager = transactionManager;
-	}
-
-	public Object get(Object key) throws CacheException {
-		Transaction tx = suspend();
-		try {
-			return read(key);
-		}
-		finally {
-			resume( tx );
-		}
-	}
-	
-	public Object read(Object key) throws CacheException {
-		try {
-			return cache.get( new Fqn( regionFqn, key ), ITEM );
-		}
-		catch (Exception e) {
-			throw new CacheException(e);
-		}
-	}
-
-	public void update(Object key, Object value) throws CacheException {
-		try {
-			cache.put( new Fqn( regionFqn, key ), ITEM, value );
-		}
-		catch (Exception e) {
-			throw new CacheException(e);
-		}
-	}
-
-	public void put(Object key, Object value) throws CacheException {
-		Transaction tx = suspend();
-		try {
-			//do the failfast put outside the scope of the JTA txn
-			cache.putFailFast( new Fqn( regionFqn, key ), ITEM, value, 0 );
-		}
-		catch (TimeoutException te) {
-			//ignore!
-			log.debug("ignoring write lock acquisition failure");
-		}
-		catch (Exception e) {
-			throw new CacheException(e);
-		}
-		finally {
-			resume( tx );
-		}
-	}
-
-	private void resume(Transaction tx) {
-		try {
-			if (tx!=null) transactionManager.resume(tx);
-		}
-		catch (Exception e) {
-			throw new CacheException("Could not resume transaction", e);
-		}
-	}
-
-	private 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;
-	}
-
-	public void remove(Object key) throws CacheException {
-		try {
-			cache.remove( new Fqn( regionFqn, key ) );
-		}
-		catch (Exception e) {
-			throw new CacheException(e);
-		}
-	}
-
-	public void clear() throws CacheException {
-		try {
-			cache.remove( regionFqn );
-		}
-		catch (Exception e) {
-			throw new CacheException(e);
-		}
-	}
-
-	public void destroy() throws CacheException {
-		try {
-			// NOTE : evict() operates locally only (i.e., does not propogate
-			// to any other nodes in the potential cluster).  This is
-			// exactly what is needed when we destroy() here; destroy() is used
-			// as part of the process of shutting down a SessionFactory; thus
-			// these removals should not be propogated
-			cache.evict( regionFqn );
-		}
-		catch( Exception e ) {
-			throw new CacheException( e );
-		}
-	}
-
-	public void lock(Object key) throws CacheException {
-		throw new UnsupportedOperationException( "TreeCache is a fully transactional cache" + regionName );
-	}
-
-	public void unlock(Object key) throws CacheException {
-		throw new UnsupportedOperationException( "TreeCache is a fully transactional cache: " + regionName );
-	}
-
-	public long nextTimestamp() {
-		return System.currentTimeMillis() / 100;
-	}
-
-	public int getTimeout() {
-		return 600; //60 seconds
-	}
-
-	public String getRegionName() {
-		return regionName;
-	}
-
-	public long getSizeInMemory() {
-		return -1;
-	}
-
-	public long getElementCountInMemory() {
-		try {
-			Set children = cache.getChildrenNames( regionFqn );
-			return children == null ? 0 : children.size();
-		}
-		catch (Exception e) {
-			throw new CacheException(e);
-		}
-	}
-
-	public long getElementCountOnDisk() {
-		return 0;
-	}
-	
-	public Map toMap() {
-		try {
-			Map result = new HashMap();
-			Set childrenNames = cache.getChildrenNames( regionFqn );
-			if (childrenNames != null) {
-				Iterator iter = childrenNames.iterator();
-				while ( iter.hasNext() ) {
-					Object key = iter.next();
-					result.put( 
-							key, 
-							cache.get( new Fqn( regionFqn, key ), ITEM )
-						);
-				}
-			}
-			return result;
-		}
-		catch (Exception e) {
-			throw new CacheException(e);
-		}
-	}
-	
-	public String toString() {
-		return "TreeCache(" + regionName + ')';
-	}
-	
-}
diff --git a/src/main/java/org/hibernate/cache/TreeCacheProvider.java b/src/main/java/org/hibernate/cache/TreeCacheProvider.java
deleted file mode 100644
index 8d8ae7b..0000000
--- a/src/main/java/org/hibernate/cache/TreeCacheProvider.java
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * 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;
-
-import java.util.Properties;
-import javax.transaction.TransactionManager;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.hibernate.transaction.TransactionManagerLookup;
-import org.hibernate.transaction.TransactionManagerLookupFactory;
-import org.hibernate.cfg.Environment;
-import org.jboss.cache.PropertyConfigurator;
-
-/**
- * Support for a standalone JBossCache (TreeCache) instance.  The JBossCache is configured
- * via a local config resource.
- *
- * @author Gavin King
- */
-public class TreeCacheProvider implements CacheProvider {
-
-	/**
-	 * @deprecated use {@link org.hibernate.cfg.Environment#CACHE_PROVIDER_CONFIG}
-	 */
-	public static final String CONFIG_RESOURCE = "hibernate.cache.tree_cache.config";
-	public static final String DEFAULT_CONFIG = "treecache-optimistic.xml";
-
-	private static final Logger log = LoggerFactory.getLogger( TreeCacheProvider.class );
-
-	private org.jboss.cache.TreeCache cache;
-	private TransactionManager transactionManager;
-
-	/**
-	 * Construct and configure the Cache representation of a named cache region.
-	 *
-	 * @param regionName the name of the cache region
-	 * @param properties configuration settings
-	 * @return The Cache representation of the named cache region.
-	 * @throws CacheException Indicates an error building the cache region.
-	 */
-	public Cache buildCache(String regionName, Properties properties) throws CacheException {
-		return new TreeCache(cache, regionName, transactionManager);
-	}
-
-	public long nextTimestamp() {
-		return System.currentTimeMillis() / 100;
-	}
-
-	/**
-	 * Prepare the underlying JBossCache TreeCache instance.
-	 *
-	 * @param properties All current config settings.
-	 *
-	 * @throws CacheException Indicates a problem preparing cache for use.
-	 */
-	public void start(Properties properties) {
-		String resource = properties.getProperty( Environment.CACHE_PROVIDER_CONFIG );
-
-		if ( resource == null ) {
-			resource = properties.getProperty( CONFIG_RESOURCE );
-		}
-		if ( resource == null ) {
-			resource = DEFAULT_CONFIG;
-		}
-		log.debug( "Configuring TreeCache from resource [" + resource + "]" );
-		try {
-			cache = new org.jboss.cache.TreeCache();
-			PropertyConfigurator config = new PropertyConfigurator();
-			config.configure( cache, resource );
-			TransactionManagerLookup transactionManagerLookup = TransactionManagerLookupFactory.getTransactionManagerLookup(properties);
-			if (transactionManagerLookup!=null) {
-				cache.setTransactionManagerLookup( new TransactionManagerLookupAdaptor(transactionManagerLookup, properties) );
-				transactionManager = transactionManagerLookup.getTransactionManager(properties);
-			}
-			cache.start();
-		}
-		catch (Exception e) {
-			throw new CacheException(e);
-		}
-	}
-
-	public void stop() {
-		if (cache!=null) {
-			cache.stop();
-			cache.destroy();
-			cache=null;
-		}
-	}
-	
-	public boolean isMinimalPutsEnabledByDefault() {
-		return true;
-	}
-
-	static final class TransactionManagerLookupAdaptor implements org.jboss.cache.TransactionManagerLookup {
-		private final TransactionManagerLookup tml;
-		private final Properties props;
-		TransactionManagerLookupAdaptor(TransactionManagerLookup tml, Properties props) {
-			this.tml=tml;
-			this.props=props;
-		}
-		public TransactionManager getTransactionManager() throws Exception {
-			return tml.getTransactionManager(props);
-		}
-	}
-
-	public org.jboss.cache.TreeCache getUnderlyingCache() {
-		return cache;
-	}
-}
diff --git a/src/test/java/org/hibernate/cache/OptimisticTreeCacheTest.java b/src/test/java/org/hibernate/cache/OptimisticTreeCacheTest.java
deleted file mode 100644
index a9c3b07..0000000
--- a/src/test/java/org/hibernate/cache/OptimisticTreeCacheTest.java
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * 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;
-
-import junit.framework.Test;
-import junit.framework.Assert;
-import org.jboss.cache.Fqn;
-import org.jboss.cache.TreeCache;
-import org.jboss.cache.config.Option;
-import org.jboss.cache.optimistic.DataVersion;
-
-import org.hibernate.cache.impl.bridge.RegionFactoryCacheProviderBridge;
-import org.hibernate.cfg.Environment;
-import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
-import org.hibernate.test.cache.BaseCacheProviderTestCase;
-import org.hibernate.test.tm.SimpleJtaTransactionManagerImpl;
-
-/**
- * @author Steve Ebersole
- */
-public class OptimisticTreeCacheTest extends BaseCacheProviderTestCase {
-	public OptimisticTreeCacheTest(String x) {
-		super( x );
-	}
-
-	public static Test suite() {
-		return new FunctionalTestClassTestSuite( OptimisticTreeCacheTest.class );
-	}
-
-	public String getCacheConcurrencyStrategy() {
-		return "transactional";
-	}
-
-	protected Class getCacheProvider() {
-		return OptimisticTreeCacheProvider.class;
-	}
-
-	protected String getConfigResourceKey() {
-		return Environment.CACHE_PROVIDER_CONFIG;
-	}
-
-	protected String getConfigResourceLocation() {
-		return "treecache-optimistic.xml";
-	}
-
-	protected boolean useTransactionManager() {
-		return true;
-	}
-
-	public void testCacheLevelStaleWritesFail() throws Throwable {
-		Fqn fqn = new Fqn( "whatever" );
-		TreeCache treeCache = ( ( OptimisticTreeCacheProvider ) ( ( RegionFactoryCacheProviderBridge ) sfi().getSettings().getRegionFactory() ).getCacheProvider() ).getUnderlyingCache();
-
-		Long long1 = new Long(1);
-		Long long2 = new Long(2);
-
-		try {
-			System.out.println( "****************************************************************" );
-			SimpleJtaTransactionManagerImpl.getInstance().begin();
-			treeCache.put( fqn, "ITEM", long1, ManualDataVersion.gen( 1 ) );
-			SimpleJtaTransactionManagerImpl.getInstance().commit();
-
-			System.out.println( "****************************************************************" );
-			SimpleJtaTransactionManagerImpl.getInstance().begin();
-			treeCache.put( fqn, "ITEM", long2, ManualDataVersion.gen( 2 ) );
-			SimpleJtaTransactionManagerImpl.getInstance().commit();
-
-			try {
-				System.out.println( "****************************************************************" );
-				SimpleJtaTransactionManagerImpl.getInstance().begin();
-				treeCache.put( fqn, "ITEM", long1, ManualDataVersion.gen( 1 ) );
-				SimpleJtaTransactionManagerImpl.getInstance().commit();
-				Assert.fail( "stale write allowed" );
-			}
-			catch( Throwable ignore ) {
-				// expected behavior
-				SimpleJtaTransactionManagerImpl.getInstance().rollback();
-			}
-
-			Long current = ( Long ) treeCache.get( fqn, "ITEM" );
-			Assert.assertEquals( "unexpected current value", 2, current.longValue() );
-		}
-		finally {
-			try {
-				treeCache.remove( fqn, "ITEM" );
-			}
-			catch( Throwable ignore ) {
-			}
-		}
-	}
-
-	private static class ManualDataVersion implements DataVersion {
-		private final int version;
-
-		public ManualDataVersion(int version) {
-			this.version = version;
-		}
-
-		public boolean newerThan(DataVersion dataVersion) {
-			return this.version > ( ( ManualDataVersion ) dataVersion ).version;
-		}
-
-		public static Option gen(int version) {
-			ManualDataVersion mdv = new ManualDataVersion( version );
-			Option option = new Option();
-			option.setDataVersion( mdv );
-			return option;
-		}
-	}
-}
diff --git a/src/test/resources/hibernate.properties b/src/test/resources/hibernate.properties
deleted file mode 100644
index f0db52e..0000000
--- a/src/test/resources/hibernate.properties
+++ /dev/null
@@ -1,32 +0,0 @@
-################################################################################
-# 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                                                  #
-################################################################################
-hibernate.dialect org.hibernate.dialect.HSQLDialect
-hibernate.connection.driver_class org.hsqldb.jdbcDriver
-hibernate.connection.url jdbc:hsqldb:mem:/test
-hibernate.connection.username sa
-hibernate.connection.password
-
-hibernate.connection.pool_size 5
-
-hibernate.cache.region_prefix hibernate.test
diff --git a/src/test/resources/log4j.properties b/src/test/resources/log4j.properties
deleted file mode 100644
index d63d595..0000000
--- a/src/test/resources/log4j.properties
+++ /dev/null
@@ -1,32 +0,0 @@
-################################################################################
-# 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                                                  #
-################################################################################
-log4j.appender.stdout=org.apache.log4j.ConsoleAppender
-log4j.appender.stdout.Target=System.out
-log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
-log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
-
-
-log4j.rootLogger=info, stdout
-
-log4j.logger.org.hibernate.test=info
\ No newline at end of file
diff --git a/src/test/resources/treecache-optimistic.xml b/src/test/resources/treecache-optimistic.xml
deleted file mode 100644
index d8a0d2f..0000000
--- a/src/test/resources/treecache-optimistic.xml
+++ /dev/null
@@ -1,171 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<!--
-  ~ 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
-  -->
-
-<!-- ===================================================================== -->
-<!--                                                                       -->
-<!--  Sample TreeCache Service Configuration                               -->
-<!--  Recommended for use as Hibernate's 2nd Level Cache                   -->
-<!--  For use with JBossCache >= 1.3.0 ONLY!!!                             -->
-<!--                                                                       -->
-<!-- ===================================================================== -->
-
-<server>
-
-    <classpath codebase="./lib" archives="jboss-cache.jar, jgroups.jar"/>
-
-
-    <!-- ==================================================================== -->
-    <!-- Defines TreeCache configuration                                      -->
-    <!-- ==================================================================== -->
-
-    <mbean code="org.jboss.cache.TreeCache"
-        name="jboss.cache:service=TreeCache">
-
-        <depends>jboss:service=Naming</depends>
-        <depends>jboss:service=TransactionManager</depends>
-
-        <!--
-            Configure the TransactionManager : no matter since Hibernate will plug in
-            an "adapter" to its own TransactionManagerLookup strategy here
-        -->
-        <attribute name="TransactionManagerLookupClass">org.jboss.cache.GenericTransactionManagerLookup</attribute>
-
-
-        <!--
-            Node locking scheme:
-                OPTIMISTIC
-                PESSIMISTIC (default)
-        -->
-        <attribute name="NodeLockingScheme">OPTIMISTIC</attribute>
-
-        <!--
-            Note that this attribute is IGNORED if your NodeLockingScheme above is OPTIMISTIC.
-
-            Isolation level : SERIALIZABLE
-                              REPEATABLE_READ (default)
-                              READ_COMMITTED
-                              READ_UNCOMMITTED
-                              NONE
-        -->
-        <attribute name="IsolationLevel">REPEATABLE_READ</attribute>
-
-        <!--
-             Valid modes are LOCAL
-                             REPL_ASYNC
-                             REPL_SYNC
-                             INVALIDATION_ASYNC
-                             INVALIDATION_SYNC
-
-             INVALIDATION_ASYNC is highly recommended as the mode for use
-             with clustered second-level caches.
-        -->
-        <attribute name="CacheMode">LOCAL</attribute>
-
-        <!--
-        Just used for async repl: use a replication queue
-        -->
-        <attribute name="UseReplQueue">false</attribute>
-
-        <!--
-            Replication interval for replication queue (in ms)
-        -->
-        <attribute name="ReplQueueInterval">0</attribute>
-
-        <!--
-            Max number of elements which trigger replication
-        -->
-        <attribute name="ReplQueueMaxElements">0</attribute>
-
-        <!-- Name of cluster. Needs to be the same for all clusters, in order
-             to find each other
-        -->
-        <attribute name="ClusterName">TreeCache-Cluster</attribute>
-
-        <!-- JGroups protocol stack properties. Can also be a URL,
-             e.g. file:/home/bela/default.xml
-           <attribute name="ClusterProperties"></attribute>
-        -->
-
-        <attribute name="ClusterConfig">
-            <config>
-                <!-- UDP: if you have a multihomed machine,
-                set the bind_addr attribute to the appropriate NIC IP address -->
-                <!-- UDP: On Windows machines, because of the media sense feature
-                 being broken with multicast (even after disabling media sense)
-                 set the loopback attribute to true -->
-                <UDP mcast_addr="228.1.2.3" mcast_port="48866"
-                    ip_ttl="64" ip_mcast="true"
-                    mcast_send_buf_size="150000" mcast_recv_buf_size="80000"
-                    ucast_send_buf_size="150000" ucast_recv_buf_size="80000"
-                    loopback="false"/>
-                <PING timeout="2000" num_initial_members="3"
-                    up_thread="false" down_thread="false"/>
-                <MERGE2 min_interval="10000" max_interval="20000"/>
-                <!--        <FD shun="true" up_thread="true" down_thread="true" />-->
-                <FD_SOCK/>
-                <VERIFY_SUSPECT timeout="1500"
-                    up_thread="false" down_thread="false"/>
-                <pbcast.NAKACK gc_lag="50" retransmit_timeout="600,1200,2400,4800"
-                    max_xmit_size="8192" up_thread="false" down_thread="false"/>
-                <UNICAST timeout="600,1200,2400" window_size="100" min_threshold="10"
-                    down_thread="false"/>
-                <pbcast.STABLE desired_avg_gossip="20000"
-                    up_thread="false" down_thread="false"/>
-                <FRAG frag_size="8192"
-                    down_thread="false" up_thread="false"/>
-                <pbcast.GMS join_timeout="5000" join_retry_timeout="2000"
-                    shun="true" print_local_addr="true"/>
-                <pbcast.STATE_TRANSFER up_thread="true" down_thread="true"/>
-            </config>
-        </attribute>
-
-        <!--
-         Whether or not to fetch state on joining a cluster
-         NOTE this used to be called FetchStateOnStartup and has been renamed to be more descriptive.
-        -->
-        <attribute name="FetchInMemoryState">false</attribute>
-
-        <!--
-            Number of milliseconds to wait until all responses for a
-            synchronous call have been received.
-        -->
-        <attribute name="SyncReplTimeout">20000</attribute>
-
-        <!-- Max number of milliseconds to wait for a lock acquisition -->
-        <attribute name="LockAcquisitionTimeout">15000</attribute>
-
-
-        <!-- Name of the eviction policy class. -->
-        <attribute name="EvictionPolicyClass"></attribute>
-
-       <!--
-          Indicate whether to use marshalling or not. Set this to true if you are running under a scoped
-          class loader, e.g., inside an application server. Default is "false".
-       -->
-       <attribute name="UseMarshalling">false</attribute>
-
-    </mbean>
-</server>
diff --git a/src/test/resources/treecache-pessimistic.xml b/src/test/resources/treecache-pessimistic.xml
deleted file mode 100644
index 3ae0140..0000000
--- a/src/test/resources/treecache-pessimistic.xml
+++ /dev/null
@@ -1,143 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<!--
-  ~ 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
-  -->
-
-<!-- ===================================================================== -->
-<!--                                                                       -->
-<!--  Sample TreeCache Service Configuration                               -->
-<!--                                                                       -->
-<!-- ===================================================================== -->
-
-<server>
-
-    <classpath codebase="./lib" archives="jboss-cache.jar, jgroups.jar"/>
-
-
-    <!-- ==================================================================== -->
-    <!-- Defines TreeCache configuration                                      -->
-    <!-- ==================================================================== -->
-
-    <mbean code="org.jboss.cache.TreeCache"
-        name="jboss.cache:service=TreeCache">
-
-        <depends>jboss:service=Naming</depends>
-        <depends>jboss:service=TransactionManager</depends>
-
-        <!--
-            TransactionManager configuration not required for Hibernate!
-        -->
-
-
-        <!--
-            Node isolation level : SERIALIZABLE
-                                 REPEATABLE_READ (default)
-                                 READ_COMMITTED
-                                 READ_UNCOMMITTED
-                                 NONE
-        -->
-        <attribute name="IsolationLevel">REPEATABLE_READ</attribute>
-
-        <!--
-             Valid modes are LOCAL
-                             REPL_ASYNC
-                             REPL_SYNC
-        -->
-        <attribute name="CacheMode">LOCAL</attribute>
-
-        <!-- Name of cluster. Needs to be the same for all clusters, in order
-             to find each other
-        -->
-        <attribute name="ClusterName">TreeCache-Cluster</attribute>
-
-        <!-- JGroups protocol stack properties. Can also be a URL,
-             e.g. file:/home/bela/default.xml
-           <attribute name="ClusterProperties"></attribute>
-        -->
-
-        <attribute name="ClusterConfig">
-            <config>
-                <!-- UDP: if you have a multihomed machine,
-                set the bind_addr attribute to the appropriate NIC IP address -->
-                <!-- UDP: On Windows machines, because of the media sense feature
-                 being broken with multicast (even after disabling media sense)
-                 set the loopback attribute to true -->
-                <UDP mcast_addr="228.1.2.3" mcast_port="45566"
-                    ip_ttl="64" ip_mcast="true"
-                    mcast_send_buf_size="150000" mcast_recv_buf_size="80000"
-                    ucast_send_buf_size="150000" ucast_recv_buf_size="80000"
-                    loopback="false"/>
-                <PING timeout="2000" num_initial_members="3"
-                    up_thread="false" down_thread="false"/>
-                <MERGE2 min_interval="10000" max_interval="20000"/>
-                <FD shun="true" up_thread="true" down_thread="true"/>
-                <VERIFY_SUSPECT timeout="1500"
-                    up_thread="false" down_thread="false"/>
-                <pbcast.NAKACK gc_lag="50" retransmit_timeout="600,1200,2400,4800"
-                    up_thread="false" down_thread="false"/>
-                <pbcast.STABLE desired_avg_gossip="20000"
-                    up_thread="false" down_thread="false"/>
-                <UNICAST timeout="600,1200,2400" window_size="100" min_threshold="10"
-                    down_thread="false"/>
-                <FRAG frag_size="8192"
-                    down_thread="false" up_thread="false"/>
-                <pbcast.GMS join_timeout="5000" join_retry_timeout="2000"
-                    shun="true" print_local_addr="true"/>
-                <pbcast.STATE_TRANSFER up_thread="false" down_thread="false"/>
-            </config>
-        </attribute>
-
-        <!--
-             Max number of entries in the cache. If this is exceeded, the
-             eviction policy will kick some entries out in order to make
-             more room
-        -->
-        <attribute name="MaxCapacity">20000</attribute>
-
-        <!--
-            The max amount of time (in milliseconds) we wait until the
-            initial state (ie. the contents of the cache) are retrieved from
-            existing members in a clustered environment
-        -->
-        <attribute name="InitialStateRetrievalTimeout">20000</attribute>
-
-        <!--
-            Number of milliseconds to wait until all responses for a
-            synchronous call have been received.
-        -->
-        <attribute name="SyncReplTimeout">10000</attribute>
-
-        <!-- Max number of milliseconds to wait for a lock acquisition -->
-        <attribute name="LockAcquisitionTimeout">15000</attribute>
-
-        <!-- Max number of milliseconds we hold a lock (not currently
-        implemented) -->
-        <attribute name="LockLeaseTimeout">60000</attribute>
-
-        <!-- Name of the eviction policy class. Not supported now. -->
-        <attribute name="EvictionPolicyClass"></attribute>
-    </mbean>
-
-
-</server>

-- 
hibernate-jbosscache: Integration of Hibernate with JBossCache



More information about the pkg-java-commits mailing list