[HHH-2555] Reimplement Hibernate/JBC 2.0 integration
git-svn-id: https://svn.jboss.org/repos/hibernate/core/trunk@14101 1b8cb986-b30d-0410-93ca-fae66ebed9b2
This commit is contained in:
parent
b0beac4acd
commit
161e5cc19f
|
@ -25,16 +25,36 @@
|
|||
<version>${version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>jboss</groupId>
|
||||
<artifactId>jboss-cache</artifactId>
|
||||
<groupId>${groupId}</groupId>
|
||||
<artifactId>hibernate-testing</artifactId>
|
||||
<version>${version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jboss.cache</groupId>
|
||||
<artifactId>jbosscache-core</artifactId>
|
||||
<!-- I'd prefer this, at least until we get a GA...
|
||||
<version>[2.0.0.BETA2,)</version>
|
||||
-->
|
||||
<version>2.0.0.BETA2</version>
|
||||
</dependency>
|
||||
<version>2.1.0.BETA1</version>
|
||||
</dependency>
|
||||
<!-- test dependencies -->
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<build>
|
||||
<testResources>
|
||||
<testResource>
|
||||
<filtering>false</filtering>
|
||||
<directory>src/test/java</directory>
|
||||
<includes>
|
||||
<include>**/*.xml</include>
|
||||
</includes>
|
||||
</testResource>
|
||||
<testResource>
|
||||
<filtering>true</filtering>
|
||||
<directory>src/test/resources</directory>
|
||||
</testResource>
|
||||
</testResources>
|
||||
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
|
@ -43,8 +63,72 @@
|
|||
<source>1.5</source>
|
||||
<target>1.5</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.jboss.maven.plugins</groupId>
|
||||
<artifactId>maven-test-ext-plugin</artifactId>
|
||||
<version>1.1.0</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>extend</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<configuration>
|
||||
<systemProperties>
|
||||
<property>
|
||||
<name>hibernate.test.validatefailureexpected</name>
|
||||
<value>true</value>
|
||||
</property>
|
||||
</systemProperties>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</build>
|
||||
|
||||
<profiles>
|
||||
<!-- HSQLDB is the default (eventually move to H2) -->
|
||||
<profile>
|
||||
<id>hsqldb</id>
|
||||
<activation>
|
||||
<activeByDefault>true</activeByDefault>
|
||||
</activation>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>hsqldb</groupId>
|
||||
<artifactId>hsqldb</artifactId>
|
||||
<version>1.8.0.2</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-log4j12</artifactId>
|
||||
<version>1.4.2</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>log4j</groupId>
|
||||
<artifactId>log4j</artifactId>
|
||||
<version>1.2.14</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cglib</groupId>
|
||||
<artifactId>cglib</artifactId>
|
||||
<version>2.1_3</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<properties>
|
||||
<db.dialect>org.hibernate.dialect.HSQLDialect</db.dialect>
|
||||
<jdbc.driver>org.hsqldb.jdbcDriver</jdbc.driver>
|
||||
<jdbc.url>jdbc:hsqldb:target/test/db/hsqldb/hibernate</jdbc.url>
|
||||
<jdbc.user>sa</jdbc.user>
|
||||
<jdbc.pass/>
|
||||
<jdbc.isolation/>
|
||||
</properties>
|
||||
</profile>
|
||||
</profiles>
|
||||
|
||||
</project>
|
||||
|
|
|
@ -19,128 +19,307 @@ import java.util.HashMap;
|
|||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.transaction.SystemException;
|
||||
import javax.transaction.Transaction;
|
||||
import javax.transaction.TransactionManager;
|
||||
|
||||
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.CacheListener;
|
||||
import org.jboss.cache.notifications.annotation.NodeCreated;
|
||||
import org.jboss.cache.notifications.event.NodeCreatedEvent;
|
||||
import org.jboss.cache.optimistic.DataVersion;
|
||||
|
||||
import org.hibernate.cache.CacheException;
|
||||
import org.hibernate.cache.Region;
|
||||
import org.hibernate.cache.jbc2.util.CacheHelper;
|
||||
import org.hibernate.cache.jbc2.util.NonLockingDataVersion;
|
||||
|
||||
/**
|
||||
* General support for writing {@link Region} implementations for
|
||||
*
|
||||
*
|
||||
* General support for writing {@link Region} implementations for JBoss Cache
|
||||
* 2.x.
|
||||
*
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
@CacheListener
|
||||
public abstract class BasicRegionAdapter implements Region {
|
||||
public static final String ITEM = "item";
|
||||
public static final String ITEM = CacheHelper.ITEM;
|
||||
|
||||
protected final Cache jbcCache;
|
||||
protected final String regionName;
|
||||
protected final Fqn regionFqn;
|
||||
protected final Cache jbcCache;
|
||||
protected final String regionName;
|
||||
protected final Fqn regionFqn;
|
||||
protected final boolean optimistic;
|
||||
|
||||
protected final TransactionManager transactionManager;
|
||||
|
||||
public BasicRegionAdapter(Cache jbcCache, String regionName) {
|
||||
this.jbcCache = jbcCache;
|
||||
this.regionName = regionName;
|
||||
this.regionFqn = Fqn.fromString( regionName.replace( '.', '/' ) );
|
||||
activateLocalClusterNode();
|
||||
}
|
||||
protected SetResidentListener listener;
|
||||
|
||||
public BasicRegionAdapter(Cache jbcCache, String regionName, String regionPrefix) {
|
||||
this.jbcCache = jbcCache;
|
||||
this.transactionManager = jbcCache.getConfiguration().getRuntimeConfig().getTransactionManager();
|
||||
this.regionName = regionName;
|
||||
this.regionFqn = createRegionFqn(regionName, regionPrefix);
|
||||
optimistic = jbcCache.getConfiguration().getNodeLockingScheme() == NodeLockingScheme.OPTIMISTIC;
|
||||
activateLocalClusterNode();
|
||||
}
|
||||
|
||||
private void activateLocalClusterNode() {
|
||||
org.jboss.cache.Region jbcRegion = jbcCache.getRegion( regionFqn, true );
|
||||
if ( jbcRegion.isActive() ) {
|
||||
return;
|
||||
}
|
||||
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
|
||||
if ( classLoader == null ) {
|
||||
classLoader = getClass().getClassLoader();
|
||||
}
|
||||
jbcRegion.registerContextClassLoader( classLoader );
|
||||
jbcRegion.activate();
|
||||
}
|
||||
protected abstract Fqn<String> createRegionFqn(String regionName, String regionPrefix);
|
||||
|
||||
public String getName() {
|
||||
return regionName;
|
||||
}
|
||||
protected void activateLocalClusterNode() {
|
||||
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() == false) {
|
||||
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())) {
|
||||
listener = new SetResidentListener();
|
||||
jbcCache.addCacheListener(listener);
|
||||
}
|
||||
|
||||
// Make sure the root node for the region exists and
|
||||
// has a DataVersion that never complains
|
||||
Node regionRoot = jbcCache.getRoot().getChild( regionFqn );
|
||||
if (regionRoot == null) {
|
||||
// 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) == false) {
|
||||
((NodeSPI) regionRoot).setVersion(NonLockingDataVersion.INSTANCE);
|
||||
}
|
||||
}
|
||||
// Never evict this node
|
||||
regionRoot.setResident(true);
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new CacheException(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
public Cache getCacheInstance() {
|
||||
return jbcCache;
|
||||
}
|
||||
public String getName() {
|
||||
return regionName;
|
||||
}
|
||||
|
||||
public Fqn getRegionFqn() {
|
||||
return regionFqn;
|
||||
}
|
||||
public Cache getCacheInstance() {
|
||||
return jbcCache;
|
||||
}
|
||||
|
||||
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 propogate 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 );
|
||||
jbcCache.getInvocationContext().setOptionOverrides( option );
|
||||
jbcCache.removeNode( regionFqn );
|
||||
deactivateLocalNode();
|
||||
}
|
||||
catch( Exception e ) {
|
||||
throw new CacheException( e );
|
||||
}
|
||||
}
|
||||
public Fqn getRegionFqn() {
|
||||
return regionFqn;
|
||||
}
|
||||
|
||||
private void deactivateLocalNode() {
|
||||
org.jboss.cache.Region jbcRegion = jbcCache.getRegion( regionFqn, false );
|
||||
if ( jbcRegion != null && jbcRegion.isActive() ) {
|
||||
jbcRegion.deactivate();
|
||||
jbcRegion.unregisterContextClassLoader();
|
||||
}
|
||||
}
|
||||
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 propogate 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 {
|
||||
if (listener != null)
|
||||
jbcCache.removeCacheListener(listener);
|
||||
}
|
||||
}
|
||||
|
||||
public long getSizeInMemory() {
|
||||
// not supported
|
||||
return -1;
|
||||
}
|
||||
protected void deactivateLocalNode() {
|
||||
org.jboss.cache.Region jbcRegion = jbcCache.getRegion(regionFqn, false);
|
||||
if (jbcRegion != null && jbcRegion.isActive()) {
|
||||
jbcRegion.deactivate();
|
||||
jbcRegion.unregisterContextClassLoader();
|
||||
}
|
||||
}
|
||||
|
||||
public long getElementCountInMemory() {
|
||||
try {
|
||||
Set children = jbcCache.getRoot().getChild( regionFqn ).getChildrenNames();
|
||||
return children == null ? 0 : children.size();
|
||||
}
|
||||
catch ( Exception e ) {
|
||||
throw new CacheException( e );
|
||||
}
|
||||
}
|
||||
public long getSizeInMemory() {
|
||||
// not supported
|
||||
return -1;
|
||||
}
|
||||
|
||||
public long getElementCountOnDisk() {
|
||||
return -1;
|
||||
}
|
||||
public long getElementCountInMemory() {
|
||||
try {
|
||||
Set childrenNames = CacheHelper.getChildrenNames(jbcCache, regionFqn);
|
||||
return childrenNames.size();
|
||||
} catch (Exception e) {
|
||||
throw new CacheException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public Map toMap() {
|
||||
try {
|
||||
Map result = new HashMap();
|
||||
Set childrenNames = jbcCache.getRoot().getChild( regionFqn ).getChildrenNames();
|
||||
if (childrenNames != null) {
|
||||
for ( Object childName : childrenNames ) {
|
||||
result.put( childName, jbcCache.get( new Fqn( regionFqn, childName ), ITEM ) );
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new CacheException(e);
|
||||
}
|
||||
}
|
||||
public long getElementCountOnDisk() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
public long nextTimestamp() {
|
||||
return System.currentTimeMillis() / 100;
|
||||
}
|
||||
public Map toMap() {
|
||||
try {
|
||||
Map result = new HashMap();
|
||||
Set childrenNames = CacheHelper.getChildrenNames(jbcCache, regionFqn);
|
||||
for (Object childName : childrenNames) {
|
||||
result.put(childName, jbcCache.get(new Fqn(regionFqn, childName), ITEM));
|
||||
}
|
||||
return result;
|
||||
} catch (Exception e) {
|
||||
throw new CacheException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public int getTimeout() {
|
||||
return 600; //60 seconds
|
||||
}
|
||||
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
|
||||
* @param opt any option to add to the get invocation. May be <code>null</code>
|
||||
* @param suppressTimeout should any TimeoutException be suppressed?
|
||||
* @return
|
||||
*/
|
||||
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
|
||||
*/
|
||||
protected Transaction suspend() {
|
||||
Transaction tx = null;
|
||||
try {
|
||||
if (transactionManager != null) {
|
||||
tx = transactionManager.suspend();
|
||||
}
|
||||
} catch (SystemException se) {
|
||||
throw new CacheException("Could not suspend transaction", se);
|
||||
}
|
||||
return tx;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tell the TransactionManager to resume the given transaction
|
||||
*
|
||||
* @param tx
|
||||
* the transaction to suspend. May be <code>null</code>.
|
||||
*/
|
||||
protected void resume(Transaction tx) {
|
||||
try {
|
||||
if (tx != null)
|
||||
transactionManager.resume(tx);
|
||||
} catch (Exception e) {
|
||||
throw new CacheException("Could not resume transaction", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
@CacheListener
|
||||
public class SetResidentListener {
|
||||
|
||||
@NodeCreated
|
||||
public void nodeCreated(NodeCreatedEvent event) {
|
||||
if (!event.isPre() && event.getFqn().equals(getRegionFqn())) {
|
||||
Node regionRoot = jbcCache.getRoot().getChild(getRegionFqn());
|
||||
regionRoot.setResident(true);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,48 +15,69 @@
|
|||
*/
|
||||
package org.hibernate.cache.jbc2;
|
||||
|
||||
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
|
||||
* 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
|
||||
* 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
|
||||
* 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();
|
||||
/**
|
||||
* Retrieve a handle to the {@link Cache} instance to be used for storing
|
||||
* timestamps.
|
||||
*
|
||||
* @return The timestamps cache instance.
|
||||
*/
|
||||
public Cache getTimestampsCacheInstance();
|
||||
|
||||
/**
|
||||
* Release any held resources.
|
||||
*/
|
||||
public void release();
|
||||
/**
|
||||
* 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();
|
||||
}
|
||||
|
|
142
cache-jbosscache2/src/main/java/org/hibernate/cache/jbc2/JBossCacheRegionFactory.java
vendored
Normal file → Executable file
142
cache-jbosscache2/src/main/java/org/hibernate/cache/jbc2/JBossCacheRegionFactory.java
vendored
Normal file → Executable file
|
@ -24,66 +24,122 @@ import org.hibernate.cache.EntityRegion;
|
|||
import org.hibernate.cache.QueryResultsRegion;
|
||||
import org.hibernate.cache.RegionFactory;
|
||||
import org.hibernate.cache.TimestampsRegion;
|
||||
import org.hibernate.cache.jbc2.builder.InvalidationCacheInstanceManager;
|
||||
import org.hibernate.cache.jbc2.builder.JndiSharedCacheInstanceManager;
|
||||
import org.hibernate.cache.jbc2.builder.SharedCacheInstanceManager;
|
||||
import org.hibernate.cache.jbc2.collection.CollectionRegionImpl;
|
||||
import org.hibernate.cache.jbc2.entity.EntityRegionImpl;
|
||||
import org.hibernate.cache.jbc2.query.QueryResultsRegionImpl;
|
||||
import org.hibernate.cache.jbc2.timestamp.TimestampsRegionImpl;
|
||||
import org.hibernate.cfg.Environment;
|
||||
import org.hibernate.cfg.Settings;
|
||||
import org.hibernate.util.PropertiesHelper;
|
||||
import org.jboss.cache.DefaultCacheFactory;
|
||||
|
||||
;
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* {@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>
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
* @author Brian Stansberry
|
||||
*/
|
||||
public class JBossCacheRegionFactory implements RegionFactory {
|
||||
private CacheInstanceManager cacheInstanceManager;
|
||||
private CacheInstanceManager cacheInstanceManager;
|
||||
|
||||
public JBossCacheRegionFactory() {
|
||||
}
|
||||
/**
|
||||
* FIXME Per the RegionFactory class Javadoc, this constructor version
|
||||
* should not be necessary.
|
||||
*
|
||||
* @param props
|
||||
*/
|
||||
public JBossCacheRegionFactory(Properties props) {
|
||||
this();
|
||||
}
|
||||
|
||||
public JBossCacheRegionFactory(CacheInstanceManager cacheInstanceManager) {
|
||||
this.cacheInstanceManager = cacheInstanceManager;
|
||||
}
|
||||
/**
|
||||
* Create a new JBossCacheRegionFactory.
|
||||
*/
|
||||
public JBossCacheRegionFactory() {
|
||||
}
|
||||
|
||||
public void start(Settings settings, Properties properties) throws CacheException {
|
||||
if ( cacheInstanceManager == null ) {
|
||||
cacheInstanceManager = new InvalidationCacheInstanceManager( settings, properties );
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Create a new JBossCacheRegionFactory that uses the provided
|
||||
* {@link CacheInstanceManager}.
|
||||
*
|
||||
* @param cacheInstanceManager
|
||||
*/
|
||||
public JBossCacheRegionFactory(CacheInstanceManager cacheInstanceManager) {
|
||||
this.cacheInstanceManager = cacheInstanceManager;
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
if ( cacheInstanceManager != null ) {
|
||||
cacheInstanceManager.release();
|
||||
}
|
||||
}
|
||||
public CacheInstanceManager getCacheInstanceManager() {
|
||||
return cacheInstanceManager;
|
||||
}
|
||||
|
||||
public boolean isMinimalPutsEnabledByDefault() {
|
||||
return true;
|
||||
}
|
||||
public void start(Settings settings, Properties properties) throws CacheException {
|
||||
if (cacheInstanceManager == null) {
|
||||
cacheInstanceManager = new SharedCacheInstanceManager();
|
||||
}
|
||||
|
||||
public long nextTimestamp() {
|
||||
return System.currentTimeMillis() / 100;
|
||||
}
|
||||
cacheInstanceManager.start(settings, properties);
|
||||
}
|
||||
|
||||
public EntityRegion buildEntityRegion(
|
||||
String regionName,
|
||||
Properties properties,
|
||||
CacheDataDescription metadata) throws CacheException {
|
||||
return new EntityRegionImpl( cacheInstanceManager.getEntityCacheInstance(), regionName, metadata );
|
||||
}
|
||||
public void stop() {
|
||||
if (cacheInstanceManager != null) {
|
||||
cacheInstanceManager.stop();
|
||||
}
|
||||
}
|
||||
|
||||
public CollectionRegion buildCollectionRegion(
|
||||
String regionName,
|
||||
Properties properties,
|
||||
CacheDataDescription metadata) throws CacheException {
|
||||
return new CollectionRegionImpl( cacheInstanceManager.getCollectionCacheInstance(), regionName, metadata );
|
||||
}
|
||||
public boolean isMinimalPutsEnabledByDefault() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public QueryResultsRegion buildQueryResultsRegion(String regionName, Properties properties) throws CacheException {
|
||||
return null;
|
||||
}
|
||||
public long nextTimestamp() {
|
||||
return System.currentTimeMillis() / 100;
|
||||
}
|
||||
|
||||
public TimestampsRegion buildTimestampsRegion(String regionName, Properties properties) throws CacheException {
|
||||
return null;
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* 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.jbc2;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import org.hibernate.cache.jbc2.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 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>
|
||||
*
|
||||
* @author Brian Stansberry
|
||||
* @version $Revision$
|
||||
*/
|
||||
public class JndiMultiplexedJBossCacheRegionFactory extends JBossCacheRegionFactory {
|
||||
|
||||
/**
|
||||
* FIXME Per the RegionFactory class Javadoc, this constructor version
|
||||
* should not be necessary.
|
||||
*
|
||||
* @param props
|
||||
*/
|
||||
public JndiMultiplexedJBossCacheRegionFactory(Properties props) {
|
||||
this();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new MultiplexedJBossCacheRegionFactory.
|
||||
*
|
||||
*/
|
||||
public JndiMultiplexedJBossCacheRegionFactory() {
|
||||
super(new JndiMultiplexingCacheInstanceManager());
|
||||
}
|
||||
|
||||
}
|
57
cache-jbosscache2/src/main/java/org/hibernate/cache/jbc2/JndiSharedJBossCacheRegionFactory.java
vendored
Normal file
57
cache-jbosscache2/src/main/java/org/hibernate/cache/jbc2/JndiSharedJBossCacheRegionFactory.java
vendored
Normal file
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* 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.jbc2;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import org.hibernate.cache.jbc2.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>
|
||||
*
|
||||
* @author Brian Stansberry
|
||||
* @version $Revision$
|
||||
*/
|
||||
public class JndiSharedJBossCacheRegionFactory extends JBossCacheRegionFactory {
|
||||
|
||||
/**
|
||||
* FIXME Per the RegionFactory class Javadoc, this constructor version
|
||||
* should not be necessary.
|
||||
*
|
||||
* @param props
|
||||
*/
|
||||
public JndiSharedJBossCacheRegionFactory(Properties props) {
|
||||
this();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new MultiplexedJBossCacheRegionFactory.
|
||||
*
|
||||
*/
|
||||
public JndiSharedJBossCacheRegionFactory() {
|
||||
super(new JndiSharedCacheInstanceManager());
|
||||
}
|
||||
|
||||
}
|
61
cache-jbosscache2/src/main/java/org/hibernate/cache/jbc2/MultiplexedJBossCacheRegionFactory.java
vendored
Normal file
61
cache-jbosscache2/src/main/java/org/hibernate/cache/jbc2/MultiplexedJBossCacheRegionFactory.java
vendored
Normal file
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* 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.jbc2;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import org.hibernate.cache.jbc2.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 multiplexed
|
||||
* JGroups 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>
|
||||
*
|
||||
* @author Brian Stansberry
|
||||
* @version $Revision$
|
||||
*/
|
||||
public class MultiplexedJBossCacheRegionFactory extends JBossCacheRegionFactory {
|
||||
|
||||
/**
|
||||
* FIXME Per the RegionFactory class Javadoc, this constructor version
|
||||
* should not be necessary.
|
||||
*
|
||||
* @param props
|
||||
*/
|
||||
public MultiplexedJBossCacheRegionFactory(Properties props) {
|
||||
this();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new MultiplexedJBossCacheRegionFactory.
|
||||
*
|
||||
*/
|
||||
public MultiplexedJBossCacheRegionFactory() {
|
||||
super(new MultiplexingCacheInstanceManager());
|
||||
}
|
||||
|
||||
}
|
60
cache-jbosscache2/src/main/java/org/hibernate/cache/jbc2/SharedJBossCacheRegionFactory.java
vendored
Normal file
60
cache-jbosscache2/src/main/java/org/hibernate/cache/jbc2/SharedJBossCacheRegionFactory.java
vendored
Normal file
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* 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.jbc2;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import org.hibernate.cache.jbc2.builder.JndiSharedCacheInstanceManager;
|
||||
import org.hibernate.cache.jbc2.builder.SharedCacheInstanceManager;
|
||||
import org.jboss.cache.DefaultCacheFactory;
|
||||
|
||||
/**
|
||||
* {@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>
|
||||
*
|
||||
* @author Brian Stansberry
|
||||
* @version $Revision$
|
||||
*/
|
||||
public class SharedJBossCacheRegionFactory extends JBossCacheRegionFactory {
|
||||
|
||||
/**
|
||||
* FIXME Per the RegionFactory class Javadoc, this constructor version
|
||||
* should not be necessary.
|
||||
*
|
||||
* @param props
|
||||
*/
|
||||
public SharedJBossCacheRegionFactory(Properties props) {
|
||||
this();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new MultiplexedJBossCacheRegionFactory.
|
||||
*
|
||||
*/
|
||||
public SharedJBossCacheRegionFactory() {
|
||||
super(new SharedCacheInstanceManager());
|
||||
}
|
||||
|
||||
}
|
|
@ -15,36 +15,38 @@
|
|||
*/
|
||||
package org.hibernate.cache.jbc2;
|
||||
|
||||
import org.jboss.cache.Cache;
|
||||
|
||||
import org.hibernate.cache.TransactionalDataRegion;
|
||||
import org.hibernate.cache.CacheDataDescription;
|
||||
import org.hibernate.cache.TransactionalDataRegion;
|
||||
import org.jboss.cache.Cache;
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class TransactionalDataRegionAdapter extends BasicRegionAdapter implements TransactionalDataRegion {
|
||||
protected final CacheDataDescription metadata;
|
||||
public abstract class TransactionalDataRegionAdapter extends BasicRegionAdapter implements TransactionalDataRegion {
|
||||
|
||||
public TransactionalDataRegionAdapter(Cache jbcCache, String regionName, CacheDataDescription metadata) {
|
||||
super( jbcCache, regionName );
|
||||
this.metadata = metadata;
|
||||
}
|
||||
protected final CacheDataDescription metadata;
|
||||
|
||||
/**
|
||||
* Here, for JBossCache, we consider the cache to be transaction aware if the underlying
|
||||
* cache instance has a refernece to the transaction manager.
|
||||
*/
|
||||
public boolean isTransactionAware() {
|
||||
return jbcCache.getConfiguration().getRuntimeConfig().getTransactionManager() != null;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public CacheDataDescription getCacheDataDescription() {
|
||||
return metadata;
|
||||
}
|
||||
}
|
||||
|
|
144
cache-jbosscache2/src/main/java/org/hibernate/cache/jbc2/access/OptimisticTransactionalAccessDelegate.java
vendored
Executable file
144
cache-jbosscache2/src/main/java/org/hibernate/cache/jbc2/access/OptimisticTransactionalAccessDelegate.java
vendored
Executable file
|
@ -0,0 +1,144 @@
|
|||
/*
|
||||
* 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.jbc2.access;
|
||||
|
||||
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.jbc2.util.CacheHelper;
|
||||
import org.hibernate.cache.jbc2.util.DataVersionAdapter;
|
||||
import org.hibernate.cache.jbc2.util.NonLockingDataVersion;
|
||||
import org.jboss.cache.Cache;
|
||||
import org.jboss.cache.Fqn;
|
||||
import org.jboss.cache.config.Option;
|
||||
import org.jboss.cache.optimistic.DataVersion;
|
||||
|
||||
/**
|
||||
* 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(Cache cache, Fqn regionFqn, CacheDataDescription dataDescription) {
|
||||
super(cache, regionFqn);
|
||||
this.dataDescription = dataDescription;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides the
|
||||
* {@link TransactionalAccessDelegate#evict(Object) superclass} by adding a
|
||||
* {@link NonLockingDataVersion} to the invocation.
|
||||
*/
|
||||
@Override
|
||||
public void evict(Object key) throws CacheException {
|
||||
|
||||
Option opt = NonLockingDataVersion.getInvocationOption();
|
||||
CacheHelper.remove(cache, regionFqn, key, opt);
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides the {@link TransactionalAccessDelegate#evictAll() superclass}
|
||||
* by adding a {@link NonLockingDataVersion} to the invocation.
|
||||
*/
|
||||
@Override
|
||||
public void evictAll() throws CacheException {
|
||||
|
||||
evictOrRemoveAll();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
|
||||
Option opt = getDataVersionOption(version, null);
|
||||
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 {
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean putFromLoad(Object key, Object value, long txTimestamp, Object version) throws CacheException {
|
||||
|
||||
Option opt = getDataVersionOption(version, version);
|
||||
return CacheHelper.putForExternalRead(cache, regionFqn, key, value, opt);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove(Object key) throws CacheException {
|
||||
|
||||
Option opt = NonLockingDataVersion.getInvocationOption();
|
||||
CacheHelper.remove(cache, regionFqn, key, opt);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeAll() throws CacheException {
|
||||
|
||||
evictOrRemoveAll();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean update(Object key, Object value, Object currentVersion, Object previousVersion)
|
||||
throws CacheException {
|
||||
|
||||
Option opt = getDataVersionOption(currentVersion, previousVersion);
|
||||
CacheHelper.put(cache, regionFqn, key, value, opt);
|
||||
return true;
|
||||
}
|
||||
|
||||
private Option getDataVersionOption(Object currentVersion, Object previousVersion) {
|
||||
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;
|
||||
}
|
||||
|
||||
private void evictOrRemoveAll() {
|
||||
Option opt = NonLockingDataVersion.getInvocationOption();
|
||||
CacheHelper.removeAll(cache, regionFqn, opt);
|
||||
|
||||
// Restablish the region root node with a non-locking data version
|
||||
CacheHelper.addNode(cache, regionFqn, false, true, NonLockingDataVersion.INSTANCE);
|
||||
}
|
||||
|
||||
}
|
124
cache-jbosscache2/src/main/java/org/hibernate/cache/jbc2/access/TransactionalAccessDelegate.java
vendored
Executable file
124
cache-jbosscache2/src/main/java/org/hibernate/cache/jbc2/access/TransactionalAccessDelegate.java
vendored
Executable file
|
@ -0,0 +1,124 @@
|
|||
/*
|
||||
* 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): Steve Ebersole
|
||||
*/
|
||||
package org.hibernate.cache.jbc2.access;
|
||||
|
||||
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.jbc2.util.CacheHelper;
|
||||
import org.jboss.cache.Cache;
|
||||
import org.jboss.cache.Fqn;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
public TransactionalAccessDelegate(Cache cache, Fqn regionFqn) {
|
||||
this.cache = cache;
|
||||
this.regionFqn = regionFqn;
|
||||
}
|
||||
|
||||
public Object get(Object key, long txTimestamp) throws CacheException {
|
||||
|
||||
return CacheHelper.get(cache, regionFqn, key);
|
||||
}
|
||||
|
||||
public boolean putFromLoad(Object key, Object value, long txTimestamp, Object version) throws CacheException {
|
||||
|
||||
return CacheHelper.putForExternalRead(cache, regionFqn, key, value);
|
||||
}
|
||||
|
||||
public boolean putFromLoad(Object key, Object value, long txTimestamp, Object version, boolean minimalPutOverride)
|
||||
throws CacheException {
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
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 {
|
||||
|
||||
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 {
|
||||
|
||||
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 {
|
||||
|
||||
CacheHelper.remove(cache, regionFqn, key);
|
||||
}
|
||||
|
||||
public void removeAll() throws CacheException {
|
||||
evictOrRemoveAll();
|
||||
}
|
||||
|
||||
public void evict(Object key) throws CacheException {
|
||||
CacheHelper.remove(cache, regionFqn, key);
|
||||
}
|
||||
|
||||
public void evictAll() throws CacheException {
|
||||
evictOrRemoveAll();
|
||||
}
|
||||
|
||||
private void evictOrRemoveAll() throws CacheException {
|
||||
CacheHelper.removeAll(cache, regionFqn);
|
||||
// Restore the region root node
|
||||
CacheHelper.addNode(cache, regionFqn, false, true, null);
|
||||
}
|
||||
}
|
|
@ -1,112 +0,0 @@
|
|||
/*
|
||||
* 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): Steve Ebersole
|
||||
*/
|
||||
package org.hibernate.cache.jbc2.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.DefaultCacheFactory;
|
||||
|
||||
import org.hibernate.cache.CacheException;
|
||||
import org.hibernate.cache.jbc2.CacheInstanceManager;
|
||||
import org.hibernate.cache.jbc2.util.CacheModeHelper;
|
||||
import org.hibernate.cfg.Settings;
|
||||
import org.hibernate.util.PropertiesHelper;
|
||||
|
||||
/**
|
||||
* A {@link CacheInstanceManager} implementation where we use a single cache instance
|
||||
* we assume to be configured for invalidation if operating on a cluster. Under that
|
||||
* assumption, we can store all data into the same {@link Cache} instance.
|
||||
* <p/>
|
||||
* todo : this is built on the assumption that JBC clustered invalidation is changed to keep the "cache node" around on the other "cluster nodes"
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class InvalidationCacheInstanceManager implements CacheInstanceManager {
|
||||
public static final String CACHE_RESOURCE_PROP = "hibernate.cache.region.jbc2.cfg.invalidation";
|
||||
public static final String DEFAULT_CACHE_RESOURCE = "treecache.xml";
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger( InvalidationCacheInstanceManager.class );
|
||||
|
||||
private final Cache cache;
|
||||
|
||||
public InvalidationCacheInstanceManager(Settings settings, Properties properties) {
|
||||
String configResource = PropertiesHelper.getString( CACHE_RESOURCE_PROP, properties, DEFAULT_CACHE_RESOURCE );
|
||||
cache = DefaultCacheFactory.getInstance().createCache( configResource, false );
|
||||
if ( settings.getTransactionManagerLookup() != null ) {
|
||||
TransactionManager tm = settings.getTransactionManagerLookup().getTransactionManager( properties );
|
||||
if ( tm != null ) {
|
||||
cache.getConfiguration().getRuntimeConfig().setTransactionManager( tm );
|
||||
}
|
||||
}
|
||||
cache.start();
|
||||
}
|
||||
|
||||
public InvalidationCacheInstanceManager(Cache cache) {
|
||||
this.cache = cache;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public Cache getEntityCacheInstance() {
|
||||
return cache;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public Cache getCollectionCacheInstance() {
|
||||
return cache;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public Cache getQueryCacheInstance() {
|
||||
if ( CacheModeHelper.isClusteredInvalidation( cache ) ) {
|
||||
throw new CacheException( "Query cache not supported for clustered invalidation" );
|
||||
}
|
||||
return cache;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public Cache getTimestampsCacheInstance() {
|
||||
if ( CacheModeHelper.isClusteredInvalidation( cache ) ) {
|
||||
throw new CacheException( "Query cache not supported for clustered invalidation" );
|
||||
}
|
||||
return cache;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public void release() {
|
||||
if ( cache != null ) {
|
||||
try {
|
||||
cache.stop();
|
||||
}
|
||||
catch( Throwable t ) {
|
||||
log.warn( "Unable to stop cache instance", t );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
74
cache-jbosscache2/src/main/java/org/hibernate/cache/jbc2/builder/JBossCacheFactory.java
vendored
Normal file
74
cache-jbosscache2/src/main/java/org/hibernate/cache/jbc2/builder/JBossCacheFactory.java
vendored
Normal file
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
* 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.jbc2.builder;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import org.jboss.cache.Cache;
|
||||
|
||||
/**
|
||||
* Factory and registry for JBoss Cache instances configured using
|
||||
* named configurations.
|
||||
*
|
||||
* @author <a href="brian.stansberry@jboss.com">Brian Stansberry</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public interface JBossCacheFactory {
|
||||
|
||||
/**
|
||||
* Gets all the names of all the configurations of which this object
|
||||
* is aware.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
Set getConfigurationNames();
|
||||
|
||||
/**
|
||||
* Get a cache configured according to the given configuration name.
|
||||
* <p>
|
||||
* The caller is free to invoke the {@link Cache#create()} and
|
||||
* {@link Cache#start()} lifecycle methods on the returned cache, but
|
||||
* the @link Cache#stop()} and {@link Cache#destroy()} methods should not
|
||||
* be invoked, since it is quite possible other session factories are
|
||||
* still using the cache. Use {@link #releaseCache(String)} to notify this
|
||||
* factory that the caller is no longer using a cache; let the factory
|
||||
* control stopping and destroying the underlying cache.
|
||||
* </p>
|
||||
*
|
||||
* @param configName the name of the configuration
|
||||
* @param create should the cache be instantiated if it
|
||||
* hasn't already been?
|
||||
* @return the cache, or <code>null</code> if
|
||||
* <code>create</code> is false and the cache hasn't
|
||||
* been created previously.
|
||||
*
|
||||
* @throws IllegalArgumentException if this object is unaware of
|
||||
* <code>configName</code>
|
||||
* @throws Exception if there is a problem instantiating the cache
|
||||
*/
|
||||
Cache getCache(String configName, boolean create) throws Exception;
|
||||
|
||||
/**
|
||||
* Notifies the factory that the caller is no longer using the given
|
||||
* cache. The factory may perform cleanup operations, such as
|
||||
* stopping and destroying the cache.
|
||||
*
|
||||
* @param configName
|
||||
*/
|
||||
void releaseCache(String configName);
|
||||
|
||||
}
|
361
cache-jbosscache2/src/main/java/org/hibernate/cache/jbc2/builder/JBossCacheFactoryImpl.java
vendored
Normal file
361
cache-jbosscache2/src/main/java/org/hibernate/cache/jbc2/builder/JBossCacheFactoryImpl.java
vendored
Normal file
|
@ -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.jbc2.builder;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.InputStream;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
|
||||
import org.hibernate.cache.CacheException;
|
||||
import org.jboss.cache.Cache;
|
||||
import org.jboss.cache.CacheStatus;
|
||||
import org.jboss.cache.DefaultCacheFactory;
|
||||
import org.jboss.cache.config.Configuration;
|
||||
import org.jboss.cache.config.ConfigurationException;
|
||||
import org.jboss.cache.xml.XmlHelper;
|
||||
import org.jgroups.ChannelFactory;
|
||||
import org.jgroups.JChannelFactory;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.w3c.dom.DOMImplementation;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NodeList;
|
||||
import org.w3c.dom.ls.DOMImplementationLS;
|
||||
import org.w3c.dom.ls.LSOutput;
|
||||
import org.w3c.dom.ls.LSSerializer;
|
||||
|
||||
/**
|
||||
* A JBossCacheConfigurationFactory. This is a basic prototype of a
|
||||
* JBCACHE-1156 solution; only in Hibernate code base for a very short
|
||||
* period.
|
||||
*
|
||||
* @author <a href="brian.stansberry@jboss.com">Brian Stansberry</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class JBossCacheFactoryImpl implements JBossCacheFactory {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(JBossCacheFactoryImpl.class);
|
||||
|
||||
private static final String DOCUMENT_ROOT = "cache-configs";
|
||||
private static final String CONFIG_ROOT = "cache-config";
|
||||
private static final String CONFIG_NAME = "name";
|
||||
|
||||
private static JBossCacheFactoryImpl sharedFactory;
|
||||
private static String sharedChannelFactoryCfg;
|
||||
|
||||
private XmlConfigurationParser parser;
|
||||
private String configResource;
|
||||
private Map configs = new HashMap();
|
||||
private Map caches = new HashMap();
|
||||
private Map checkouts = new HashMap();
|
||||
private ChannelFactory channelFactory;
|
||||
private boolean started;
|
||||
|
||||
public JBossCacheFactoryImpl(String configResource, ChannelFactory factory) {
|
||||
|
||||
parser = new XmlConfigurationParser();
|
||||
this.configResource = configResource;
|
||||
this.channelFactory = factory;
|
||||
}
|
||||
|
||||
public static synchronized JBossCacheFactory getSharedInstance(String cacheConfigResource, String channelFactoryConfigResource) {
|
||||
|
||||
if (sharedFactory == null) {
|
||||
ChannelFactory cf = new JChannelFactory();
|
||||
try {
|
||||
cf.setMultiplexerConfig(channelFactoryConfigResource);
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new CacheException("Problem setting ChannelFactory config", e);
|
||||
}
|
||||
sharedFactory = new JBossCacheFactoryImpl(cacheConfigResource, cf);
|
||||
sharedChannelFactoryCfg = channelFactoryConfigResource;
|
||||
}
|
||||
else {
|
||||
// Validate that the provided resources match the existing singleton
|
||||
if (!sharedFactory.getConfigResource().equals(cacheConfigResource)) {
|
||||
throw new CacheException("Provided cacheConfigResource does " +
|
||||
"not match the existing shared factory: provided = " +
|
||||
cacheConfigResource + "; existing = " + sharedFactory.getConfigResource());
|
||||
}
|
||||
else if (!sharedChannelFactoryCfg.equals(channelFactoryConfigResource)) {
|
||||
throw new IllegalStateException("Provided channelFactoryConfigResource does " +
|
||||
"not match the existing shared factory: provided = " +
|
||||
channelFactoryConfigResource + "; existing = " + sharedChannelFactoryCfg);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return sharedFactory;
|
||||
}
|
||||
|
||||
public void start() {
|
||||
if (!started) {
|
||||
this.configs = parser.parseConfigs(configResource);
|
||||
started = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
if (started) {
|
||||
synchronized (caches) {
|
||||
for (Iterator it = caches.entrySet().iterator(); it.hasNext(); ) {
|
||||
Map.Entry entry = (Entry) it.next();
|
||||
destroyCache((Cache) entry.getValue());
|
||||
it.remove();
|
||||
}
|
||||
caches.clear();
|
||||
checkouts.clear();
|
||||
configs.clear();
|
||||
}
|
||||
started = false;
|
||||
}
|
||||
}
|
||||
|
||||
public String getConfigResource() {
|
||||
return configResource;
|
||||
}
|
||||
|
||||
public ChannelFactory getChannelFactory() {
|
||||
return channelFactory;
|
||||
}
|
||||
|
||||
public Set getConfigurationNames()
|
||||
{
|
||||
return new HashSet(configs.keySet());
|
||||
}
|
||||
|
||||
public Cache getCache(String configName, boolean create) throws Exception
|
||||
{
|
||||
Cache cache = null;
|
||||
synchronized (caches) {
|
||||
cache = (Cache) caches.get(configName);
|
||||
if (cache == null && create) {
|
||||
Configuration config = getConfiguration(configName);
|
||||
cache = DefaultCacheFactory.getInstance().createCache(config, false);
|
||||
registerCache(cache, configName);
|
||||
}
|
||||
else if (cache != null) {
|
||||
incrementCheckout(configName);
|
||||
}
|
||||
}
|
||||
|
||||
return cache;
|
||||
}
|
||||
|
||||
private int incrementCheckout(String configName) {
|
||||
synchronized (checkouts) {
|
||||
Integer count = (Integer) checkouts.get(configName);
|
||||
if (count == null)
|
||||
count = new Integer(0);
|
||||
Integer newVal = new Integer(count.intValue() + 1);
|
||||
checkouts.put(configName, newVal);
|
||||
return newVal.intValue();
|
||||
}
|
||||
}
|
||||
|
||||
private int decrementCheckout(String configName) {
|
||||
synchronized (checkouts) {
|
||||
Integer count = (Integer) checkouts.get(configName);
|
||||
if (count == null || count.intValue() < 1)
|
||||
throw new IllegalStateException("invalid count of " + count + " for " + configName);
|
||||
|
||||
Integer newVal = new Integer(count.intValue() - 1);
|
||||
checkouts.put(configName, newVal);
|
||||
return newVal.intValue();
|
||||
}
|
||||
}
|
||||
|
||||
public void registerCache(Cache cache, String configName) {
|
||||
synchronized (caches) {
|
||||
if (caches.containsKey(configName))
|
||||
throw new IllegalStateException(configName + " already registered");
|
||||
caches.put(configName, cache);
|
||||
incrementCheckout(configName);
|
||||
}
|
||||
}
|
||||
|
||||
public void releaseCache(String configName) {
|
||||
|
||||
synchronized (caches) {
|
||||
if (!caches.containsKey(configName))
|
||||
throw new IllegalStateException(configName + " not registered");
|
||||
if (decrementCheckout(configName) == 0) {
|
||||
Cache cache = (Cache) caches.remove(configName);
|
||||
destroyCache(cache);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void destroyCache(Cache cache) {
|
||||
if (cache.getCacheStatus() == CacheStatus.STARTED) {
|
||||
cache.stop();
|
||||
}
|
||||
if (cache.getCacheStatus() != CacheStatus.DESTROYED
|
||||
&& cache.getCacheStatus() != CacheStatus.INSTANTIATED) {
|
||||
cache.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
public Configuration getConfiguration(String configName) throws Exception {
|
||||
Element element = (Element) configs.get(configName);
|
||||
if (element == null)
|
||||
throw new IllegalArgumentException("unknown config " + configName);
|
||||
Configuration config = parser.parseConfig(element);
|
||||
if (channelFactory != null && config.getMultiplexerStack() != null) {
|
||||
config.getRuntimeConfig().setMuxChannelFactory(channelFactory);
|
||||
}
|
||||
return config;
|
||||
}
|
||||
|
||||
class XmlConfigurationParser extends org.jboss.cache.factories.XmlConfigurationParser {
|
||||
|
||||
public Map parseConfigs(String configs) {
|
||||
InputStream is = getAsInputStreamFromClassLoader(configs);
|
||||
if (is == null)
|
||||
{
|
||||
if (log.isDebugEnabled())
|
||||
log.debug("Unable to find configuration file " + configs + " in classpath; searching for this file on the filesystem instead.");
|
||||
try
|
||||
{
|
||||
is = new FileInputStream(configs);
|
||||
}
|
||||
catch (FileNotFoundException e)
|
||||
{
|
||||
throw new ConfigurationException("Unable to find config file " + configs + " either in classpath or on the filesystem!", e);
|
||||
}
|
||||
}
|
||||
|
||||
return parseConfigs(is);
|
||||
}
|
||||
|
||||
public Map parseConfigs(InputStream stream) {
|
||||
|
||||
// loop through all elements in XML.
|
||||
Element root = XmlHelper.getDocumentRoot(stream);
|
||||
NodeList list = root.getElementsByTagName(CONFIG_ROOT);
|
||||
if (list == null || list.getLength() == 0)
|
||||
throw new ConfigurationException("Can't find " + CONFIG_ROOT + " tag");
|
||||
|
||||
Map result = new HashMap();
|
||||
|
||||
for (int i = 0; i < list.getLength(); i++)
|
||||
{
|
||||
org.w3c.dom.Node node = list.item(i);
|
||||
if (node.getNodeType() != org.w3c.dom.Node.ELEMENT_NODE)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
Element element = (Element) node;
|
||||
String name = element.getAttribute(CONFIG_NAME);
|
||||
if (name == null || name.trim().length() == 0)
|
||||
throw new ConfigurationException("Element " + element + " has no name attribute");
|
||||
|
||||
result.put(name.trim(), element);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public Configuration parseConfig(Element config) throws Exception {
|
||||
|
||||
DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
|
||||
DocumentBuilder builder = docBuilderFactory.newDocumentBuilder();
|
||||
Document doc = builder.newDocument();
|
||||
Element root = doc.createElement(DOCUMENT_ROOT);
|
||||
doc.appendChild(root);
|
||||
Node imported = doc.importNode(config, true);
|
||||
root.appendChild(imported);
|
||||
|
||||
DOMImplementation domImpl = doc.getImplementation();
|
||||
|
||||
DOMImplementationLS impl =
|
||||
(DOMImplementationLS)domImpl.getFeature("LS", "3.0");
|
||||
|
||||
LSSerializer writer = impl.createLSSerializer();
|
||||
LSOutput output = impl.createLSOutput();
|
||||
output.setEncoding("UTF-8");
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
output.setByteStream(baos);
|
||||
writer.write(doc, output);
|
||||
|
||||
ByteArrayInputStream is = new ByteArrayInputStream(baos.toByteArray());
|
||||
return parseStream(is);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected Element getMBeanElement(Element root)
|
||||
{
|
||||
// This is following JBoss convention.
|
||||
NodeList list = root.getElementsByTagName(CONFIG_ROOT);
|
||||
if (list == null) throw new ConfigurationException("Can't find " + CONFIG_ROOT + " tag");
|
||||
|
||||
if (list.getLength() > 1) throw new ConfigurationException("Has multiple " + CONFIG_ROOT + " tag");
|
||||
|
||||
Node node = list.item(0);
|
||||
Element element = null;
|
||||
if (node.getNodeType() == org.w3c.dom.Node.ELEMENT_NODE)
|
||||
{
|
||||
element = (Element) node;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ConfigurationException("Can't find " + CONFIG_ROOT + " element");
|
||||
}
|
||||
return element;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public static void main(String[] args)
|
||||
{
|
||||
try
|
||||
{
|
||||
JChannelFactory cf = new JChannelFactory();
|
||||
cf.setMultiplexerConfig("stacks.xml");
|
||||
JBossCacheFactoryImpl factory = new JBossCacheFactoryImpl("jbc2-configs.xml", cf);
|
||||
for (Iterator iter = factory.getConfigurationNames().iterator(); iter.hasNext(); )
|
||||
{
|
||||
String name = (String) iter.next();
|
||||
Cache c = factory.getCache(name, true);
|
||||
c.start();
|
||||
System.out.println(name + " == " + c);
|
||||
factory.releaseCache(name);
|
||||
System.out.println(name + " == " + c.getCacheStatus());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace(System.out);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
* 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.jbc2.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.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@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 JBossCacheFactory} 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");
|
||||
|
||||
JBossCacheFactory cf = locateCacheFactory( name, NamingHelper.getJndiProperties( properties ) );
|
||||
setCacheFactory( cf );
|
||||
|
||||
super.start(settings, properties);
|
||||
}
|
||||
|
||||
private JBossCacheFactory locateCacheFactory(String jndiNamespace, Properties jndiProperties) {
|
||||
|
||||
Context ctx = null;
|
||||
try {
|
||||
ctx = new InitialContext( jndiProperties );
|
||||
return (JBossCacheFactory) 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 );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
105
cache-jbosscache2/src/main/java/org/hibernate/cache/jbc2/builder/JndiSharedCacheInstanceManager.java
vendored
Normal file
105
cache-jbosscache2/src/main/java/org/hibernate/cache/jbc2/builder/JndiSharedCacheInstanceManager.java
vendored
Normal file
|
@ -0,0 +1,105 @@
|
|||
/*
|
||||
* 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.jbc2.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@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 );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -19,188 +19,442 @@ import java.util.Properties;
|
|||
import javax.transaction.TransactionManager;
|
||||
|
||||
import org.jboss.cache.Cache;
|
||||
import org.jboss.cache.DefaultCacheFactory;
|
||||
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.jbc2.CacheInstanceManager;
|
||||
import org.hibernate.cfg.Settings;
|
||||
import org.hibernate.transaction.TransactionManagerLookup;
|
||||
import org.hibernate.util.PropertiesHelper;
|
||||
|
||||
/**
|
||||
* Here we build separate {@link Cache} instances for each type of region, but
|
||||
* using the jgroups multiplexer under the covers to re-use the same group
|
||||
* communication stack.
|
||||
* <p/>
|
||||
* todo : this can get simplified once JBC implemants their "configuration factory" (the stuff akin to channel factory) - http://jira.jboss.com/jira/browse/JBCACHE-1156
|
||||
* Allows building separate {@link Cache} instances for each type of region, but
|
||||
* supports using the JGroups multiplexer under the covers to re-use the same group
|
||||
* communication stack. <p/> todo : replace the prototype cache factory with
|
||||
* the equivalent JBoss Cache solution from
|
||||
* http://jira.jboss.com/jira/browse/JBCACHE-1156
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
* @author Brian Stansberry
|
||||
*/
|
||||
public class MultiplexingCacheInstanceManager implements CacheInstanceManager {
|
||||
public static final String ENTITY_CACHE_RESOURCE_PROP = "hibernate.cache.region.jbc2.cfg.entity";
|
||||
public static final String COLL_CACHE_RESOURCE_PROP = "hibernate.cache.region.jbc2.cfg.collection";
|
||||
public static final String TS_CACHE_RESOURCE_PROP = "hibernate.cache.region.jbc2.cfg.ts";
|
||||
public static final String QUERY_CACHE_RESOURCE_PROP = "hibernate.cache.region.jbc2.cfg.query";
|
||||
|
||||
public static final String DEF_ENTITY_RESOURCE = "entity-cache.xml";
|
||||
public static final String DEF_COLL_RESOURCE = "collection-cache.xml";
|
||||
public static final String DEF_TS_RESOURCE = "ts-cache.xml";
|
||||
public static final String DEF_QUERY_RESOURCE = "query-cache.xml";
|
||||
private static final Logger log = LoggerFactory.getLogger(MultiplexingCacheInstanceManager.class);
|
||||
|
||||
/**
|
||||
* Classpath or filesystem resource identifying containing JBoss Cache
|
||||
* configurations the factory should use.
|
||||
*
|
||||
* @see #DEF_CACHE_FACTORY_RESOURCE
|
||||
*/
|
||||
public static final String CACHE_FACTORY_RESOURCE_PROP = "hibernate.cache.region.jbc2.configs";
|
||||
/**
|
||||
* Classpath or filesystem resource identifying containing JGroups protocol
|
||||
* stack configurations the <code>org.jgroups.ChannelFactory</code>
|
||||
* should use.
|
||||
*
|
||||
* @see #DEF_MULTIPLEXER_RESOURCE
|
||||
*/
|
||||
public static final String CHANNEL_FACTORY_RESOURCE_PROP = "hibernate.cache.region.jbc2.multiplexer.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.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.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.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.region.jbc2.cfg.query";
|
||||
|
||||
public static final String OPTIMISTIC_LOCKING_SCHEME = "OPTIMISTIC";
|
||||
/**
|
||||
* 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/jbc2/builder/jbc2-configs.xml";
|
||||
/**
|
||||
* Default value for {@link #CHANNEL_FACTORY_RESOURCE_PROP}. Specifies
|
||||
* "stacks.xml", which can be found in the root of the JGroups jar file.
|
||||
* Thus, leaving this value at default means using the default protocol
|
||||
* stack configs provided by JGroups.
|
||||
*/
|
||||
public static final String DEF_MULTIPLEXER_RESOURCE = "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";
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger( MultiplexingCacheInstanceManager.class );
|
||||
/** 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 JBossCacheFactory 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;
|
||||
|
||||
private final Cache jbcEntityCache;
|
||||
private final Cache jbcCollectionCache;
|
||||
private final Cache jbcTsCache;
|
||||
private final Cache jbcQueryCache;
|
||||
/**
|
||||
* 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.
|
||||
* </p>
|
||||
*
|
||||
*/
|
||||
public MultiplexingCacheInstanceManager(Cache jbcEntityCache, Cache jbcCollectionCache,
|
||||
Cache jbcTsCache, Cache jbcQueryCache) {
|
||||
|
||||
this.jbcEntityCache = jbcEntityCache;
|
||||
this.jbcCollectionCache = jbcCollectionCache;
|
||||
this.jbcTsCache = jbcTsCache;
|
||||
this.jbcQueryCache = jbcQueryCache;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the cache factory.
|
||||
*/
|
||||
public JBossCacheFactory getCacheFactory() {
|
||||
return jbcFactory;
|
||||
}
|
||||
|
||||
public MultiplexingCacheInstanceManager(Settings settings, Properties properties) {
|
||||
try {
|
||||
TransactionManager tm = settings.getTransactionManagerLookup() == null
|
||||
? null
|
||||
: settings.getTransactionManagerLookup().getTransactionManager( properties );
|
||||
if ( settings.isSecondLevelCacheEnabled() ) {
|
||||
jbcEntityCache = buildEntityRegionCacheInstance( properties );
|
||||
jbcCollectionCache = buildCollectionRegionCacheInstance( properties );
|
||||
if ( tm != null ) {
|
||||
jbcEntityCache.getConfiguration().getRuntimeConfig().setTransactionManager( tm );
|
||||
jbcCollectionCache.getConfiguration().getRuntimeConfig().setTransactionManager( tm );
|
||||
}
|
||||
}
|
||||
else {
|
||||
jbcEntityCache = null;
|
||||
jbcCollectionCache = null;
|
||||
}
|
||||
if ( settings.isQueryCacheEnabled() ) {
|
||||
jbcTsCache = buildTsRegionCacheInstance( properties );
|
||||
jbcQueryCache = buildQueryRegionCacheInstance( properties );
|
||||
}
|
||||
else {
|
||||
jbcTsCache = null;
|
||||
jbcQueryCache = null;
|
||||
}
|
||||
}
|
||||
catch( CacheException ce ) {
|
||||
throw ce;
|
||||
}
|
||||
catch( Throwable t ) {
|
||||
throw new CacheException( "Unable to start region factory", t );
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Sets the cache factory.
|
||||
* @param cacheFactory the cache factory
|
||||
*/
|
||||
public void setCacheFactory(JBossCacheFactory factory) {
|
||||
this.jbcFactory = factory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the channel factory.
|
||||
*/
|
||||
public ChannelFactory getChannelFactory() {
|
||||
return channelFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the channel factory.
|
||||
*
|
||||
* @param factory the channel factory
|
||||
*/
|
||||
public void setChannelFactory(ChannelFactory factory) {
|
||||
this.channelFactory = factory;
|
||||
}
|
||||
|
||||
public MultiplexingCacheInstanceManager(Cache jbcEntityCache, Cache jbcCollectionCache, Cache jbcTsCache, Cache jbcQueryCache) {
|
||||
this.jbcEntityCache = jbcEntityCache;
|
||||
this.jbcCollectionCache = jbcCollectionCache;
|
||||
this.jbcTsCache = jbcTsCache;
|
||||
this.jbcQueryCache = jbcQueryCache;
|
||||
}
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public Cache getEntityCacheInstance() {
|
||||
return jbcEntityCache;
|
||||
}
|
||||
|
||||
protected Cache buildEntityRegionCacheInstance(Properties properties) {
|
||||
try {
|
||||
String configResource = PropertiesHelper.getString( ENTITY_CACHE_RESOURCE_PROP, properties, DEF_ENTITY_RESOURCE );
|
||||
return DefaultCacheFactory.getInstance().createCache( configResource );
|
||||
}
|
||||
catch( Throwable t ) {
|
||||
throw new CacheException( "unable to build entity region cache instance", t );
|
||||
}
|
||||
}
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public Cache getCollectionCacheInstance() {
|
||||
return jbcCollectionCache;
|
||||
}
|
||||
|
||||
protected Cache buildCollectionRegionCacheInstance(Properties properties) {
|
||||
try {
|
||||
String configResource = PropertiesHelper.getString( COLL_CACHE_RESOURCE_PROP, properties, DEF_COLL_RESOURCE );
|
||||
return DefaultCacheFactory.getInstance().createCache( configResource );
|
||||
}
|
||||
catch( Throwable t ) {
|
||||
throw new CacheException( "unable to build collection region cache instance", t );
|
||||
}
|
||||
}
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public Cache getQueryCacheInstance() {
|
||||
return jbcQueryCache;
|
||||
}
|
||||
|
||||
protected Cache buildTsRegionCacheInstance(Properties properties) {
|
||||
try {
|
||||
String configResource = PropertiesHelper.getString( TS_CACHE_RESOURCE_PROP, properties, DEF_TS_RESOURCE );
|
||||
return DefaultCacheFactory.getInstance().createCache( configResource );
|
||||
}
|
||||
catch( Throwable t ) {
|
||||
throw new CacheException( "unable to build timestamps region cache instance", t );
|
||||
}
|
||||
}
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public Cache getTimestampsCacheInstance() {
|
||||
return jbcTsCache;
|
||||
}
|
||||
|
||||
protected Cache buildQueryRegionCacheInstance(Properties properties) {
|
||||
try {
|
||||
String configResource = PropertiesHelper.getString( QUERY_CACHE_RESOURCE_PROP, properties, DEF_QUERY_RESOURCE );
|
||||
return DefaultCacheFactory.getInstance().createCache( configResource );
|
||||
}
|
||||
catch( Throwable t ) {
|
||||
throw new CacheException( "unable to build query region cache instance", t );
|
||||
}
|
||||
}
|
||||
/**
|
||||
* {@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));
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public Cache getEntityCacheInstance() {
|
||||
return jbcEntityCache;
|
||||
}
|
||||
// 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, DEF_MULTIPLEXER_RESOURCE);
|
||||
if (muxStacks != null) {
|
||||
channelFactory = new JChannelFactory();
|
||||
channelFactory.setMultiplexerConfig(muxStacks);
|
||||
}
|
||||
}
|
||||
|
||||
String factoryRes = PropertiesHelper.getString(CACHE_FACTORY_RESOURCE_PROP, properties, DEF_CACHE_FACTORY_RESOURCE);
|
||||
// FIXME use an impl from JBossCache
|
||||
jbcFactory = new JBossCacheFactoryImpl(factoryRes, channelFactory);
|
||||
((JBossCacheFactoryImpl) jbcFactory).start();
|
||||
selfCreatedFactory = true;
|
||||
}
|
||||
|
||||
if (settings.isSecondLevelCacheEnabled()) {
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public Cache getCollectionCacheInstance() {
|
||||
return jbcCollectionCache;
|
||||
}
|
||||
if (buildCaches) {
|
||||
entityConfig = PropertiesHelper
|
||||
.getString(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, 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public Cache getQueryCacheInstance() {
|
||||
return jbcQueryCache;
|
||||
}
|
||||
if (settings.isQueryCacheEnabled()) {
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public Cache getTimestampsCacheInstance() {
|
||||
return jbcTsCache;
|
||||
}
|
||||
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, 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, 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();
|
||||
}
|
||||
if (jbcTsCache != null) {
|
||||
configureTransactionManager(jbcTsCache, tm, true);
|
||||
jbcTsCache.start();
|
||||
}
|
||||
}
|
||||
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 release() {
|
||||
if ( jbcEntityCache != null ) {
|
||||
try {
|
||||
jbcEntityCache.stop();
|
||||
}
|
||||
catch( Throwable t ) {
|
||||
log.info( "Unable to stop entity cache instance", t );
|
||||
}
|
||||
}
|
||||
if ( jbcCollectionCache != null ) {
|
||||
try {
|
||||
jbcCollectionCache.stop();
|
||||
}
|
||||
catch( Throwable t ) {
|
||||
log.info( "Unable to stop collection cache instance", t );
|
||||
}
|
||||
}
|
||||
if ( jbcTsCache != null ) {
|
||||
try {
|
||||
jbcTsCache.stop();
|
||||
}
|
||||
catch( Throwable t ) {
|
||||
log.info( "Unable to stop timestamp cache instance", t );
|
||||
}
|
||||
}
|
||||
if ( jbcQueryCache != null ) {
|
||||
try {
|
||||
jbcQueryCache.stop();
|
||||
}
|
||||
catch( Throwable t ) {
|
||||
log.info( "Unable to stop query cache instance", t );
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public void stop() {
|
||||
releaseCaches();
|
||||
if (selfCreatedFactory) {
|
||||
((JBossCacheFactoryImpl) 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 a transaction manager ("
|
||||
+ cacheTm + ") that doesn't match 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)));
|
||||
}
|
||||
}
|
||||
|
|
247
cache-jbosscache2/src/main/java/org/hibernate/cache/jbc2/builder/SharedCacheInstanceManager.java
vendored
Normal file
247
cache-jbosscache2/src/main/java/org/hibernate/cache/jbc2/builder/SharedCacheInstanceManager.java
vendored
Normal file
|
@ -0,0 +1,247 @@
|
|||
/*
|
||||
* 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): Steve Ebersole
|
||||
*/
|
||||
package org.hibernate.cache.jbc2.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.jbc2.CacheInstanceManager;
|
||||
import org.hibernate.cache.jbc2.util.CacheHelper;
|
||||
import org.hibernate.cfg.Settings;
|
||||
import org.hibernate.util.PropertiesHelper;
|
||||
|
||||
/**
|
||||
* A {@link CacheInstanceManager} implementation where we use a single cache
|
||||
* instance we assume to be configured for invalidation if operating on a
|
||||
* cluster. Under that assumption, we can store all data into the same
|
||||
* {@link Cache} instance.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class SharedCacheInstanceManager implements CacheInstanceManager {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(SharedCacheInstanceManager.class);
|
||||
|
||||
/**
|
||||
* Classpath or filesystem resource identifying containing JBoss Cache
|
||||
* configuration settings the {@link Cache} should use.
|
||||
*
|
||||
* @see #DEFAULT_CACHE_RESOURCE
|
||||
*/
|
||||
public static final String 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 identifying containing JGroups protocol
|
||||
* stack configurations the <code>org.jgroups.ChannelFactory</code>
|
||||
* should use.
|
||||
*
|
||||
* @see #DEF_MULTIPLEXER_RESOURCE
|
||||
*/
|
||||
public static final String CHANNEL_FACTORY_RESOURCE_PROP = "hibernate.cache.region.jbc2.cfg.multiplexer.stacks";
|
||||
/**
|
||||
* Default value for {@link #CHANNEL_FACTORY_RESOURCE_PROP}. Specifies
|
||||
* "stacks.xml", which can be found in the root of the JGroups jar file.
|
||||
* Thus, leaving this value at default means using the default protocol
|
||||
* stack configs provided by JGroups.
|
||||
*/
|
||||
public static final String DEF_MULTIPLEXER_RESOURCE = "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, DEF_MULTIPLEXER_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
|
||||
* @param properties
|
||||
* @return
|
||||
*/
|
||||
protected Cache createSharedCache(Settings settings, Properties properties)
|
||||
{
|
||||
String configResource = PropertiesHelper.getString(CACHE_RESOURCE_PROP, properties, DEFAULT_CACHE_RESOURCE);
|
||||
return DefaultCacheFactory.getInstance().createCache(configResource, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Injects the TransactionManager found via {@link Settings#getTransactionManagerLookup()}
|
||||
* into the cache.
|
||||
*
|
||||
* @param cache
|
||||
* @param settings
|
||||
* @param 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) {
|
||||
throw new CacheException("JBoss Cache is already started " + "with a transaction manager ("
|
||||
+ cacheTm + ") that doesn't match 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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -16,6 +16,8 @@
|
|||
package org.hibernate.cache.jbc2.collection;
|
||||
|
||||
import org.jboss.cache.Cache;
|
||||
import org.jboss.cache.Fqn;
|
||||
import org.jboss.cache.config.Configuration.NodeLockingScheme;
|
||||
|
||||
import org.hibernate.cache.CacheDataDescription;
|
||||
import org.hibernate.cache.CacheException;
|
||||
|
@ -25,25 +27,35 @@ import org.hibernate.cache.access.CollectionRegionAccessStrategy;
|
|||
import org.hibernate.cache.jbc2.TransactionalDataRegionAdapter;
|
||||
|
||||
/**
|
||||
* Defines the behavior of the collection cache regions for JBossCache.
|
||||
*
|
||||
* Defines the behavior of the collection cache regions for JBossCache 2.x.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class CollectionRegionImpl extends TransactionalDataRegionAdapter implements CollectionRegion {
|
||||
public CollectionRegionImpl(Cache jbcCache, String regionName, CacheDataDescription metadata) {
|
||||
super( jbcCache, regionName, metadata );
|
||||
}
|
||||
|
||||
public CollectionRegionAccessStrategy buildAccessStrategy(AccessType accessType) throws CacheException {
|
||||
if ( AccessType.READ_ONLY.equals( accessType ) ) {
|
||||
return new ReadOnlyAccess( this );
|
||||
}
|
||||
if ( AccessType.TRANSACTIONAL.equals( accessType ) ) {
|
||||
return new TransactionalAccess( this );
|
||||
}
|
||||
public static final String TYPE = "COLL";
|
||||
private boolean optimistic;
|
||||
|
||||
// todo : add support for READ_WRITE ( + NONSTRICT_READ_WRITE ??? )
|
||||
public CollectionRegionImpl(Cache jbcCache, String regionName, String regionPrefix, CacheDataDescription metadata) {
|
||||
super(jbcCache, regionName, regionPrefix, metadata);
|
||||
optimistic = (jbcCache.getConfiguration().getNodeLockingScheme() == NodeLockingScheme.OPTIMISTIC);
|
||||
}
|
||||
|
||||
throw new CacheException( "unsupported access type [" + accessType.getName() + "]" );
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
64
cache-jbosscache2/src/main/java/org/hibernate/cache/jbc2/collection/OptimisticReadOnlyAccess.java
vendored
Executable file
64
cache-jbosscache2/src/main/java/org/hibernate/cache/jbc2/collection/OptimisticReadOnlyAccess.java
vendored
Executable file
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* 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.jbc2.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
|
||||
*/
|
||||
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");
|
||||
}
|
||||
}
|
42
cache-jbosscache2/src/main/java/org/hibernate/cache/jbc2/collection/OptimisticTransactionalAccess.java
vendored
Executable file
42
cache-jbosscache2/src/main/java/org/hibernate/cache/jbc2/collection/OptimisticTransactionalAccess.java
vendored
Executable file
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* 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.jbc2.collection;
|
||||
|
||||
import org.hibernate.cache.jbc2.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
|
||||
*/
|
||||
public OptimisticTransactionalAccess(CollectionRegionImpl region) {
|
||||
|
||||
// We use a different delegate than the non-optimistic superclass default
|
||||
super(region, new OptimisticTransactionalAccessDelegate(region.getCacheInstance(), region.getRegionFqn(),
|
||||
region.getCacheDataDescription()));
|
||||
}
|
||||
|
||||
}
|
|
@ -22,50 +22,37 @@ 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.
|
||||
*
|
||||
* 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 );
|
||||
private static final Logger log = LoggerFactory.getLogger(ReadOnlyAccess.class);
|
||||
|
||||
public ReadOnlyAccess(CollectionRegionImpl region) {
|
||||
super( region );
|
||||
}
|
||||
public ReadOnlyAccess(CollectionRegionImpl region) {
|
||||
super(region);
|
||||
}
|
||||
|
||||
public SoftLock lockItem(Object key, Object version) throws CacheException {
|
||||
throw new UnsupportedOperationException( "Illegal attempt to edit read only item" );
|
||||
}
|
||||
@Override
|
||||
public SoftLock lockItem(Object key, Object version) throws CacheException {
|
||||
throw new UnsupportedOperationException("Illegal attempt to edit read only item");
|
||||
}
|
||||
|
||||
public SoftLock lockRegion() throws CacheException {
|
||||
throw new UnsupportedOperationException( "Illegal attempt to edit read only region" );
|
||||
}
|
||||
@Override
|
||||
public SoftLock lockRegion() throws CacheException {
|
||||
throw new UnsupportedOperationException("Illegal attempt to edit read only region");
|
||||
}
|
||||
|
||||
public void unlockItem(Object key, SoftLock lock) throws CacheException {
|
||||
log.error( "Illegal attempt to edit read only item" );
|
||||
}
|
||||
@Override
|
||||
public void unlockItem(Object key, SoftLock lock) throws CacheException {
|
||||
log.error("Illegal attempt to edit read only item");
|
||||
}
|
||||
|
||||
public void unlockRegion(SoftLock lock) throws CacheException {
|
||||
log.error( "Illegal attempt to edit read only region" );
|
||||
}
|
||||
|
||||
public boolean update(
|
||||
Object key,
|
||||
Object value,
|
||||
Object currentVersion,
|
||||
Object previousVersion) throws CacheException {
|
||||
throw new UnsupportedOperationException( "Illegal attempt to edit read only item" );
|
||||
}
|
||||
|
||||
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" );
|
||||
}
|
||||
@Override
|
||||
public void unlockRegion(SoftLock lock) throws CacheException {
|
||||
log.error("Illegal attempt to edit read only region");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,68 +15,100 @@
|
|||
*/
|
||||
package org.hibernate.cache.jbc2.collection;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
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.CollectionRegion;
|
||||
import org.hibernate.cache.CacheException;
|
||||
import org.hibernate.cache.jbc2.access.TransactionalAccessDelegate;
|
||||
|
||||
/**
|
||||
* todo : implement
|
||||
*
|
||||
* 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 static final Logger log = LoggerFactory.getLogger( TransactionalAccess.class );
|
||||
|
||||
private final CollectionRegionImpl region;
|
||||
private final CollectionRegionImpl region;
|
||||
|
||||
public TransactionalAccess(CollectionRegionImpl region) {
|
||||
this.region = 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 CollectionRegion getRegion() {
|
||||
return region;
|
||||
}
|
||||
/**
|
||||
* Create a new TransactionalAccess.
|
||||
*
|
||||
* @param region
|
||||
*/
|
||||
public TransactionalAccess(CollectionRegionImpl region) {
|
||||
this(region, new TransactionalAccessDelegate(region.getCacheInstance(), region.getRegionFqn()));
|
||||
}
|
||||
|
||||
public Object get(Object key, long txTimestamp) throws CacheException {
|
||||
return null;
|
||||
}
|
||||
/**
|
||||
* Allow subclasses to define the delegate.
|
||||
*
|
||||
* @param region
|
||||
* @param delegate
|
||||
*/
|
||||
protected TransactionalAccess(CollectionRegionImpl region, TransactionalAccessDelegate delegate) {
|
||||
this.region = region;
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
public boolean putFromLoad(Object key, Object value, long txTimestamp, Object version) throws CacheException {
|
||||
return false;
|
||||
}
|
||||
public CollectionRegion getRegion() {
|
||||
return region;
|
||||
}
|
||||
|
||||
public boolean putFromLoad(Object key, Object value, long txTimestamp, Object version, boolean minimalPutOverride)
|
||||
throws CacheException {
|
||||
return false;
|
||||
}
|
||||
public Object get(Object key, long txTimestamp) throws CacheException {
|
||||
|
||||
public SoftLock lockItem(Object key, Object version) throws CacheException {
|
||||
return null;
|
||||
}
|
||||
return delegate.get(key, txTimestamp);
|
||||
}
|
||||
|
||||
public SoftLock lockRegion() throws CacheException {
|
||||
return null;
|
||||
}
|
||||
public boolean putFromLoad(Object key, Object value, long txTimestamp, Object version) throws CacheException {
|
||||
|
||||
public void unlockItem(Object key, SoftLock lock) throws CacheException {
|
||||
}
|
||||
return delegate.putFromLoad(key, value, txTimestamp, version);
|
||||
}
|
||||
|
||||
public void unlockRegion(SoftLock lock) throws CacheException {
|
||||
}
|
||||
public boolean putFromLoad(Object key, Object value, long txTimestamp, Object version, boolean minimalPutOverride)
|
||||
throws CacheException {
|
||||
|
||||
public void remove(Object key) throws CacheException {
|
||||
}
|
||||
return delegate.putFromLoad(key, value, txTimestamp, version, minimalPutOverride);
|
||||
}
|
||||
|
||||
public void removeAll() throws CacheException {
|
||||
}
|
||||
public void remove(Object key) throws CacheException {
|
||||
|
||||
public void evict(Object key) throws CacheException {
|
||||
}
|
||||
delegate.remove(key);
|
||||
}
|
||||
|
||||
public void evictAll() throws CacheException {
|
||||
}
|
||||
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 {
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
package org.hibernate.cache.jbc2.entity;
|
||||
|
||||
import org.jboss.cache.Cache;
|
||||
import org.jboss.cache.Fqn;
|
||||
import org.jboss.cache.config.Configuration.NodeLockingScheme;
|
||||
|
||||
import org.hibernate.cache.CacheDataDescription;
|
||||
import org.hibernate.cache.CacheException;
|
||||
|
@ -26,28 +28,39 @@ import org.hibernate.cache.jbc2.TransactionalDataRegionAdapter;
|
|||
|
||||
/**
|
||||
* Defines the behavior of the entity cache regions for JBossCache.
|
||||
*
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class EntityRegionImpl extends TransactionalDataRegionAdapter implements EntityRegion {
|
||||
|
||||
public EntityRegionImpl(Cache jbcCache, String regionName, CacheDataDescription metadata) {
|
||||
super( jbcCache, regionName, metadata );
|
||||
}
|
||||
public static final String TYPE = "ENTITY";
|
||||
|
||||
private boolean optimistic;
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public EntityRegionAccessStrategy buildAccessStrategy(AccessType accessType) throws CacheException {
|
||||
if ( AccessType.READ_ONLY.equals( accessType ) ) {
|
||||
return new ReadOnlyAccess( this );
|
||||
}
|
||||
if ( AccessType.TRANSACTIONAL.equals( accessType ) ) {
|
||||
return new TransactionalAccess( this );
|
||||
}
|
||||
public EntityRegionImpl(Cache jbcCache, String regionName, String regionPrefix, CacheDataDescription metadata) {
|
||||
super(jbcCache, regionName, regionPrefix, metadata);
|
||||
optimistic = (jbcCache.getConfiguration().getNodeLockingScheme() == NodeLockingScheme.OPTIMISTIC);
|
||||
}
|
||||
|
||||
// todo : add support for READ_WRITE ( + NONSTRICT_READ_WRITE ??? )
|
||||
/**
|
||||
* {@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);
|
||||
}
|
||||
|
||||
throw new CacheException( "unsupported access type [" + accessType.getName() + "]" );
|
||||
}
|
||||
}
|
||||
|
|
70
cache-jbosscache2/src/main/java/org/hibernate/cache/jbc2/entity/OptimisticReadOnlyAccess.java
vendored
Executable file
70
cache-jbosscache2/src/main/java/org/hibernate/cache/jbc2/entity/OptimisticReadOnlyAccess.java
vendored
Executable file
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* 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): Steve Ebersole
|
||||
*/
|
||||
package org.hibernate.cache.jbc2.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");
|
||||
}
|
||||
}
|
39
cache-jbosscache2/src/main/java/org/hibernate/cache/jbc2/entity/OptimisticTransactionalAccess.java
vendored
Executable file
39
cache-jbosscache2/src/main/java/org/hibernate/cache/jbc2/entity/OptimisticTransactionalAccess.java
vendored
Executable file
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* 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.jbc2.entity;
|
||||
|
||||
import org.hibernate.cache.jbc2.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
|
||||
*/
|
||||
public OptimisticTransactionalAccess(EntityRegionImpl region) {
|
||||
super(region, new OptimisticTransactionalAccessDelegate(region.getCacheInstance(), region.getRegionFqn(),
|
||||
region.getCacheDataDescription()));
|
||||
}
|
||||
}
|
|
@ -22,50 +22,49 @@ 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.
|
||||
*
|
||||
* 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 );
|
||||
private static final Logger log = LoggerFactory.getLogger(ReadOnlyAccess.class);
|
||||
|
||||
public ReadOnlyAccess(EntityRegionImpl region) {
|
||||
super( region );
|
||||
}
|
||||
public ReadOnlyAccess(EntityRegionImpl region) {
|
||||
super(region);
|
||||
}
|
||||
|
||||
public SoftLock lockItem(Object key, Object version) throws CacheException {
|
||||
throw new UnsupportedOperationException( "Illegal attempt to edit read only item" );
|
||||
}
|
||||
@Override
|
||||
public SoftLock lockItem(Object key, Object version) throws CacheException {
|
||||
throw new UnsupportedOperationException("Illegal attempt to edit read only item");
|
||||
}
|
||||
|
||||
public SoftLock lockRegion() throws CacheException {
|
||||
throw new UnsupportedOperationException( "Illegal attempt to edit read only region" );
|
||||
}
|
||||
@Override
|
||||
public SoftLock lockRegion() throws CacheException {
|
||||
throw new UnsupportedOperationException("Illegal attempt to edit read only region");
|
||||
}
|
||||
|
||||
public void unlockItem(Object key, SoftLock lock) throws CacheException {
|
||||
log.error( "Illegal attempt to edit read only item" );
|
||||
}
|
||||
@Override
|
||||
public void unlockItem(Object key, SoftLock lock) throws CacheException {
|
||||
log.error("Illegal attempt to edit read only item");
|
||||
}
|
||||
|
||||
public void unlockRegion(SoftLock lock) throws CacheException {
|
||||
log.error( "Illegal attempt to edit read only region" );
|
||||
}
|
||||
@Override
|
||||
public void unlockRegion(SoftLock lock) throws CacheException {
|
||||
log.error("Illegal attempt to edit read only region");
|
||||
}
|
||||
|
||||
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 update(Object key, Object value, Object currentVersion, Object previousVersion)
|
||||
throws CacheException {
|
||||
throw new UnsupportedOperationException("Illegal attempt to edit read only item");
|
||||
}
|
||||
|
||||
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" );
|
||||
}
|
||||
@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");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,145 +15,108 @@
|
|||
*/
|
||||
package org.hibernate.cache.jbc2.entity;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.jboss.cache.Fqn;
|
||||
import org.jboss.cache.lock.TimeoutException;
|
||||
|
||||
import org.hibernate.cache.access.EntityRegionAccessStrategy;
|
||||
import org.hibernate.cache.access.SoftLock;
|
||||
import org.hibernate.cache.jbc2.access.TransactionalAccessDelegate;
|
||||
import org.hibernate.cache.EntityRegion;
|
||||
import org.hibernate.cache.CacheException;
|
||||
|
||||
/**
|
||||
* This defines the strategy for transactional access to enity data
|
||||
* in JBossCache using its 2.x APIs
|
||||
*
|
||||
* 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 {
|
||||
private static final Logger log = LoggerFactory.getLogger( TransactionalAccess.class );
|
||||
|
||||
private final EntityRegionImpl region;
|
||||
protected final EntityRegionImpl region;
|
||||
|
||||
public TransactionalAccess(EntityRegionImpl region) {
|
||||
this.region = 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 EntityRegion getRegion() {
|
||||
return region;
|
||||
}
|
||||
public TransactionalAccess(EntityRegionImpl region) {
|
||||
this(region, new TransactionalAccessDelegate(region.getCacheInstance(), region.getRegionFqn()));
|
||||
}
|
||||
|
||||
public Object get(Object key, long txTimestamp) throws CacheException {
|
||||
try {
|
||||
return region.getCacheInstance().get( region.getRegionFqn(), EntityRegionImpl.ITEM );
|
||||
}
|
||||
catch ( Exception e ) {
|
||||
throw new CacheException( e );
|
||||
}
|
||||
}
|
||||
protected TransactionalAccess(EntityRegionImpl region, TransactionalAccessDelegate delegate) {
|
||||
this.region = region;
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
public boolean putFromLoad(
|
||||
Object key,
|
||||
Object value,
|
||||
long txTimestamp,
|
||||
Object version) throws CacheException {
|
||||
try {
|
||||
region.getCacheInstance().putForExternalRead( new Fqn( region.getRegionFqn(), key ), EntityRegionImpl.ITEM, value );
|
||||
return true;
|
||||
}
|
||||
catch ( TimeoutException te) {
|
||||
//ignore!
|
||||
log.debug( "ignoring write lock acquisition failure" );
|
||||
return false;
|
||||
}
|
||||
catch ( Throwable t ) {
|
||||
throw new CacheException( t );
|
||||
}
|
||||
}
|
||||
public EntityRegion getRegion() {
|
||||
return region;
|
||||
}
|
||||
|
||||
public boolean putFromLoad(
|
||||
Object key,
|
||||
Object value,
|
||||
long txTimestamp,
|
||||
Object version,
|
||||
boolean minimalPutOverride) throws CacheException {
|
||||
if ( minimalPutOverride && get( key, txTimestamp ) != null ) {
|
||||
if ( log.isDebugEnabled() ) {
|
||||
log.debug( "item already cached: " + key );
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return putFromLoad( key, value, txTimestamp, version );
|
||||
}
|
||||
public Object get(Object key, long txTimestamp) throws CacheException {
|
||||
|
||||
public SoftLock lockItem(Object key, Object version) throws CacheException {
|
||||
return null;
|
||||
}
|
||||
return delegate.get(key, txTimestamp);
|
||||
}
|
||||
|
||||
public SoftLock lockRegion() throws CacheException {
|
||||
return null;
|
||||
}
|
||||
public boolean putFromLoad(Object key, Object value, long txTimestamp, Object version) throws CacheException {
|
||||
|
||||
public void unlockItem(Object key, SoftLock lock) throws CacheException {
|
||||
}
|
||||
return delegate.putFromLoad(key, value, txTimestamp, version);
|
||||
}
|
||||
|
||||
public void unlockRegion(SoftLock lock) throws CacheException {
|
||||
}
|
||||
public boolean putFromLoad(Object key, Object value, long txTimestamp, Object version, boolean minimalPutOverride)
|
||||
throws CacheException {
|
||||
|
||||
public boolean insert(Object key, Object value, Object version) throws CacheException {
|
||||
try {
|
||||
region.getCacheInstance().put( new Fqn( region.getRegionFqn(), key ), EntityRegionImpl.ITEM, value );
|
||||
}
|
||||
catch ( Throwable t ) {
|
||||
throw new CacheException( t );
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return delegate.putFromLoad(key, value, txTimestamp, version, minimalPutOverride);
|
||||
}
|
||||
|
||||
public boolean afterInsert(Object key, Object value, Object version) throws CacheException {
|
||||
return false;
|
||||
}
|
||||
public boolean insert(Object key, Object value, Object version) throws CacheException {
|
||||
|
||||
public boolean update(Object key, Object value, Object currentVersion, Object previousVersion)
|
||||
throws CacheException {
|
||||
try {
|
||||
region.getCacheInstance().put( new Fqn( region.getRegionFqn(), key ), EntityRegionImpl.ITEM, value );
|
||||
}
|
||||
catch ( Throwable t ) {
|
||||
throw new CacheException( t );
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return delegate.insert(key, value, version);
|
||||
}
|
||||
|
||||
public boolean afterUpdate(Object key, Object value, Object currentVersion, Object previousVersion, SoftLock lock)
|
||||
throws CacheException {
|
||||
return false;
|
||||
}
|
||||
public boolean update(Object key, Object value, Object currentVersion, Object previousVersion)
|
||||
throws CacheException {
|
||||
|
||||
public void remove(Object key) throws CacheException {
|
||||
try {
|
||||
region.getCacheInstance().removeNode( new Fqn( region.getRegionFqn(), key ) );
|
||||
}
|
||||
catch ( Exception e ) {
|
||||
throw new CacheException( e );
|
||||
}
|
||||
}
|
||||
return delegate.update(key, value, currentVersion, previousVersion);
|
||||
}
|
||||
|
||||
public void removeAll() throws CacheException {
|
||||
try {
|
||||
region.getCacheInstance().removeNode( region.getRegionFqn() );
|
||||
}
|
||||
catch ( Exception e ) {
|
||||
throw new CacheException( e );
|
||||
}
|
||||
}
|
||||
public void remove(Object key) throws CacheException {
|
||||
|
||||
public void evict(Object key) throws CacheException {
|
||||
remove( key );
|
||||
}
|
||||
delegate.remove(key);
|
||||
}
|
||||
|
||||
public void evictAll() throws CacheException {
|
||||
removeAll();
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
124
cache-jbosscache2/src/main/java/org/hibernate/cache/jbc2/query/QueryResultsRegionImpl.java
vendored
Normal file
124
cache-jbosscache2/src/main/java/org/hibernate/cache/jbc2/query/QueryResultsRegionImpl.java
vendored
Normal file
|
@ -0,0 +1,124 @@
|
|||
/*
|
||||
* 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.jbc2.query;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import org.hibernate.cache.CacheException;
|
||||
import org.hibernate.cache.QueryResultsRegion;
|
||||
import org.hibernate.cache.jbc2.TransactionalDataRegionAdapter;
|
||||
import org.hibernate.cache.jbc2.util.CacheHelper;
|
||||
import org.hibernate.util.PropertiesHelper;
|
||||
import org.jboss.cache.Cache;
|
||||
import org.jboss.cache.Fqn;
|
||||
import org.jboss.cache.config.Option;
|
||||
|
||||
/**
|
||||
* Defines the behavior of the query cache regions for JBossCache 2.x.
|
||||
*
|
||||
* @author Brian Stansberry
|
||||
* @version $Revision$
|
||||
*/
|
||||
public class QueryResultsRegionImpl extends TransactionalDataRegionAdapter implements QueryResultsRegion {
|
||||
|
||||
public static final String QUERY_CACHE_LOCAL_ONLY_PROP = "hibernate.cache.region.jbc2.query.localonly";
|
||||
|
||||
|
||||
/**
|
||||
* Whether we should set an option to disable propagation of changes around
|
||||
* cluster.
|
||||
*/
|
||||
private boolean localOnly;
|
||||
|
||||
/**
|
||||
* Create a new QueryResultsRegionImpl.
|
||||
*
|
||||
* @param jbcCache
|
||||
* @param regionName
|
||||
* @param regionPrefix
|
||||
* TODO
|
||||
*/
|
||||
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
|
||||
localOnly = CacheHelper.isClusteredReplication(jbcCache)
|
||||
&& PropertiesHelper.getBoolean(QUERY_CACHE_LOCAL_ONLY_PROP, properties, false);
|
||||
}
|
||||
}
|
||||
|
||||
public void evict(Object key) throws CacheException {
|
||||
Option opt = getNonLockingDataVersionOption(false);
|
||||
if (localOnly)
|
||||
opt.setCacheModeLocal(true);
|
||||
CacheHelper.remove(getCacheInstance(), getRegionFqn(), key, opt);
|
||||
}
|
||||
|
||||
public void evictAll() throws CacheException {
|
||||
Option opt = getNonLockingDataVersionOption(false);
|
||||
if (localOnly)
|
||||
opt.setCacheModeLocal(true);
|
||||
CacheHelper.removeAll(getCacheInstance(), getRegionFqn(), opt);
|
||||
}
|
||||
|
||||
public Object get(Object key) throws CacheException {
|
||||
|
||||
// Don't hold the JBC node lock throughout the tx, as that
|
||||
// prevents updates
|
||||
// Add a zero (or low) timeout option so we don't block
|
||||
// waiting for tx's that did a put to commit
|
||||
Option opt = new Option();
|
||||
opt.setLockAcquisitionTimeout(0);
|
||||
return suspendAndGet(key, opt, true);
|
||||
}
|
||||
|
||||
public void put(Object key, Object value) throws CacheException {
|
||||
|
||||
// Here we don't want to suspend the tx. If we do:
|
||||
// 1) We might be caching query results that reflect uncommitted
|
||||
// changes. No tx == no WL on cache node, so other threads
|
||||
// can prematurely see those query results
|
||||
// 2) No tx == immediate replication. More overhead, plus we
|
||||
// spread issue #1 above around the cluster
|
||||
|
||||
// Add a zero (or quite low) timeout option so we don't block
|
||||
// Ignore any TimeoutException. Basically we forego caching the
|
||||
// query result in order to avoid blocking for concurrent reads.
|
||||
// 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 Fqn.fromString(escapeRegionName(regionName, regionPrefix));
|
||||
}
|
||||
|
||||
}
|
207
cache-jbosscache2/src/main/java/org/hibernate/cache/jbc2/timestamp/TimestampsRegionImpl.java
vendored
Normal file
207
cache-jbosscache2/src/main/java/org/hibernate/cache/jbc2/timestamp/TimestampsRegionImpl.java
vendored
Normal file
|
@ -0,0 +1,207 @@
|
|||
/*
|
||||
* 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.jbc2.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.jbc2.TransactionalDataRegionAdapter;
|
||||
import org.hibernate.cache.jbc2.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.event.NodeModifiedEvent;
|
||||
|
||||
/**
|
||||
* Defines the behavior of the timestamps cache region for JBossCache 2.x.
|
||||
* <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 an increase in the timestamp. This approach allows
|
||||
* timestamp changes to be replicated asynchronously by JBoss Cache while still
|
||||
* preventing backward changes in timestamps.
|
||||
* </p>
|
||||
*
|
||||
* @author Brian Stansberry
|
||||
* @version $Revision$
|
||||
*/
|
||||
@CacheListener
|
||||
public class TimestampsRegionImpl extends TransactionalDataRegionAdapter implements TimestampsRegion {
|
||||
|
||||
public static final String TYPE = "TS";
|
||||
|
||||
private final Map localCache = new ConcurrentHashMap();
|
||||
|
||||
/**
|
||||
* Create a new TimestampsRegionImpl.
|
||||
*
|
||||
* @param jbcCache
|
||||
* @param regionName
|
||||
* @param regionPrefix
|
||||
* TODO
|
||||
* @param metadata
|
||||
*/
|
||||
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 {
|
||||
// TODO Is this a valid operation on a timestamps cache?
|
||||
localCache.remove(key);
|
||||
Option opt = getNonLockingDataVersionOption(true);
|
||||
CacheHelper.remove(getCacheInstance(), getRegionFqn(), key, opt);
|
||||
}
|
||||
|
||||
public void evictAll() throws CacheException {
|
||||
// TODO Is this a valid operation on a timestamps cache?
|
||||
localCache.clear();
|
||||
Option opt = getNonLockingDataVersionOption(true);
|
||||
CacheHelper.removeAll(getCacheInstance(), getRegionFqn(), opt);
|
||||
}
|
||||
|
||||
public Object get(Object key) throws CacheException {
|
||||
|
||||
Object timestamp = localCache.get(key);
|
||||
if (timestamp == null) {
|
||||
// Check the cluster-wide cache
|
||||
// Don't hold the cache node lock throughout the tx, as that
|
||||
// prevents updates
|
||||
timestamp = suspendAndGet(key, null, false);
|
||||
updateLocalCache(key, timestamp);
|
||||
}
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
public void put(Object key, Object value) throws CacheException {
|
||||
|
||||
// Immediately update the local cache
|
||||
boolean incremented = updateLocalCache(key, value);
|
||||
|
||||
if (incremented) {
|
||||
// Now the cluster-wide cache
|
||||
|
||||
// TODO there's a race here where 2 threads can get through
|
||||
// updateLocalCache() in proper sequence but then the earlier
|
||||
// one updates JBC *later*. This should only affect newly
|
||||
// joined nodes who populate their initial localCache from JBC.
|
||||
|
||||
// Don't hold the JBC node lock throughout the tx, as that
|
||||
// prevents reads and other updates
|
||||
Transaction tx = suspend();
|
||||
try {
|
||||
// We ensure ASYNC semantics (JBCACHE-1175)
|
||||
Option opt = getNonLockingDataVersionOption(false);
|
||||
opt.setForceAsynchronous(true);
|
||||
getCacheInstance().getInvocationContext().setOptionOverrides(opt);
|
||||
getCacheInstance().put(new Fqn(regionFqn, key), ITEM, value);
|
||||
} 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 (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());
|
||||
updateLocalCache(key, event.getData().get(ITEM));
|
||||
}
|
||||
}
|
||||
|
||||
private void populateLocalCache() {
|
||||
Set children = CacheHelper.getChildrenNames(getCacheInstance(), getRegionFqn());
|
||||
for (Object key : children) {
|
||||
get(key);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the local cache, ensuring that the new value represents a higher
|
||||
* value than the old (i.e. timestamp never goes back in time).
|
||||
*
|
||||
* @param key
|
||||
* @param value
|
||||
*/
|
||||
private boolean updateLocalCache(Object key, Object value) {
|
||||
if (value == null)
|
||||
return false;
|
||||
|
||||
boolean increase = true;
|
||||
|
||||
long newVal = 0;
|
||||
try {
|
||||
newVal = ((Long) value).longValue();
|
||||
|
||||
Long oldVal = (Long) localCache.get(key);
|
||||
increase = oldVal == null || newVal > oldVal.longValue();
|
||||
if (increase) {
|
||||
oldVal = (Long) localCache.put(key, value);
|
||||
// Double check that it was an increase
|
||||
if (oldVal != null && oldVal.longValue() > newVal) {
|
||||
// Nope; Restore the old value
|
||||
increase = updateLocalCache(key, oldVal);
|
||||
}
|
||||
}
|
||||
} catch (ClassCastException cce) {
|
||||
// TODO -- this is stupid; look into changing TimestampsRegion API
|
||||
// not using Long; just store it
|
||||
localCache.put(key, value);
|
||||
}
|
||||
|
||||
return increase;
|
||||
|
||||
}
|
||||
|
||||
}
|
441
cache-jbosscache2/src/main/java/org/hibernate/cache/jbc2/util/CacheHelper.java
vendored
Normal file
441
cache-jbosscache2/src/main/java/org/hibernate/cache/jbc2/util/CacheHelper.java
vendored
Normal file
|
@ -0,0 +1,441 @@
|
|||
/*
|
||||
* 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): Steve Ebersole
|
||||
*/
|
||||
package org.hibernate.cache.jbc2.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 {
|
||||
|
||||
/** 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);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
|
@ -1,54 +0,0 @@
|
|||
/*
|
||||
* 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): Steve Ebersole
|
||||
*/
|
||||
package org.hibernate.cache.jbc2.util;
|
||||
|
||||
import org.jboss.cache.Cache;
|
||||
import org.jboss.cache.config.Configuration;
|
||||
|
||||
/**
|
||||
* Helper for dealing with JBossCache {@link Configuration.CacheMode}.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class CacheModeHelper {
|
||||
/**
|
||||
* Disallow external instantiation of CacheModeHelper.
|
||||
*/
|
||||
private CacheModeHelper() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.REPL_ASYNC || cacheMode == Configuration.CacheMode.REPL_SYNC;
|
||||
}
|
||||
}
|
47
cache-jbosscache2/src/main/java/org/hibernate/cache/jbc2/util/CircumventChecksDataVersion.java
vendored
Executable file
47
cache-jbosscache2/src/main/java/org/hibernate/cache/jbc2/util/CircumventChecksDataVersion.java
vendored
Executable file
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* 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.jbc2.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@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");
|
||||
}
|
||||
|
||||
}
|
152
cache-jbosscache2/src/main/java/org/hibernate/cache/jbc2/util/DataVersionAdapter.java
vendored
Executable file
152
cache-jbosscache2/src/main/java/org/hibernate/cache/jbc2/util/DataVersionAdapter.java
vendored
Executable file
|
@ -0,0 +1,152 @@
|
|||
/*
|
||||
* 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.jbc2.util;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Comparator;
|
||||
|
||||
import org.hibernate.cache.jbc2.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@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) {
|
||||
if (((DefaultDataVersion) dataVersion).getRawVersion() == 0) {
|
||||
// JBC put a version in the node when it created it as
|
||||
// part of building a larger tree
|
||||
return true;
|
||||
} else {
|
||||
log.error("Cannot compare to " + dataVersion);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
59
cache-jbosscache2/src/main/java/org/hibernate/cache/jbc2/util/NonLockingDataVersion.java
vendored
Executable file
59
cache-jbosscache2/src/main/java/org/hibernate/cache/jbc2/util/NonLockingDataVersion.java
vendored
Executable file
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* 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.jbc2.util;
|
||||
|
||||
import org.hibernate.cache.jbc2.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@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;
|
||||
// }
|
||||
}
|
||||
|
||||
}
|
BIN
cache-jbosscache2/src/main/resources/org/hibernate/cache/jbc2/builder/jbc2-configs.xml
vendored
Normal file
BIN
cache-jbosscache2/src/main/resources/org/hibernate/cache/jbc2/builder/jbc2-configs.xml
vendored
Normal file
Binary file not shown.
|
@ -0,0 +1,140 @@
|
|||
/*
|
||||
* 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.test.cache.jbc2;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import org.hibernate.cache.CacheDataDescription;
|
||||
import org.hibernate.cache.RegionFactory;
|
||||
import org.hibernate.cache.TransactionalDataRegion;
|
||||
import org.hibernate.cache.access.AccessType;
|
||||
import org.hibernate.cache.jbc2.JBossCacheRegionFactory;
|
||||
import org.hibernate.cache.jbc2.MultiplexedJBossCacheRegionFactory;
|
||||
import org.hibernate.cache.jbc2.SharedJBossCacheRegionFactory;
|
||||
import org.hibernate.cache.jbc2.builder.MultiplexingCacheInstanceManager;
|
||||
import org.hibernate.cache.jbc2.builder.SharedCacheInstanceManager;
|
||||
import org.hibernate.cfg.Configuration;
|
||||
import org.hibernate.cfg.Environment;
|
||||
import org.hibernate.test.util.CacheTestUtil;
|
||||
|
||||
/**
|
||||
* Base class for tests of EntityRegion and CollectionRegion implementations.
|
||||
*
|
||||
* @author <a href="brian.stansberry@jboss.com">Brian Stansberry</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public abstract class AbstractEntityCollectionRegionTestCase extends AbstractRegionImplTestCase {
|
||||
|
||||
/**
|
||||
* Create a new EntityCollectionRegionTestCaseBase.
|
||||
*
|
||||
* @param name
|
||||
*/
|
||||
public AbstractEntityCollectionRegionTestCase(String name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Region backed by an OPTIMISTIC locking JBoss Cache, and then
|
||||
* ensure that it handles calls to buildAccessStrategy as expected when
|
||||
* all the various {@link AccessType}s are passed as arguments.
|
||||
*/
|
||||
public void testSupportedAccessTypesOptimistic() throws Exception {
|
||||
|
||||
supportedAccessTypeTest(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a Region backed by an PESSIMISTIC locking JBoss Cache, and then
|
||||
* ensures that it handles calls to buildAccessStrategy as expected when
|
||||
* all the various {@link AccessType}s are passed as arguments.
|
||||
*/
|
||||
public void testSupportedAccessTypesPessimistic() throws Exception {
|
||||
|
||||
supportedAccessTypeTest(false);
|
||||
}
|
||||
|
||||
private void supportedAccessTypeTest(boolean optimistic) throws Exception {
|
||||
|
||||
Configuration cfg = CacheTestUtil.buildConfiguration("test", MultiplexedJBossCacheRegionFactory.class, true, false);
|
||||
String entityCfg = optimistic ? "optimistic-entity" : "pessimistic-entity";
|
||||
cfg.setProperty(MultiplexingCacheInstanceManager.ENTITY_CACHE_RESOURCE_PROP, entityCfg);
|
||||
|
||||
JBossCacheRegionFactory regionFactory = CacheTestUtil.startRegionFactory(cfg, getCacheTestSupport());
|
||||
|
||||
supportedAccessTypeTest(regionFactory, cfg.getProperties());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a Region using the given factory, and then ensure that it
|
||||
* handles calls to buildAccessStrategy as expected when all the
|
||||
* various {@link AccessType}s are passed as arguments.
|
||||
*/
|
||||
protected abstract void supportedAccessTypeTest(RegionFactory regionFactory, Properties properties);
|
||||
|
||||
/**
|
||||
* Test that the Region properly implements
|
||||
* {@link TransactionalDataRegion#isTransactionAware()}.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public void testIsTransactionAware() throws Exception {
|
||||
|
||||
Configuration cfg = CacheTestUtil.buildConfiguration("test", SharedJBossCacheRegionFactory.class, true, false);
|
||||
cfg.setProperty(SharedCacheInstanceManager.CACHE_RESOURCE_PROP, CacheTestUtil.LOCAL_PESSIMISTIC_CACHE);
|
||||
|
||||
JBossCacheRegionFactory regionFactory = CacheTestUtil.startRegionFactory(cfg, getCacheTestSupport());
|
||||
|
||||
TransactionalDataRegion region = (TransactionalDataRegion) createRegion(regionFactory, "test/test", cfg.getProperties(), getCacheDataDescription());
|
||||
|
||||
assertTrue("Region is transaction-aware", region.isTransactionAware());
|
||||
|
||||
CacheTestUtil.stopRegionFactory(regionFactory, getCacheTestSupport());
|
||||
|
||||
cfg = CacheTestUtil.buildConfiguration("test", SharedJBossCacheRegionFactory.class, true, false);
|
||||
cfg.setProperty(SharedCacheInstanceManager.CACHE_RESOURCE_PROP, CacheTestUtil.LOCAL_PESSIMISTIC_CACHE);
|
||||
// Make it non-transactional
|
||||
cfg.getProperties().remove(Environment.TRANSACTION_MANAGER_STRATEGY);
|
||||
|
||||
regionFactory = CacheTestUtil.startRegionFactory(cfg, getCacheTestSupport());
|
||||
|
||||
region = (TransactionalDataRegion) createRegion(regionFactory, "test/test", cfg.getProperties(), getCacheDataDescription());
|
||||
|
||||
assertFalse("Region is not transaction-aware", region.isTransactionAware());
|
||||
|
||||
CacheTestUtil.stopRegionFactory(regionFactory, getCacheTestSupport());
|
||||
}
|
||||
|
||||
public void testGetCacheDataDescription() throws Exception {
|
||||
Configuration cfg = CacheTestUtil.buildConfiguration("test", SharedJBossCacheRegionFactory.class, true, false);
|
||||
cfg.setProperty(SharedCacheInstanceManager.CACHE_RESOURCE_PROP, CacheTestUtil.LOCAL_PESSIMISTIC_CACHE);
|
||||
|
||||
JBossCacheRegionFactory regionFactory = CacheTestUtil.startRegionFactory(cfg, getCacheTestSupport());
|
||||
|
||||
TransactionalDataRegion region = (TransactionalDataRegion) createRegion(regionFactory, "test/test", cfg.getProperties(), getCacheDataDescription());
|
||||
|
||||
CacheDataDescription cdd = region.getCacheDataDescription();
|
||||
|
||||
assertNotNull(cdd);
|
||||
|
||||
CacheDataDescription expected = getCacheDataDescription();
|
||||
assertEquals(expected.isMutable(), cdd.isMutable());
|
||||
assertEquals(expected.isVersioned(), cdd.isVersioned());
|
||||
assertEquals(expected.getVersionComparator(), cdd.getVersionComparator());
|
||||
|
||||
}
|
||||
}
|
118
cache-jbosscache2/src/test/java/org/hibernate/test/cache/jbc2/AbstractJBossCacheTestCase.java
vendored
Normal file
118
cache-jbosscache2/src/test/java/org/hibernate/test/cache/jbc2/AbstractJBossCacheTestCase.java
vendored
Normal file
|
@ -0,0 +1,118 @@
|
|||
package org.hibernate.test.cache.jbc2;
|
||||
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import junit.framework.Test;
|
||||
import junit.framework.TestCase;
|
||||
import junit.framework.TestSuite;
|
||||
|
||||
import org.hibernate.cache.RegionFactory;
|
||||
import org.hibernate.junit.UnitTestCase;
|
||||
import org.hibernate.test.util.CacheTestSupport;
|
||||
import org.jboss.cache.Cache;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Base class for all non-functional tests of JBoss Cache integration.
|
||||
*
|
||||
* @author <a href="brian.stansberry@jboss.com">Brian Stansberry</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public abstract class AbstractJBossCacheTestCase extends UnitTestCase {
|
||||
|
||||
public static final String REGION_PREFIX = "test";
|
||||
|
||||
private CacheTestSupport testSupport = new CacheTestSupport();
|
||||
protected final Logger log = LoggerFactory.getLogger(getClass());
|
||||
|
||||
|
||||
public AbstractJBossCacheTestCase(String name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
|
||||
testSupport.setUp();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void tearDown() throws Exception {
|
||||
super.tearDown();
|
||||
|
||||
testSupport.tearDown();
|
||||
}
|
||||
|
||||
protected void registerCache(Cache cache) {
|
||||
testSupport.registerCache(cache);
|
||||
}
|
||||
|
||||
protected void unregisterCache(Cache cache) {
|
||||
testSupport.unregisterCache(cache);
|
||||
}
|
||||
|
||||
protected void registerFactory(RegionFactory factory) {
|
||||
testSupport.registerFactory(factory);
|
||||
}
|
||||
|
||||
protected void unregisterFactory(RegionFactory factory) {
|
||||
testSupport.unregisterFactory(factory);
|
||||
}
|
||||
|
||||
protected CacheTestSupport getCacheTestSupport() {
|
||||
return testSupport;
|
||||
}
|
||||
|
||||
protected void sleep(long ms) {
|
||||
try {
|
||||
Thread.sleep(ms);
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
log.warn("Interrupted during sleep", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Supports easy creation of a TestSuite where a subclass' "FailureExpected"
|
||||
* version of a base test is included in the suite, while the base test
|
||||
* is excluded. E.g. test class FooTestCase includes method testBar(), while test
|
||||
* class SubFooTestCase extends FooTestCase includes method testBarFailureExcluded().
|
||||
* Passing SubFooTestCase.class to this method will return a suite that
|
||||
* does not include testBar().
|
||||
*
|
||||
* FIXME Move this to UnitTestCase
|
||||
*/
|
||||
public static TestSuite createFailureExpectedSuite(Class testClass) {
|
||||
|
||||
TestSuite allTests = new TestSuite(testClass);
|
||||
Set failureExpected = new HashSet();
|
||||
Enumeration tests = allTests.tests();
|
||||
while (tests.hasMoreElements()) {
|
||||
Test t = (Test) tests.nextElement();
|
||||
if (t instanceof TestCase) {
|
||||
String name = ((TestCase) t).getName();
|
||||
if (name.endsWith("FailureExpected"))
|
||||
failureExpected.add(name);
|
||||
}
|
||||
}
|
||||
|
||||
TestSuite result = new TestSuite();
|
||||
tests = allTests.tests();
|
||||
while (tests.hasMoreElements()) {
|
||||
Test t = (Test) tests.nextElement();
|
||||
if (t instanceof TestCase) {
|
||||
String name = ((TestCase) t).getName();
|
||||
if (!failureExpected.contains(name + "FailureExpected")) {
|
||||
result.addTest(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
122
cache-jbosscache2/src/test/java/org/hibernate/test/cache/jbc2/AbstractRegionImplTestCase.java
vendored
Normal file
122
cache-jbosscache2/src/test/java/org/hibernate/test/cache/jbc2/AbstractRegionImplTestCase.java
vendored
Normal file
|
@ -0,0 +1,122 @@
|
|||
/*
|
||||
* 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.test.cache.jbc2;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import org.hibernate.cache.CacheDataDescription;
|
||||
import org.hibernate.cache.Region;
|
||||
import org.hibernate.cache.impl.CacheDataDescriptionImpl;
|
||||
import org.hibernate.cache.jbc2.JBossCacheRegionFactory;
|
||||
import org.hibernate.cache.jbc2.SharedJBossCacheRegionFactory;
|
||||
import org.hibernate.cache.jbc2.builder.SharedCacheInstanceManager;
|
||||
import org.hibernate.cfg.Configuration;
|
||||
import org.hibernate.test.util.CacheTestUtil;
|
||||
import org.hibernate.util.ComparableComparator;
|
||||
import org.jboss.cache.Cache;
|
||||
import org.jboss.cache.DefaultCacheFactory;
|
||||
import org.jboss.cache.Fqn;
|
||||
import org.jboss.cache.Node;
|
||||
import org.jboss.cache.config.Option;
|
||||
import org.jgroups.JChannelFactory;
|
||||
|
||||
/**
|
||||
* Base class for tests of Region implementations.
|
||||
*
|
||||
* @author <a href="brian.stansberry@jboss.com">Brian Stansberry</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public abstract class AbstractRegionImplTestCase extends AbstractJBossCacheTestCase {
|
||||
|
||||
/**
|
||||
* Create a new RegionImplTestCaseBase.
|
||||
*
|
||||
* @param name
|
||||
*/
|
||||
public AbstractRegionImplTestCase(String name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests proper handling of region initialization and destruction.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public void testActivationDeactivation() throws Exception {
|
||||
|
||||
// Set up a cache to monitor affects of starting the region
|
||||
Cache remoteCache = DefaultCacheFactory.getInstance().createCache(SharedCacheInstanceManager.DEFAULT_CACHE_RESOURCE, false);
|
||||
|
||||
// This test assumes replication; verify that's correct
|
||||
assertEquals("Cache is REPL_SYNC", "REPL_SYNC", remoteCache.getConfiguration().getCacheModeString());
|
||||
|
||||
JChannelFactory channelFactory = new JChannelFactory();
|
||||
channelFactory.setMultiplexerConfig(SharedCacheInstanceManager.DEF_MULTIPLEXER_RESOURCE);
|
||||
remoteCache.getConfiguration().getRuntimeConfig().setMuxChannelFactory(channelFactory);
|
||||
remoteCache.start();
|
||||
|
||||
// Make sure we stop the remoteCache
|
||||
registerCache(remoteCache);
|
||||
|
||||
Fqn regionFqn = getRegionFqn("test/test", "test");
|
||||
|
||||
assertNull("No region node", remoteCache.getRoot().getChild( regionFqn ));
|
||||
|
||||
Configuration cfg = CacheTestUtil.buildConfiguration("test", SharedJBossCacheRegionFactory.class, true, true);
|
||||
JBossCacheRegionFactory regionFactory = CacheTestUtil.startRegionFactory(cfg, getCacheTestSupport());
|
||||
|
||||
Region region = createRegion(regionFactory, "test/test", cfg.getProperties(), getCacheDataDescription());
|
||||
|
||||
Cache localCache = getJBossCache( regionFactory );
|
||||
|
||||
// This test assumes replication; verify that's correct
|
||||
assertEquals("Cache is REPL_SYNC", "REPL_SYNC", localCache.getConfiguration().getCacheModeString());
|
||||
|
||||
// Region creation should not have affected remoteCache
|
||||
|
||||
assertNull("No region node", remoteCache.getRoot().getChild( regionFqn ));
|
||||
Node regionRoot = localCache.getRoot().getChild( regionFqn );
|
||||
assertTrue("Has a node at " + regionFqn, regionRoot != null );
|
||||
assertTrue(regionFqn + " is resident", regionRoot.isResident() );
|
||||
|
||||
// Confirm region destroy does not affect remote cache
|
||||
|
||||
Option option = new Option();
|
||||
option.setCacheModeLocal(true);
|
||||
remoteCache.getInvocationContext().setOptionOverrides(option);
|
||||
remoteCache.put(regionFqn, "test", "test");
|
||||
|
||||
assertEquals("Put succeeded", "test", remoteCache.get(regionFqn, "test"));
|
||||
assertNull("Put was local", localCache.get(regionFqn, "test"));
|
||||
|
||||
region.destroy();
|
||||
|
||||
assertEquals("Remote cache unchanged", "test", remoteCache.get(regionFqn, "test"));
|
||||
assertNull("No region node", localCache.getRoot().getChild( regionFqn ));
|
||||
}
|
||||
|
||||
protected abstract Cache getJBossCache(JBossCacheRegionFactory regionFactory);
|
||||
|
||||
protected abstract Fqn getRegionFqn(String regionName, String regionPrefix);
|
||||
|
||||
protected abstract Region createRegion(JBossCacheRegionFactory regionFactory, String regionName, Properties properties, CacheDataDescription cdd);
|
||||
|
||||
protected CacheDataDescription getCacheDataDescription() {
|
||||
return new CacheDataDescriptionImpl(true, true, ComparableComparator.INSTANCE);
|
||||
}
|
||||
|
||||
}
|
150
cache-jbosscache2/src/test/java/org/hibernate/test/cache/jbc2/JBossCacheComplianceTest.java
vendored
Executable file
150
cache-jbosscache2/src/test/java/org/hibernate/test/cache/jbc2/JBossCacheComplianceTest.java
vendored
Executable file
|
@ -0,0 +1,150 @@
|
|||
package org.hibernate.test.cache.jbc2;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.hibernate.cache.RegionFactory;
|
||||
import org.hibernate.cache.jbc2.JBossCacheRegionFactory;
|
||||
import org.hibernate.cache.jbc2.MultiplexedJBossCacheRegionFactory;
|
||||
import org.hibernate.cache.jbc2.builder.SharedCacheInstanceManager;
|
||||
import org.hibernate.cache.jbc2.util.CacheHelper;
|
||||
import org.hibernate.cfg.Configuration;
|
||||
import org.hibernate.cfg.Settings;
|
||||
import org.hibernate.test.util.CacheTestSupport;
|
||||
import org.hibernate.test.util.CacheTestUtil;
|
||||
import org.jboss.cache.Cache;
|
||||
import org.jboss.cache.Fqn;
|
||||
import org.jboss.cache.config.Option;
|
||||
import org.jboss.cache.optimistic.DataVersion;
|
||||
import org.jboss.cache.transaction.BatchModeTransactionManager;
|
||||
|
||||
/**
|
||||
* Tests that JBC itself functions as expected in certain areas where there
|
||||
* may have been problems in the past. Basically tests JBC itself, not the
|
||||
* Hibernate/JBC integration.
|
||||
*
|
||||
* TODO if the equivalent tests are not in the JBC testsuite, add them.
|
||||
*
|
||||
* @author Brian Stansberry
|
||||
*/
|
||||
public class JBossCacheComplianceTest extends TestCase {
|
||||
|
||||
private CacheTestSupport testSupport = new CacheTestSupport();
|
||||
|
||||
|
||||
public JBossCacheComplianceTest(String x) {
|
||||
super(x);
|
||||
}
|
||||
|
||||
protected String getConfigResourceKey() {
|
||||
return SharedCacheInstanceManager.CACHE_RESOURCE_PROP;
|
||||
}
|
||||
|
||||
protected String getConfigResourceLocation() {
|
||||
return "org/hibernate/test/cache/jbc2/functional/optimistic-treecache.xml";
|
||||
}
|
||||
|
||||
protected Class<? extends RegionFactory> getCacheRegionFactory() {
|
||||
return JBossCacheRegionFactory.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
|
||||
testSupport.setUp();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void tearDown() throws Exception {
|
||||
|
||||
testSupport.tearDown();
|
||||
|
||||
super.tearDown();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void testCacheLevelStaleWritesFail() throws Throwable {
|
||||
|
||||
Configuration cfg = CacheTestUtil.buildConfiguration("", MultiplexedJBossCacheRegionFactory.class, true, false);
|
||||
cfg.setProperty(getConfigResourceKey(), getConfigResourceLocation());
|
||||
|
||||
Settings settings = cfg.buildSettings();
|
||||
|
||||
Fqn<String> fqn = Fqn.fromString("/whatever");
|
||||
JBossCacheRegionFactory regionFactory = (JBossCacheRegionFactory) settings.getRegionFactory();
|
||||
regionFactory.start(settings, cfg.getProperties());
|
||||
|
||||
// Make sure we clean up when done
|
||||
testSupport.registerFactory(regionFactory);
|
||||
|
||||
Cache<Object, Object> treeCache = regionFactory.getCacheInstanceManager().getEntityCacheInstance();
|
||||
|
||||
// Make sure this is an OPTIMISTIC cache
|
||||
assertEquals("Cache is OPTIMISTIC", "OPTIMISTIC", treeCache.getConfiguration().getNodeLockingSchemeString());
|
||||
|
||||
Long long1 = new Long(1);
|
||||
Long long2 = new Long(2);
|
||||
|
||||
try {
|
||||
System.out.println("****************************************************************");
|
||||
BatchModeTransactionManager.getInstance().begin();
|
||||
CacheHelper.setInvocationOption(treeCache, ManualDataVersion.gen(1));
|
||||
treeCache.put(fqn, "ITEM", long1);
|
||||
BatchModeTransactionManager.getInstance().commit();
|
||||
|
||||
System.out.println("****************************************************************");
|
||||
BatchModeTransactionManager.getInstance().begin();
|
||||
CacheHelper.setInvocationOption(treeCache, ManualDataVersion.gen(2));
|
||||
treeCache.put(fqn, "ITEM", long2);
|
||||
BatchModeTransactionManager.getInstance().commit();
|
||||
|
||||
try {
|
||||
System.out.println("****************************************************************");
|
||||
BatchModeTransactionManager.getInstance().begin();
|
||||
CacheHelper.setInvocationOption(treeCache, ManualDataVersion.gen(1));
|
||||
treeCache.put(fqn, "ITEM", long1);
|
||||
BatchModeTransactionManager.getInstance().commit();
|
||||
fail("stale write allowed");
|
||||
} catch (Throwable ignore) {
|
||||
// expected behavior
|
||||
try {
|
||||
BatchModeTransactionManager.getInstance().rollback();
|
||||
}
|
||||
catch (IllegalStateException ignored) {
|
||||
// tx is already cleared
|
||||
}
|
||||
}
|
||||
|
||||
Long current = (Long) treeCache.get(fqn, "ITEM");
|
||||
assertEquals("unexpected current value", 2, current.longValue());
|
||||
} finally {
|
||||
try {
|
||||
treeCache.remove(fqn, "ITEM");
|
||||
} catch (Throwable ignore) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class ManualDataVersion implements DataVersion {
|
||||
|
||||
/** The serialVersionUID */
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,86 @@
|
|||
/*
|
||||
* 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.test.cache.jbc2;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import org.hibernate.cache.jbc2.CacheInstanceManager;
|
||||
import org.hibernate.cache.jbc2.JBossCacheRegionFactory;
|
||||
import org.hibernate.cache.jbc2.builder.MultiplexingCacheInstanceManager;
|
||||
import org.hibernate.cache.jbc2.builder.SharedCacheInstanceManager;
|
||||
import org.hibernate.cfg.Configuration;
|
||||
import org.hibernate.cfg.Settings;
|
||||
import org.hibernate.test.util.CacheTestUtil;
|
||||
import org.jboss.cache.Cache;
|
||||
import org.jboss.cache.CacheStatus;
|
||||
|
||||
/**
|
||||
* A JBossCacheRegionFactoryTestCase.
|
||||
*
|
||||
* @author <a href="brian.stansberry@jboss.com">Brian Stansberry</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class JBossCacheRegionFactoryTestCase extends AbstractJBossCacheTestCase {
|
||||
|
||||
/**
|
||||
* Create a new JBossCacheRegionFactoryTestCase.
|
||||
*
|
||||
* @param name
|
||||
*/
|
||||
public JBossCacheRegionFactoryTestCase(String name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
public void testDefaultConfig() throws Exception {
|
||||
|
||||
Configuration cfg = CacheTestUtil.buildConfiguration("", JBossCacheRegionFactory.class, true, true);
|
||||
|
||||
JBossCacheRegionFactory regionFactory = CacheTestUtil.startRegionFactory(cfg, getCacheTestSupport());
|
||||
|
||||
CacheInstanceManager mgr = regionFactory.getCacheInstanceManager();
|
||||
assertTrue("Correct default CacheInstanceManager type", mgr instanceof SharedCacheInstanceManager);
|
||||
|
||||
Cache cache = mgr.getEntityCacheInstance();
|
||||
assertTrue("entity cache exists", cache != null);
|
||||
assertEquals("Used correct config", "TestSharedCache", cache.getConfiguration().getClusterName());
|
||||
assertEquals("Cache started", CacheStatus.STARTED, cache.getCacheStatus());
|
||||
|
||||
CacheTestUtil.stopRegionFactory(regionFactory, getCacheTestSupport());
|
||||
|
||||
assertEquals("Cache destroyed", CacheStatus.DESTROYED, cache.getCacheStatus());
|
||||
}
|
||||
|
||||
public void testInjectedCacheInstanceManager() {
|
||||
|
||||
Configuration cfg = CacheTestUtil.buildConfiguration("", JBossCacheRegionFactory.class, true, true);
|
||||
|
||||
CacheInstanceManager cim = new MultiplexingCacheInstanceManager();
|
||||
JBossCacheRegionFactory regionFactory = new JBossCacheRegionFactory(cim);
|
||||
|
||||
Settings settings = cfg.buildSettings();
|
||||
Properties properties = cfg.getProperties();
|
||||
|
||||
regionFactory.start(settings, properties);
|
||||
// Ensure we clean up
|
||||
registerFactory(regionFactory);
|
||||
|
||||
assertEquals("Used injected CacheInstanceManager", cim, regionFactory.getCacheInstanceManager());
|
||||
|
||||
CacheTestUtil.stopRegionFactory(regionFactory, getCacheTestSupport());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* 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.test.cache.jbc2.builder;
|
||||
|
||||
import org.hibernate.cache.jbc2.CacheInstanceManager;
|
||||
import org.hibernate.cache.jbc2.JBossCacheRegionFactory;
|
||||
import org.hibernate.cfg.Configuration;
|
||||
import org.hibernate.test.cache.jbc2.AbstractJBossCacheTestCase;
|
||||
import org.hibernate.test.util.CacheTestUtil;
|
||||
|
||||
/**
|
||||
* A CacheInstanceManagerTestBase.
|
||||
*
|
||||
* @author <a href="brian.stansberry@jboss.com">Brian Stansberry</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public abstract class CacheInstanceManagerTestBase extends AbstractJBossCacheTestCase {
|
||||
|
||||
/**
|
||||
* Create a new CacheInstanceManagerTestBase.
|
||||
*
|
||||
* @param name
|
||||
*/
|
||||
public CacheInstanceManagerTestBase(String name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
protected abstract Class getRegionFactoryClass();
|
||||
|
||||
public void testUse2ndLevelCache() throws Exception {
|
||||
Configuration cfg = CacheTestUtil.buildConfiguration("", getRegionFactoryClass(), false, true);
|
||||
|
||||
JBossCacheRegionFactory regionFactory = CacheTestUtil.startRegionFactory(cfg, getCacheTestSupport());
|
||||
|
||||
CacheInstanceManager cim = regionFactory.getCacheInstanceManager();
|
||||
|
||||
assertNull(cim.getCollectionCacheInstance());
|
||||
assertNull(cim.getEntityCacheInstance());
|
||||
assertNotNull(cim.getQueryCacheInstance());
|
||||
assertNotNull(cim.getTimestampsCacheInstance());
|
||||
}
|
||||
|
||||
public void testUseQueryCache() throws Exception {
|
||||
Configuration cfg = CacheTestUtil.buildConfiguration("", getRegionFactoryClass(), true, false);
|
||||
|
||||
JBossCacheRegionFactory regionFactory = CacheTestUtil.startRegionFactory(cfg, getCacheTestSupport());
|
||||
|
||||
CacheInstanceManager cim = regionFactory.getCacheInstanceManager();
|
||||
|
||||
assertNotNull(cim.getCollectionCacheInstance());
|
||||
assertNotNull(cim.getEntityCacheInstance());
|
||||
assertNull(cim.getQueryCacheInstance());
|
||||
assertNull(cim.getTimestampsCacheInstance());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* 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.test.cache.jbc2.builder;
|
||||
|
||||
import org.hibernate.cache.jbc2.MultiplexedJBossCacheRegionFactory;
|
||||
|
||||
|
||||
/**
|
||||
* A SharedCacheInstanceManagerTestCase.
|
||||
*
|
||||
* @author <a href="brian.stansberry@jboss.com">Brian Stansberry</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class MultiplexedCacheInstanceManagerTestCase extends CacheInstanceManagerTestBase {
|
||||
|
||||
/**
|
||||
* Create a new SharedCacheInstanceManagerTestCase.
|
||||
*
|
||||
* @param name
|
||||
*/
|
||||
public MultiplexedCacheInstanceManagerTestCase(String name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class getRegionFactoryClass() {
|
||||
return MultiplexedJBossCacheRegionFactory.class;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* 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.test.cache.jbc2.builder;
|
||||
|
||||
import org.hibernate.cache.jbc2.SharedJBossCacheRegionFactory;
|
||||
|
||||
/**
|
||||
* A SharedCacheInstanceManagerTestCase.
|
||||
*
|
||||
* @author <a href="brian.stansberry@jboss.com">Brian Stansberry</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class SharedCacheInstanceManagerTestCase extends CacheInstanceManagerTestBase {
|
||||
|
||||
/**
|
||||
* Create a new SharedCacheInstanceManagerTestCase.
|
||||
*
|
||||
* @param name
|
||||
*/
|
||||
public SharedCacheInstanceManagerTestCase(String name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class getRegionFactoryClass() {
|
||||
return SharedJBossCacheRegionFactory.class;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,539 @@
|
|||
/*
|
||||
* 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.test.cache.jbc2.collection;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import junit.extensions.TestSetup;
|
||||
import junit.framework.AssertionFailedError;
|
||||
import junit.framework.Test;
|
||||
import junit.framework.TestSuite;
|
||||
|
||||
import org.hibernate.cache.CacheDataDescription;
|
||||
import org.hibernate.cache.CollectionRegion;
|
||||
import org.hibernate.cache.access.AccessType;
|
||||
import org.hibernate.cache.access.CollectionRegionAccessStrategy;
|
||||
import org.hibernate.cache.impl.CacheDataDescriptionImpl;
|
||||
import org.hibernate.cache.jbc2.BasicRegionAdapter;
|
||||
import org.hibernate.cache.jbc2.JBossCacheRegionFactory;
|
||||
import org.hibernate.cache.jbc2.MultiplexedJBossCacheRegionFactory;
|
||||
import org.hibernate.cache.jbc2.builder.MultiplexingCacheInstanceManager;
|
||||
import org.hibernate.cache.jbc2.collection.CollectionRegionImpl;
|
||||
import org.hibernate.cache.jbc2.entity.TransactionalAccess;
|
||||
import org.hibernate.cache.jbc2.util.CacheHelper;
|
||||
import org.hibernate.cache.jbc2.util.NonLockingDataVersion;
|
||||
import org.hibernate.cfg.Configuration;
|
||||
import org.hibernate.test.cache.jbc2.AbstractJBossCacheTestCase;
|
||||
import org.hibernate.test.util.CacheTestUtil;
|
||||
import org.hibernate.util.ComparableComparator;
|
||||
import org.jboss.cache.Cache;
|
||||
import org.jboss.cache.Fqn;
|
||||
import org.jboss.cache.Node;
|
||||
import org.jboss.cache.NodeSPI;
|
||||
import org.jboss.cache.transaction.BatchModeTransactionManager;
|
||||
|
||||
/**
|
||||
* Base class for tests of CollectionRegionAccessStrategy impls.
|
||||
*
|
||||
* @author <a href="brian.stansberry@jboss.com">Brian Stansberry</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public abstract class AbstractCollectionRegionAccessStrategyTestCase extends AbstractJBossCacheTestCase {
|
||||
|
||||
public static final String REGION_NAME = "test/com.foo.test";
|
||||
public static final String KEY = "KEY";
|
||||
public static final String VALUE1 = "VALUE1";
|
||||
public static final String VALUE2 = "VALUE2";
|
||||
|
||||
protected static Configuration localCfg;
|
||||
protected static JBossCacheRegionFactory localRegionFactory;
|
||||
protected static Cache localCache;
|
||||
protected static Configuration remoteCfg;
|
||||
protected static JBossCacheRegionFactory remoteRegionFactory;
|
||||
protected static Cache remoteCache;
|
||||
|
||||
protected CollectionRegion localCollectionRegion;
|
||||
protected CollectionRegionAccessStrategy localAccessStrategy;
|
||||
|
||||
protected CollectionRegion remoteCollectionRegion;
|
||||
protected CollectionRegionAccessStrategy remoteAccessStrategy;
|
||||
|
||||
protected boolean invalidation;
|
||||
protected boolean optimistic;
|
||||
protected boolean synchronous;
|
||||
|
||||
protected Exception node1Exception;
|
||||
protected Exception node2Exception;
|
||||
|
||||
protected AssertionFailedError node1Failure;
|
||||
protected AssertionFailedError node2Failure;
|
||||
|
||||
public static Test getTestSetup(Class testClass, String configName) {
|
||||
TestSuite suite = new TestSuite(testClass);
|
||||
return new AccessStrategyTestSetup(suite, configName);
|
||||
}
|
||||
|
||||
public static Test getTestSetup(Test test, String configName) {
|
||||
return new AccessStrategyTestSetup(test, configName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new TransactionalAccessTestCase.
|
||||
*
|
||||
* @param name
|
||||
*/
|
||||
public AbstractCollectionRegionAccessStrategyTestCase(String name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
protected abstract AccessType getAccessType();
|
||||
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
|
||||
invalidation = CacheHelper.isClusteredInvalidation(localCache);
|
||||
synchronous = CacheHelper.isSynchronous(localCache);
|
||||
optimistic = localCache.getConfiguration().getNodeLockingScheme() == org.jboss.cache.config.Configuration.NodeLockingScheme.OPTIMISTIC;
|
||||
localCollectionRegion = localRegionFactory.buildCollectionRegion(REGION_NAME, localCfg.getProperties(), getCacheDataDescription());
|
||||
localAccessStrategy = localCollectionRegion.buildAccessStrategy(getAccessType());
|
||||
|
||||
remoteCollectionRegion = remoteRegionFactory.buildCollectionRegion(REGION_NAME, remoteCfg.getProperties(), getCacheDataDescription());
|
||||
remoteAccessStrategy = remoteCollectionRegion.buildAccessStrategy(getAccessType());
|
||||
|
||||
node1Exception = null;
|
||||
node2Exception = null;
|
||||
|
||||
node1Failure = null;
|
||||
node2Failure = null;
|
||||
}
|
||||
|
||||
protected void tearDown() throws Exception {
|
||||
|
||||
super.tearDown();
|
||||
|
||||
if (localCollectionRegion != null)
|
||||
localCollectionRegion.destroy();
|
||||
if (remoteCollectionRegion != null)
|
||||
remoteCollectionRegion.destroy();
|
||||
|
||||
try {
|
||||
localCache.getInvocationContext().getOptionOverrides().setCacheModeLocal(true);
|
||||
localCache.removeNode(Fqn.ROOT);
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.error("Problem purging local cache" ,e);
|
||||
}
|
||||
|
||||
try {
|
||||
remoteCache.getInvocationContext().getOptionOverrides().setCacheModeLocal(true);
|
||||
remoteCache.removeNode(Fqn.ROOT);
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.error("Problem purging remote cache" ,e);
|
||||
}
|
||||
|
||||
node1Exception = null;
|
||||
node2Exception = null;
|
||||
|
||||
node1Failure = null;
|
||||
node2Failure = null;
|
||||
}
|
||||
|
||||
protected static Configuration createConfiguration(String configName) {
|
||||
Configuration cfg = CacheTestUtil.buildConfiguration(REGION_PREFIX, MultiplexedJBossCacheRegionFactory.class, true, false);
|
||||
cfg.setProperty(MultiplexingCacheInstanceManager.ENTITY_CACHE_RESOURCE_PROP, configName);
|
||||
return cfg;
|
||||
}
|
||||
|
||||
protected CacheDataDescription getCacheDataDescription() {
|
||||
return new CacheDataDescriptionImpl(true, true, ComparableComparator.INSTANCE);
|
||||
}
|
||||
|
||||
protected boolean isUsingOptimisticLocking() {
|
||||
return optimistic;
|
||||
}
|
||||
|
||||
protected boolean isUsingInvalidation() {
|
||||
return invalidation;
|
||||
}
|
||||
|
||||
protected boolean isSynchronous() {
|
||||
return synchronous;
|
||||
}
|
||||
|
||||
protected Fqn getRegionFqn(String regionName, String regionPrefix) {
|
||||
return BasicRegionAdapter.getTypeLastRegionFqn(regionName, regionPrefix, CollectionRegionImpl.TYPE);
|
||||
}
|
||||
|
||||
/**
|
||||
* This is just a setup test where we assert that the cache config is
|
||||
* as we expected.
|
||||
*/
|
||||
public abstract void testCacheConfiguration();
|
||||
|
||||
/**
|
||||
* Test method for {@link TransactionalAccess#getRegion()}.
|
||||
*/
|
||||
public void testGetRegion() {
|
||||
assertEquals("Correct region", localCollectionRegion, localAccessStrategy.getRegion());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link TransactionalAccess#putFromLoad(java.lang.Object, java.lang.Object, long, java.lang.Object)}.
|
||||
*/
|
||||
public void testPutFromLoad() throws Exception {
|
||||
putFromLoadTest(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link TransactionalAccess#putFromLoad(java.lang.Object, java.lang.Object, long, java.lang.Object, boolean)}.
|
||||
*/
|
||||
public void testPutFromLoadMinimal() throws Exception {
|
||||
putFromLoadTest(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Simulate 2 nodes, both start, tx do a get, experience a cache miss,
|
||||
* then 'read from db.' First does a putFromLoad, then an evict (to represent a change).
|
||||
* Second tries to do a putFromLoad with stale data (i.e. it took
|
||||
* longer to read from the db). Both commit their tx. Then
|
||||
* both start a new tx and get. First should see the updated data;
|
||||
* second should either see the updated data (isInvalidation()( == false)
|
||||
* or null (isInvalidation() == true).
|
||||
*
|
||||
* @param useMinimalAPI
|
||||
* @throws Exception
|
||||
*/
|
||||
private void putFromLoadTest(final boolean useMinimalAPI) throws Exception {
|
||||
|
||||
final CountDownLatch writeLatch1 = new CountDownLatch(1);
|
||||
final CountDownLatch writeLatch2 = new CountDownLatch(1);
|
||||
final CountDownLatch completionLatch = new CountDownLatch(2);
|
||||
|
||||
Thread node1 = new Thread() {
|
||||
|
||||
public void run() {
|
||||
|
||||
try {
|
||||
long txTimestamp = System.currentTimeMillis();
|
||||
BatchModeTransactionManager.getInstance().begin();
|
||||
|
||||
assertEquals("node1 starts clean", null, localAccessStrategy.get(KEY, txTimestamp));
|
||||
|
||||
writeLatch1.await();
|
||||
|
||||
if (useMinimalAPI) {
|
||||
localAccessStrategy.putFromLoad(KEY, VALUE2, txTimestamp, new Integer(2), true);
|
||||
}
|
||||
else {
|
||||
localAccessStrategy.putFromLoad(KEY, VALUE2, txTimestamp, new Integer(2));
|
||||
}
|
||||
|
||||
BatchModeTransactionManager.getInstance().commit();
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.error("node1 caught exception", e);
|
||||
node1Exception = e;
|
||||
rollback();
|
||||
}
|
||||
catch (AssertionFailedError e) {
|
||||
node1Failure = e;
|
||||
rollback();
|
||||
}
|
||||
finally {
|
||||
// Let node2 write
|
||||
writeLatch2.countDown();
|
||||
completionLatch.countDown();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Thread node2 = new Thread() {
|
||||
|
||||
public void run() {
|
||||
|
||||
try {
|
||||
long txTimestamp = System.currentTimeMillis();
|
||||
BatchModeTransactionManager.getInstance().begin();
|
||||
|
||||
assertNull("node1 starts clean", remoteAccessStrategy.get(KEY, txTimestamp));
|
||||
|
||||
// Let node1 write
|
||||
writeLatch1.countDown();
|
||||
// Wait for node1 to finish
|
||||
writeLatch2.await();
|
||||
|
||||
// Let the first PFER propagate
|
||||
sleep(200);
|
||||
|
||||
if (useMinimalAPI) {
|
||||
remoteAccessStrategy.putFromLoad(KEY, VALUE1, txTimestamp, new Integer(1), true);
|
||||
}
|
||||
else {
|
||||
remoteAccessStrategy.putFromLoad(KEY, VALUE1, txTimestamp, new Integer(1));
|
||||
}
|
||||
|
||||
BatchModeTransactionManager.getInstance().commit();
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.error("node2 caught exception", e);
|
||||
node2Exception = e;
|
||||
rollback();
|
||||
}
|
||||
catch (AssertionFailedError e) {
|
||||
node2Failure = e;
|
||||
rollback();
|
||||
}
|
||||
finally {
|
||||
completionLatch.countDown();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
node1.setDaemon(true);
|
||||
node2.setDaemon(true);
|
||||
|
||||
node1.start();
|
||||
node2.start();
|
||||
|
||||
assertTrue("Threads completed", completionLatch.await(2, TimeUnit.SECONDS));
|
||||
|
||||
if (node1Failure != null)
|
||||
throw node1Failure;
|
||||
if (node2Failure != null)
|
||||
throw node2Failure;
|
||||
|
||||
assertEquals("node1 saw no exceptions", null, node1Exception);
|
||||
assertEquals("node2 saw no exceptions", null, node2Exception);
|
||||
|
||||
// let the final PFER propagate
|
||||
sleep(100);
|
||||
|
||||
long txTimestamp = System.currentTimeMillis();
|
||||
String msg1 = "Correct node1 value";
|
||||
String msg2 = "Correct node2 value";
|
||||
Object expected1 = null;
|
||||
Object expected2 = null;
|
||||
if (isUsingInvalidation()) {
|
||||
if (isUsingOptimisticLocking()) {
|
||||
expected1 = null; // the initial VALUE2 DataVersion should prevent the node2 put
|
||||
expected2 = VALUE2;
|
||||
|
||||
// We know this case fails
|
||||
msg1 = msg2 = "Known issue JBCACHE-1203";
|
||||
}
|
||||
else {
|
||||
// node2 can write since there is no data version
|
||||
// We count on db locking to prevent this case
|
||||
expected1 = VALUE1;
|
||||
expected2 = null; // invalidated by node2
|
||||
|
||||
// We know this case fails
|
||||
msg1 = msg2 = "Known issue JBCACHE-1203";
|
||||
}
|
||||
}
|
||||
else {
|
||||
// the initial VALUE2 should prevent the node2 put
|
||||
expected1 = VALUE2;
|
||||
expected2 = VALUE2;
|
||||
}
|
||||
|
||||
assertEquals(msg1, expected1, localAccessStrategy.get(KEY, txTimestamp));
|
||||
assertEquals(msg2, expected2, remoteAccessStrategy.get(KEY, txTimestamp));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link TransactionalAccess#remove(java.lang.Object)}.
|
||||
*/
|
||||
public void testRemove() {
|
||||
evictOrRemoveTest(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link TransactionalAccess#removeAll()}.
|
||||
*/
|
||||
public void testRemoveAll() {
|
||||
evictOrRemoveAllTest(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link TransactionalAccess#evict(java.lang.Object)}.
|
||||
*
|
||||
* FIXME add testing of the "immediately without regard for transaction
|
||||
* isolation" bit in the CollectionRegionAccessStrategy API.
|
||||
*/
|
||||
public void testEvict() {
|
||||
evictOrRemoveTest(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link TransactionalAccess#evictAll()}.
|
||||
*
|
||||
* FIXME add testing of the "immediately without regard for transaction
|
||||
* isolation" bit in the CollectionRegionAccessStrategy API.
|
||||
*/
|
||||
public void testEvictAll() {
|
||||
evictOrRemoveAllTest(true);
|
||||
}
|
||||
|
||||
private void evictOrRemoveTest(boolean evict) {
|
||||
assertNull("local is clean", localAccessStrategy.get(KEY, System.currentTimeMillis()));
|
||||
assertNull("remote is clean", remoteAccessStrategy.get(KEY, System.currentTimeMillis()));
|
||||
|
||||
localAccessStrategy.putFromLoad(KEY, VALUE1, System.currentTimeMillis(), new Integer(1));
|
||||
assertEquals(VALUE1, localAccessStrategy.get(KEY, System.currentTimeMillis()));
|
||||
remoteAccessStrategy.putFromLoad(KEY, VALUE1, System.currentTimeMillis(), new Integer(1));
|
||||
assertEquals(VALUE1, remoteAccessStrategy.get(KEY, System.currentTimeMillis()));
|
||||
|
||||
// Wait for async propagation
|
||||
sleep(250);
|
||||
|
||||
if (evict)
|
||||
localAccessStrategy.evict(KEY);
|
||||
else
|
||||
localAccessStrategy.remove(KEY);
|
||||
|
||||
assertEquals(null, localAccessStrategy.get(KEY, System.currentTimeMillis()));
|
||||
|
||||
assertEquals(null, remoteAccessStrategy.get(KEY, System.currentTimeMillis()));
|
||||
}
|
||||
|
||||
private void evictOrRemoveAllTest(boolean evict) {
|
||||
|
||||
Fqn regionFqn = getRegionFqn(REGION_NAME, REGION_PREFIX);
|
||||
|
||||
Node regionRoot = localCache.getRoot().getChild(regionFqn);
|
||||
assertFalse(regionRoot == null);
|
||||
assertEquals(0, regionRoot.getChildrenNames().size());
|
||||
assertTrue(regionRoot.isResident());
|
||||
|
||||
if (isUsingOptimisticLocking()) {
|
||||
assertEquals(NonLockingDataVersion.class, ((NodeSPI) regionRoot).getVersion().getClass());
|
||||
}
|
||||
|
||||
regionRoot = remoteCache.getRoot().getChild(regionFqn);
|
||||
assertFalse(regionRoot == null);
|
||||
assertEquals(0, regionRoot.getChildrenNames().size());
|
||||
assertTrue(regionRoot.isResident());
|
||||
|
||||
if (isUsingOptimisticLocking()) {
|
||||
assertEquals(NonLockingDataVersion.class, ((NodeSPI) regionRoot).getVersion().getClass());
|
||||
}
|
||||
|
||||
assertNull("local is clean", localAccessStrategy.get(KEY, System.currentTimeMillis()));
|
||||
assertNull("remote is clean", remoteAccessStrategy.get(KEY, System.currentTimeMillis()));
|
||||
|
||||
localAccessStrategy.putFromLoad(KEY, VALUE1, System.currentTimeMillis(), new Integer(1));
|
||||
assertEquals(VALUE1, localAccessStrategy.get(KEY, System.currentTimeMillis()));
|
||||
remoteAccessStrategy.putFromLoad(KEY, VALUE1, System.currentTimeMillis(), new Integer(1));
|
||||
assertEquals(VALUE1, remoteAccessStrategy.get(KEY, System.currentTimeMillis()));
|
||||
|
||||
// Wait for async propagation
|
||||
sleep(250);
|
||||
|
||||
|
||||
|
||||
if (isUsingOptimisticLocking()) {
|
||||
regionRoot = localCache.getRoot().getChild(regionFqn);
|
||||
assertEquals(NonLockingDataVersion.class, ((NodeSPI) regionRoot).getVersion().getClass());
|
||||
regionRoot = remoteCache.getRoot().getChild(regionFqn);
|
||||
assertEquals(NonLockingDataVersion.class, ((NodeSPI) regionRoot).getVersion().getClass());
|
||||
}
|
||||
|
||||
if (evict)
|
||||
localAccessStrategy.evictAll();
|
||||
else
|
||||
localAccessStrategy.removeAll();
|
||||
|
||||
regionRoot = localCache.getRoot().getChild(regionFqn);
|
||||
assertFalse(regionRoot == null);
|
||||
assertEquals(0, regionRoot.getChildrenNames().size());
|
||||
assertTrue(regionRoot.isResident());
|
||||
|
||||
regionRoot = remoteCache.getRoot().getChild(regionFqn);
|
||||
assertFalse(regionRoot == null);
|
||||
if (isUsingInvalidation()) {
|
||||
// JBC seems broken: see http://www.jboss.com/index.html?module=bb&op=viewtopic&t=121408
|
||||
// FIXME replace with the following when JBCACHE-1199 and JBCACHE-1200 are done:
|
||||
//assertFalse(regionRoot.isValid());
|
||||
checkNodeIsEmpty(regionRoot);
|
||||
}
|
||||
else {
|
||||
// Same assertion, just different assertion msg
|
||||
assertEquals(0, regionRoot.getChildrenNames().size());
|
||||
}
|
||||
assertTrue(regionRoot.isResident());
|
||||
|
||||
assertNull("local is clean", localAccessStrategy.get(KEY, System.currentTimeMillis()));
|
||||
assertNull("remote is clean", remoteAccessStrategy.get(KEY, System.currentTimeMillis()));
|
||||
}
|
||||
|
||||
private void checkNodeIsEmpty(Node node) {
|
||||
assertEquals("Known issue JBCACHE-1200. node " + node.getFqn() + " should not have keys", 0, node.getKeys().size());
|
||||
for (Iterator it = node.getChildren().iterator(); it.hasNext(); ) {
|
||||
checkNodeIsEmpty((Node) it.next());
|
||||
}
|
||||
}
|
||||
|
||||
private void rollback() {
|
||||
try {
|
||||
BatchModeTransactionManager.getInstance().rollback();
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class AccessStrategyTestSetup extends TestSetup {
|
||||
|
||||
private String configName;
|
||||
|
||||
public AccessStrategyTestSetup(Test test, String configName) {
|
||||
super(test);
|
||||
this.configName = configName;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
localCfg = createConfiguration(configName);
|
||||
localRegionFactory = CacheTestUtil.startRegionFactory(localCfg);
|
||||
localCache = localRegionFactory.getCacheInstanceManager().getCollectionCacheInstance();
|
||||
|
||||
remoteCfg = createConfiguration(configName);
|
||||
remoteRegionFactory = CacheTestUtil.startRegionFactory(remoteCfg);
|
||||
remoteCache = remoteRegionFactory.getCacheInstanceManager().getCollectionCacheInstance();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void tearDown() throws Exception {
|
||||
super.tearDown();
|
||||
|
||||
if (localRegionFactory != null)
|
||||
localRegionFactory.stop();
|
||||
|
||||
if (remoteRegionFactory != null)
|
||||
remoteRegionFactory.stop();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* 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.test.cache.jbc2.collection;
|
||||
|
||||
import org.hibernate.cache.access.AccessType;
|
||||
|
||||
/**
|
||||
* Base class for tests of TRANSACTIONAL access.
|
||||
*
|
||||
* @author <a href="brian.stansberry@jboss.com">Brian Stansberry</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public abstract class AbstractReadOnlyAccessTestCase extends AbstractCollectionRegionAccessStrategyTestCase {
|
||||
|
||||
/**
|
||||
* Create a new AbstractTransactionalAccessTestCase.
|
||||
*
|
||||
*/
|
||||
public AbstractReadOnlyAccessTestCase(String name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AccessType getAccessType() {
|
||||
return AccessType.READ_ONLY;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* 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.test.cache.jbc2.collection;
|
||||
|
||||
import org.hibernate.cache.access.AccessType;
|
||||
|
||||
/**
|
||||
* Base class for tests of TRANSACTIONAL access.
|
||||
*
|
||||
* @author <a href="brian.stansberry@jboss.com">Brian Stansberry</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public abstract class AbstractTransactionalAccessTestCase extends AbstractCollectionRegionAccessStrategyTestCase {
|
||||
|
||||
/**
|
||||
* Create a new AbstractTransactionalAccessTestCase.
|
||||
*
|
||||
*/
|
||||
public AbstractTransactionalAccessTestCase(String name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AccessType getAccessType() {
|
||||
return AccessType.TRANSACTIONAL;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,97 @@
|
|||
/*
|
||||
* 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.test.cache.jbc2.collection;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import org.hibernate.cache.CacheDataDescription;
|
||||
import org.hibernate.cache.CacheException;
|
||||
import org.hibernate.cache.CollectionRegion;
|
||||
import org.hibernate.cache.Region;
|
||||
import org.hibernate.cache.RegionFactory;
|
||||
import org.hibernate.cache.access.AccessType;
|
||||
import org.hibernate.cache.jbc2.BasicRegionAdapter;
|
||||
import org.hibernate.cache.jbc2.CacheInstanceManager;
|
||||
import org.hibernate.cache.jbc2.JBossCacheRegionFactory;
|
||||
import org.hibernate.cache.jbc2.collection.CollectionRegionImpl;
|
||||
import org.hibernate.test.cache.jbc2.AbstractEntityCollectionRegionTestCase;
|
||||
import org.jboss.cache.Cache;
|
||||
import org.jboss.cache.Fqn;
|
||||
|
||||
/**
|
||||
* Tests of CollectionRegionImpl.
|
||||
*
|
||||
* @author <a href="brian.stansberry@jboss.com">Brian Stansberry</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class CollectionRegionImplTestCase extends AbstractEntityCollectionRegionTestCase {
|
||||
|
||||
/**
|
||||
* Create a new EntityRegionImplTestCase.
|
||||
*
|
||||
* @param name
|
||||
*/
|
||||
public CollectionRegionImplTestCase(String name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
protected void supportedAccessTypeTest(RegionFactory regionFactory, Properties properties) {
|
||||
|
||||
CollectionRegion region = regionFactory.buildCollectionRegion("test", properties, null);
|
||||
|
||||
assertNull("Got TRANSACTIONAL", region.buildAccessStrategy(AccessType.TRANSACTIONAL).lockRegion());
|
||||
|
||||
try
|
||||
{
|
||||
region.buildAccessStrategy(AccessType.READ_ONLY).lockRegion();
|
||||
fail("Did not get READ_ONLY");
|
||||
}
|
||||
catch (UnsupportedOperationException good) {}
|
||||
|
||||
try
|
||||
{
|
||||
region.buildAccessStrategy(AccessType.NONSTRICT_READ_WRITE);
|
||||
fail("Incorrectly got NONSTRICT_READ_WRITE");
|
||||
}
|
||||
catch (CacheException good) {}
|
||||
|
||||
try
|
||||
{
|
||||
region.buildAccessStrategy(AccessType.READ_WRITE);
|
||||
fail("Incorrectly got READ_WRITE");
|
||||
}
|
||||
catch (CacheException good) {}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Region createRegion(JBossCacheRegionFactory regionFactory, String regionName, Properties properties, CacheDataDescription cdd) {
|
||||
return regionFactory.buildCollectionRegion(regionName, properties, cdd);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Cache getJBossCache(JBossCacheRegionFactory regionFactory) {
|
||||
CacheInstanceManager mgr = regionFactory.getCacheInstanceManager();
|
||||
return mgr.getCollectionCacheInstance();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Fqn getRegionFqn(String regionName, String regionPrefix) {
|
||||
return BasicRegionAdapter.getTypeLastRegionFqn(regionName, regionPrefix, CollectionRegionImpl.TYPE);
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* 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.test.cache.jbc2.collection;
|
||||
|
||||
import junit.framework.Test;
|
||||
import junit.framework.TestSuite;
|
||||
|
||||
/**
|
||||
* Tests TRANSACTIONAL access when optimistic locking and invalidation are used.
|
||||
*
|
||||
* @author <a href="brian.stansberry@jboss.com">Brian Stansberry</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class OptimisticInvalidatedTransactionalTestCase
|
||||
extends AbstractTransactionalAccessTestCase {
|
||||
|
||||
/**
|
||||
* Create a new TransactionalAccessTestCase.
|
||||
*
|
||||
* @param name
|
||||
*/
|
||||
public OptimisticInvalidatedTransactionalTestCase(String name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
public static Test suite() throws Exception {
|
||||
TestSuite suite = createFailureExpectedSuite(OptimisticInvalidatedTransactionalTestCase.class);
|
||||
return getTestSetup(suite, "optimistic-entity");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void testCacheConfiguration() {
|
||||
assertTrue("Using Invalidation", isUsingInvalidation());
|
||||
assertTrue("Using Optimistic locking", isUsingOptimisticLocking());
|
||||
assertTrue("Synchronous mode", isSynchronous());
|
||||
}
|
||||
|
||||
// Known failures
|
||||
|
||||
public void testEvictAllFailureExpected() {
|
||||
super.testEvictAll();
|
||||
}
|
||||
|
||||
public void testRemoveAllFailureExpected() {
|
||||
super.testRemoveAll();
|
||||
}
|
||||
|
||||
public void testPutFromLoadFailureExpected() throws Exception {
|
||||
super.testPutFromLoad();
|
||||
}
|
||||
|
||||
public void testPutFromLoadMinimalFailureExpected() throws Exception {
|
||||
super.testPutFromLoadMinimal();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,86 @@
|
|||
/*
|
||||
* 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.test.cache.jbc2.collection;
|
||||
|
||||
import org.hibernate.cache.access.AccessType;
|
||||
import org.hibernate.cache.access.CollectionRegionAccessStrategy;
|
||||
import org.hibernate.cache.jbc2.entity.TransactionalAccess;
|
||||
|
||||
/**
|
||||
* Tests for the "extra API" in EntityRegionAccessStrategy; in this
|
||||
* version using Optimistic locking with READ_ONLY access.
|
||||
* <p>
|
||||
* By "extra API" we mean those methods that are superfluous to the
|
||||
* function of the JBC integration, where the impl is a no-op or a static
|
||||
* false return value, UnsupportedOperationException, etc.
|
||||
*
|
||||
* @author <a href="brian.stansberry@jboss.com">Brian Stansberry</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class OptimisticReadOnlyExtraAPITestCase extends OptimisticTransactionalExtraAPITestCase {
|
||||
|
||||
private static CollectionRegionAccessStrategy localAccessStrategy;
|
||||
|
||||
/**
|
||||
* Create a new TransactionalAccessTestCase.
|
||||
*
|
||||
* @param name
|
||||
*/
|
||||
public OptimisticReadOnlyExtraAPITestCase(String name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AccessType getAccessType() {
|
||||
return AccessType.READ_ONLY;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CollectionRegionAccessStrategy getCollectionAccessStrategy() {
|
||||
return localAccessStrategy;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setCollectionAccessStrategy(CollectionRegionAccessStrategy strategy) {
|
||||
localAccessStrategy = strategy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link TransactionalAccess#lockItem(java.lang.Object, java.lang.Object)}.
|
||||
*/
|
||||
@Override
|
||||
public void testLockItem() {
|
||||
try {
|
||||
getCollectionAccessStrategy().lockItem(KEY, new Integer(1));
|
||||
fail("Call to lockItem did not throw exception");
|
||||
}
|
||||
catch (UnsupportedOperationException expected) {}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link TransactionalAccess#lockRegion()}.
|
||||
*/
|
||||
@Override
|
||||
public void testLockRegion() {
|
||||
try {
|
||||
getCollectionAccessStrategy().lockRegion();
|
||||
fail("Call to lockRegion did not throw exception");
|
||||
}
|
||||
catch (UnsupportedOperationException expected) {}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* 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.test.cache.jbc2.collection;
|
||||
|
||||
import junit.framework.Test;
|
||||
import junit.framework.TestSuite;
|
||||
|
||||
/**
|
||||
* Tests READ_ONLY access when optimistic locking and invalidation are used.
|
||||
*
|
||||
* @author <a href="brian.stansberry@jboss.com">Brian Stansberry</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class OptimisticReadOnlyTestCase extends AbstractReadOnlyAccessTestCase {
|
||||
|
||||
/**
|
||||
* Create a new PessimisticTransactionalAccessTestCase.
|
||||
*
|
||||
* @param name
|
||||
*/
|
||||
public OptimisticReadOnlyTestCase(String name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
public static Test suite() throws Exception {
|
||||
TestSuite suite = createFailureExpectedSuite(OptimisticReadOnlyTestCase.class);
|
||||
return getTestSetup(suite, "optimistic-entity");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void testCacheConfiguration() {
|
||||
assertTrue("Using Invalidation", isUsingInvalidation());
|
||||
assertTrue("Using Optimistic locking", isUsingOptimisticLocking());
|
||||
assertTrue("Synchronous mode", isSynchronous());
|
||||
}
|
||||
|
||||
// Known failures
|
||||
|
||||
public void testEvictAllFailureExpected() {
|
||||
super.testEvictAll();
|
||||
}
|
||||
|
||||
public void testRemoveAllFailureExpected() {
|
||||
super.testRemoveAll();
|
||||
}
|
||||
|
||||
public void testPutFromLoadFailureExpected() throws Exception {
|
||||
super.testPutFromLoad();
|
||||
}
|
||||
|
||||
public void testPutFromLoadMinimalFailureExpected() throws Exception {
|
||||
super.testPutFromLoadMinimal();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* 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.test.cache.jbc2.collection;
|
||||
|
||||
import junit.framework.Test;
|
||||
|
||||
/**
|
||||
* Tests TRANSACTIONAL access when optimistic locking and replication are used.
|
||||
*
|
||||
* @author <a href="brian.stansberry@jboss.com">Brian Stansberry</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class OptimisticReplicatedTransactionalTestCase extends AbstractTransactionalAccessTestCase {
|
||||
|
||||
/**
|
||||
* Create a new PessimisticTransactionalAccessTestCase.
|
||||
*
|
||||
* @param name
|
||||
*/
|
||||
public OptimisticReplicatedTransactionalTestCase(String name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
public static Test suite() throws Exception {
|
||||
return getTestSetup(OptimisticReplicatedTransactionalTestCase.class, "optimistic-shared");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void testCacheConfiguration() {
|
||||
assertFalse("Using Invalidation", isUsingInvalidation());
|
||||
assertTrue("Using Optimistic locking", isUsingOptimisticLocking());
|
||||
assertTrue("Synchronous mode", isSynchronous());
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,147 @@
|
|||
/*
|
||||
* 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.test.cache.jbc2.collection;
|
||||
|
||||
import org.hibernate.cache.CollectionRegion;
|
||||
import org.hibernate.cache.access.AccessType;
|
||||
import org.hibernate.cache.access.CollectionRegionAccessStrategy;
|
||||
import org.hibernate.cache.access.SoftLock;
|
||||
import org.hibernate.cache.jbc2.JBossCacheRegionFactory;
|
||||
import org.hibernate.cache.jbc2.MultiplexedJBossCacheRegionFactory;
|
||||
import org.hibernate.cache.jbc2.builder.MultiplexingCacheInstanceManager;
|
||||
import org.hibernate.cache.jbc2.entity.TransactionalAccess;
|
||||
import org.hibernate.cfg.Configuration;
|
||||
import org.hibernate.test.cache.jbc2.AbstractJBossCacheTestCase;
|
||||
import org.hibernate.test.util.CacheTestUtil;
|
||||
import org.jboss.cache.Cache;
|
||||
|
||||
/**
|
||||
* Tests for the "extra API" in CollectionRegionAccessStrategy; in this base
|
||||
* version using Optimistic locking with TRANSACTIONAL access.
|
||||
* <p>
|
||||
* By "extra API" we mean those methods that are superfluous to the
|
||||
* function of the JBC integration, where the impl is a no-op or a static
|
||||
* false return value, UnsupportedOperationException, etc.
|
||||
*
|
||||
* @author <a href="brian.stansberry@jboss.com">Brian Stansberry</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class OptimisticTransactionalExtraAPITestCase extends AbstractJBossCacheTestCase {
|
||||
|
||||
public static final String REGION_NAME = "test/com.foo.test";
|
||||
public static final String KEY = "KEY";
|
||||
public static final String VALUE1 = "VALUE1";
|
||||
public static final String VALUE2 = "VALUE2";
|
||||
|
||||
private static CollectionRegionAccessStrategy localAccessStrategy;
|
||||
|
||||
private static boolean optimistic;
|
||||
|
||||
/**
|
||||
* Create a new TransactionalAccessTestCase.
|
||||
*
|
||||
* @param name
|
||||
*/
|
||||
public OptimisticTransactionalExtraAPITestCase(String name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
|
||||
if (getCollectionAccessStrategy() == null) {
|
||||
Configuration cfg = createConfiguration();
|
||||
JBossCacheRegionFactory rf = CacheTestUtil.startRegionFactory(cfg, getCacheTestSupport());
|
||||
Cache localCache = rf.getCacheInstanceManager().getEntityCacheInstance();
|
||||
optimistic = localCache.getConfiguration().getNodeLockingScheme() == org.jboss.cache.config.Configuration.NodeLockingScheme.OPTIMISTIC;
|
||||
CollectionRegion localCollectionRegion = rf.buildCollectionRegion(REGION_NAME, cfg.getProperties(), null);
|
||||
setCollectionAccessStrategy(localCollectionRegion.buildAccessStrategy(getAccessType()));
|
||||
}
|
||||
}
|
||||
|
||||
protected void tearDown() throws Exception {
|
||||
|
||||
super.tearDown();
|
||||
}
|
||||
|
||||
protected Configuration createConfiguration() {
|
||||
Configuration cfg = CacheTestUtil.buildConfiguration(REGION_PREFIX, MultiplexedJBossCacheRegionFactory.class, true, false);
|
||||
cfg.setProperty(MultiplexingCacheInstanceManager.ENTITY_CACHE_RESOURCE_PROP, getCacheConfigName());
|
||||
return cfg;
|
||||
}
|
||||
|
||||
protected String getCacheConfigName() {
|
||||
return "optimistic-entity";
|
||||
}
|
||||
|
||||
protected boolean isUsingOptimisticLocking() {
|
||||
return optimistic;
|
||||
}
|
||||
|
||||
protected AccessType getAccessType() {
|
||||
return AccessType.TRANSACTIONAL;
|
||||
}
|
||||
|
||||
protected CollectionRegionAccessStrategy getCollectionAccessStrategy() {
|
||||
return localAccessStrategy;
|
||||
}
|
||||
|
||||
protected void setCollectionAccessStrategy(CollectionRegionAccessStrategy strategy) {
|
||||
localAccessStrategy = strategy;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is just a setup test where we assert that the cache config is
|
||||
* as we expected.
|
||||
*/
|
||||
public void testCacheConfiguration() {
|
||||
assertTrue("Using Optimistic locking", isUsingOptimisticLocking());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link TransactionalAccess#lockItem(java.lang.Object, java.lang.Object)}.
|
||||
*/
|
||||
public void testLockItem() {
|
||||
assertNull(getCollectionAccessStrategy().lockItem(KEY, new Integer(1)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link TransactionalAccess#lockRegion()}.
|
||||
*/
|
||||
public void testLockRegion() {
|
||||
assertNull(getCollectionAccessStrategy().lockRegion());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link TransactionalAccess#unlockItem(java.lang.Object, org.hibernate.cache.access.SoftLock)}.
|
||||
*/
|
||||
public void testUnlockItem() {
|
||||
getCollectionAccessStrategy().unlockItem(KEY, new MockSoftLock());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link TransactionalAccess#unlockRegion(org.hibernate.cache.access.SoftLock)}.
|
||||
*/
|
||||
public void testUnlockRegion() {
|
||||
getCollectionAccessStrategy().unlockItem(KEY, new MockSoftLock());
|
||||
}
|
||||
|
||||
public static class MockSoftLock implements SoftLock {
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* 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.test.cache.jbc2.collection;
|
||||
|
||||
import junit.framework.Test;
|
||||
import junit.framework.TestSuite;
|
||||
|
||||
/**
|
||||
* Tests TRANSACTIONAL access when pessimistic locking and invalidation are used.
|
||||
*
|
||||
* @author <a href="brian.stansberry@jboss.com">Brian Stansberry</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class PessimisticInvalidatedTransactionalTestCase extends AbstractTransactionalAccessTestCase {
|
||||
|
||||
/**
|
||||
* Create a new PessimisticTransactionalAccessTestCase.
|
||||
*
|
||||
* @param name
|
||||
*/
|
||||
public PessimisticInvalidatedTransactionalTestCase(String name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
public static Test suite() throws Exception {
|
||||
TestSuite suite = createFailureExpectedSuite(PessimisticInvalidatedTransactionalTestCase.class);
|
||||
return getTestSetup(suite, "pessimistic-entity");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void testCacheConfiguration() {
|
||||
assertTrue("Using Invalidation", isUsingInvalidation());
|
||||
assertFalse("Using Optimistic locking", isUsingOptimisticLocking());
|
||||
assertTrue("Synchronous mode", isSynchronous());
|
||||
}
|
||||
|
||||
// Known failures
|
||||
|
||||
public void testEvictAllFailureExpected() {
|
||||
super.testEvictAll();
|
||||
}
|
||||
|
||||
public void testRemoveAllFailureExpected() {
|
||||
super.testRemoveAll();
|
||||
}
|
||||
|
||||
public void testPutFromLoadFailureExpected() throws Exception {
|
||||
super.testPutFromLoad();
|
||||
}
|
||||
|
||||
public void testPutFromLoadMinimalFailureExpected() throws Exception {
|
||||
super.testPutFromLoadMinimal();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* 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.test.cache.jbc2.collection;
|
||||
|
||||
import org.hibernate.cache.access.CollectionRegionAccessStrategy;
|
||||
|
||||
/**
|
||||
* Tests for the "extra API" in EntityRegionAccessStrategy; in this
|
||||
* version using pessimistic locking with READ_ONLY access.
|
||||
* <p>
|
||||
* By "extra API" we mean those methods that are superfluous to the
|
||||
* function of the JBC integration, where the impl is a no-op or a static
|
||||
* false return value, UnsupportedOperationException, etc.
|
||||
*
|
||||
* @author <a href="brian.stansberry@jboss.com">Brian Stansberry</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class PessimisticReadOnlyExtraAPITestCase extends OptimisticReadOnlyExtraAPITestCase {
|
||||
|
||||
private static CollectionRegionAccessStrategy localAccessStrategy;
|
||||
|
||||
/**
|
||||
* Create a new PessimisticAccessStrategyExtraAPITestCase.
|
||||
*
|
||||
* @param name
|
||||
*/
|
||||
public PessimisticReadOnlyExtraAPITestCase(String name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getCacheConfigName() {
|
||||
return "pessimistic-entity";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CollectionRegionAccessStrategy getCollectionAccessStrategy() {
|
||||
return localAccessStrategy;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setCollectionAccessStrategy(CollectionRegionAccessStrategy strategy) {
|
||||
localAccessStrategy = strategy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void testCacheConfiguration() {
|
||||
assertFalse("Using Optimistic locking", isUsingOptimisticLocking());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* 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.test.cache.jbc2.collection;
|
||||
|
||||
import junit.framework.Test;
|
||||
import junit.framework.TestSuite;
|
||||
|
||||
/**
|
||||
* Tests READ_ONLY access when pessimistic locking and invalidation are used.
|
||||
*
|
||||
* @author <a href="brian.stansberry@jboss.com">Brian Stansberry</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class PessimisticReadOnlyTestCase extends AbstractReadOnlyAccessTestCase {
|
||||
|
||||
/**
|
||||
* Create a new PessimisticTransactionalAccessTestCase.
|
||||
*
|
||||
* @param name
|
||||
*/
|
||||
public PessimisticReadOnlyTestCase(String name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
public static Test suite() throws Exception {
|
||||
TestSuite suite = createFailureExpectedSuite(PessimisticReadOnlyTestCase.class);
|
||||
return getTestSetup(suite, "pessimistic-entity");
|
||||
}
|
||||
|
||||
// Known failures
|
||||
|
||||
public void testEvictAllFailureExpected() {
|
||||
super.testEvictAll();
|
||||
}
|
||||
|
||||
public void testRemoveAllFailureExpected() {
|
||||
super.testRemoveAll();
|
||||
}
|
||||
|
||||
public void testPutFromLoadFailureExpected() throws Exception {
|
||||
super.testPutFromLoad();
|
||||
}
|
||||
|
||||
public void testPutFromLoadMinimalFailureExpected() throws Exception {
|
||||
super.testPutFromLoadMinimal();
|
||||
}
|
||||
|
||||
// Overrides
|
||||
|
||||
@Override
|
||||
public void testCacheConfiguration() {
|
||||
assertTrue("Using Invalidation", isUsingInvalidation());
|
||||
assertFalse("Using Optimistic locking", isUsingOptimisticLocking());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* 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.test.cache.jbc2.collection;
|
||||
|
||||
import junit.framework.Test;
|
||||
|
||||
/**
|
||||
* Tests TRANSACTIONAL access when pessimistic locking and replication are used.
|
||||
*
|
||||
* @author <a href="brian.stansberry@jboss.com">Brian Stansberry</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class PessimisticReplicatedTransactionalTestCase extends AbstractTransactionalAccessTestCase {
|
||||
|
||||
/**
|
||||
* Create a new PessimisticTransactionalAccessTestCase.
|
||||
*
|
||||
* @param name
|
||||
*/
|
||||
public PessimisticReplicatedTransactionalTestCase(String name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
public static Test suite() throws Exception {
|
||||
return getTestSetup(PessimisticReplicatedTransactionalTestCase.class, "pessimistic-shared");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void testCacheConfiguration() {
|
||||
assertFalse("Using Invalidation", isUsingInvalidation());
|
||||
assertFalse("Using Optimistic locking", isUsingOptimisticLocking());
|
||||
assertTrue("Synchronous mode", isSynchronous());
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* 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.test.cache.jbc2.collection;
|
||||
|
||||
import org.hibernate.cache.access.CollectionRegionAccessStrategy;
|
||||
|
||||
/**
|
||||
* Tests for the "extra API" in EntityRegionAccessStrategy; in this base
|
||||
* version using Optimistic locking with TRANSACTIONAL access.
|
||||
* <p>
|
||||
* By "extra API" we mean those methods that are superfluous to the
|
||||
* function of the JBC integration, where the impl is a no-op or a static
|
||||
* false return value, UnsupportedOperationException, etc.
|
||||
*
|
||||
* @author <a href="brian.stansberry@jboss.com">Brian Stansberry</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class PessimisticTransactionalExtraAPITestCase extends OptimisticTransactionalExtraAPITestCase {
|
||||
|
||||
private static CollectionRegionAccessStrategy localAccessStrategy;
|
||||
|
||||
/**
|
||||
* Create a new PessimisticAccessStrategyExtraAPITestCase.
|
||||
*
|
||||
* @param name
|
||||
*/
|
||||
public PessimisticTransactionalExtraAPITestCase(String name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getCacheConfigName() {
|
||||
return "pessimistic-entity";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CollectionRegionAccessStrategy getCollectionAccessStrategy() {
|
||||
return localAccessStrategy;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setCollectionAccessStrategy(CollectionRegionAccessStrategy strategy) {
|
||||
localAccessStrategy = strategy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void testCacheConfiguration() {
|
||||
assertFalse("Using Optimistic locking", isUsingOptimisticLocking());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,736 @@
|
|||
/*
|
||||
* 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.test.cache.jbc2.entity;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import junit.extensions.TestSetup;
|
||||
import junit.framework.AssertionFailedError;
|
||||
import junit.framework.Test;
|
||||
import junit.framework.TestSuite;
|
||||
|
||||
import org.hibernate.cache.CacheDataDescription;
|
||||
import org.hibernate.cache.EntityRegion;
|
||||
import org.hibernate.cache.access.AccessType;
|
||||
import org.hibernate.cache.access.EntityRegionAccessStrategy;
|
||||
import org.hibernate.cache.impl.CacheDataDescriptionImpl;
|
||||
import org.hibernate.cache.jbc2.BasicRegionAdapter;
|
||||
import org.hibernate.cache.jbc2.JBossCacheRegionFactory;
|
||||
import org.hibernate.cache.jbc2.MultiplexedJBossCacheRegionFactory;
|
||||
import org.hibernate.cache.jbc2.builder.MultiplexingCacheInstanceManager;
|
||||
import org.hibernate.cache.jbc2.entity.EntityRegionImpl;
|
||||
import org.hibernate.cache.jbc2.entity.TransactionalAccess;
|
||||
import org.hibernate.cache.jbc2.util.CacheHelper;
|
||||
import org.hibernate.cache.jbc2.util.NonLockingDataVersion;
|
||||
import org.hibernate.cfg.Configuration;
|
||||
import org.hibernate.test.cache.jbc2.AbstractJBossCacheTestCase;
|
||||
import org.hibernate.test.util.CacheTestUtil;
|
||||
import org.hibernate.util.ComparableComparator;
|
||||
import org.jboss.cache.Cache;
|
||||
import org.jboss.cache.Fqn;
|
||||
import org.jboss.cache.Node;
|
||||
import org.jboss.cache.NodeSPI;
|
||||
import org.jboss.cache.transaction.BatchModeTransactionManager;
|
||||
|
||||
/**
|
||||
* Base class for tests of EntityRegionAccessStrategy impls.
|
||||
*
|
||||
* @author <a href="brian.stansberry@jboss.com">Brian Stansberry</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public abstract class AbstractEntityRegionAccessStrategyTestCase extends AbstractJBossCacheTestCase {
|
||||
|
||||
public static final String REGION_NAME = "test/com.foo.test";
|
||||
public static final String KEY = "KEY";
|
||||
public static final String VALUE1 = "VALUE1";
|
||||
public static final String VALUE2 = "VALUE2";
|
||||
|
||||
protected static Configuration localCfg;
|
||||
protected static JBossCacheRegionFactory localRegionFactory;
|
||||
protected static Cache localCache;
|
||||
protected static Configuration remoteCfg;
|
||||
protected static JBossCacheRegionFactory remoteRegionFactory;
|
||||
protected static Cache remoteCache;
|
||||
|
||||
protected static boolean invalidation;
|
||||
protected static boolean optimistic;
|
||||
protected static boolean synchronous;
|
||||
|
||||
protected EntityRegion localEntityRegion;
|
||||
protected EntityRegionAccessStrategy localAccessStrategy;
|
||||
|
||||
protected EntityRegion remoteEntityRegion;
|
||||
protected EntityRegionAccessStrategy remoteAccessStrategy;
|
||||
|
||||
protected Exception node1Exception;
|
||||
protected Exception node2Exception;
|
||||
|
||||
protected AssertionFailedError node1Failure;
|
||||
protected AssertionFailedError node2Failure;
|
||||
|
||||
|
||||
public static Test getTestSetup(Class testClass, String configName) {
|
||||
TestSuite suite = new TestSuite(testClass);
|
||||
return new AccessStrategyTestSetup(suite, configName);
|
||||
}
|
||||
|
||||
public static Test getTestSetup(Test test, String configName) {
|
||||
return new AccessStrategyTestSetup(test, configName);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create a new TransactionalAccessTestCase.
|
||||
*
|
||||
* @param name
|
||||
*/
|
||||
public AbstractEntityRegionAccessStrategyTestCase(String name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
protected abstract AccessType getAccessType();
|
||||
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
|
||||
localEntityRegion = localRegionFactory.buildEntityRegion(REGION_NAME, localCfg.getProperties(), getCacheDataDescription());
|
||||
localAccessStrategy = localEntityRegion.buildAccessStrategy(getAccessType());
|
||||
|
||||
remoteEntityRegion = remoteRegionFactory.buildEntityRegion(REGION_NAME, remoteCfg.getProperties(), getCacheDataDescription());
|
||||
remoteAccessStrategy = remoteEntityRegion.buildAccessStrategy(getAccessType());
|
||||
|
||||
node1Exception = null;
|
||||
node2Exception = null;
|
||||
|
||||
node1Failure = null;
|
||||
node2Failure = null;
|
||||
}
|
||||
|
||||
protected void tearDown() throws Exception {
|
||||
|
||||
super.tearDown();
|
||||
|
||||
if (localEntityRegion != null)
|
||||
localEntityRegion.destroy();
|
||||
if (remoteEntityRegion != null)
|
||||
remoteEntityRegion.destroy();
|
||||
|
||||
try {
|
||||
localCache.getInvocationContext().getOptionOverrides().setCacheModeLocal(true);
|
||||
localCache.removeNode(Fqn.ROOT);
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.error("Problem purging local cache" ,e);
|
||||
}
|
||||
|
||||
try {
|
||||
remoteCache.getInvocationContext().getOptionOverrides().setCacheModeLocal(true);
|
||||
remoteCache.removeNode(Fqn.ROOT);
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.error("Problem purging remote cache" ,e);
|
||||
}
|
||||
|
||||
node1Exception = null;
|
||||
node2Exception = null;
|
||||
|
||||
node1Failure = null;
|
||||
node2Failure = null;
|
||||
}
|
||||
|
||||
protected static Configuration createConfiguration(String configName) {
|
||||
Configuration cfg = CacheTestUtil.buildConfiguration(REGION_PREFIX, MultiplexedJBossCacheRegionFactory.class, true, false);
|
||||
cfg.setProperty(MultiplexingCacheInstanceManager.ENTITY_CACHE_RESOURCE_PROP, configName);
|
||||
return cfg;
|
||||
}
|
||||
|
||||
protected CacheDataDescription getCacheDataDescription() {
|
||||
return new CacheDataDescriptionImpl(true, true, ComparableComparator.INSTANCE);
|
||||
}
|
||||
|
||||
protected boolean isUsingOptimisticLocking() {
|
||||
return optimistic;
|
||||
}
|
||||
|
||||
protected boolean isUsingInvalidation() {
|
||||
return invalidation;
|
||||
}
|
||||
|
||||
protected boolean isSynchronous() {
|
||||
return synchronous;
|
||||
}
|
||||
|
||||
protected Fqn getRegionFqn(String regionName, String regionPrefix) {
|
||||
return BasicRegionAdapter.getTypeLastRegionFqn(regionName, regionPrefix, EntityRegionImpl.TYPE);
|
||||
}
|
||||
|
||||
/**
|
||||
* This is just a setup test where we assert that the cache config is
|
||||
* as we expected.
|
||||
*/
|
||||
public abstract void testCacheConfiguration();
|
||||
|
||||
/**
|
||||
* Test method for {@link TransactionalAccess#getRegion()}.
|
||||
*/
|
||||
public void testGetRegion() {
|
||||
assertEquals("Correct region", localEntityRegion, localAccessStrategy.getRegion());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link TransactionalAccess#putFromLoad(java.lang.Object, java.lang.Object, long, java.lang.Object)}.
|
||||
*/
|
||||
public void testPutFromLoad() throws Exception {
|
||||
putFromLoadTest(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link TransactionalAccess#putFromLoad(java.lang.Object, java.lang.Object, long, java.lang.Object, boolean)}.
|
||||
*/
|
||||
public void testPutFromLoadMinimal() throws Exception {
|
||||
putFromLoadTest(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Simulate 2 nodes, both start, tx do a get, experience a cache miss,
|
||||
* then 'read from db.' First does a putFromLoad, then an update.
|
||||
* Second tries to do a putFromLoad with stale data (i.e. it took
|
||||
* longer to read from the db). Both commit their tx. Then
|
||||
* both start a new tx and get. First should see the updated data;
|
||||
* second should either see the updated data (isInvalidation()( == false)
|
||||
* or null (isInvalidation() == true).
|
||||
*
|
||||
* @param useMinimalAPI
|
||||
* @throws Exception
|
||||
*/
|
||||
private void putFromLoadTest(final boolean useMinimalAPI) throws Exception {
|
||||
|
||||
final CountDownLatch writeLatch1 = new CountDownLatch(1);
|
||||
final CountDownLatch writeLatch2 = new CountDownLatch(1);
|
||||
final CountDownLatch completionLatch = new CountDownLatch(2);
|
||||
|
||||
Thread node1 = new Thread() {
|
||||
|
||||
public void run() {
|
||||
|
||||
try {
|
||||
long txTimestamp = System.currentTimeMillis();
|
||||
BatchModeTransactionManager.getInstance().begin();
|
||||
|
||||
assertNull("node1 starts clean", localAccessStrategy.get(KEY, txTimestamp));
|
||||
|
||||
writeLatch1.await();
|
||||
|
||||
if (useMinimalAPI) {
|
||||
localAccessStrategy.putFromLoad(KEY, VALUE1, txTimestamp, new Integer(1), true);
|
||||
}
|
||||
else {
|
||||
localAccessStrategy.putFromLoad(KEY, VALUE1, txTimestamp, new Integer(1));
|
||||
}
|
||||
|
||||
localAccessStrategy.update(KEY, VALUE2, new Integer(2), new Integer(1));
|
||||
|
||||
BatchModeTransactionManager.getInstance().commit();
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.error("node1 caught exception", e);
|
||||
node1Exception = e;
|
||||
rollback();
|
||||
}
|
||||
catch (AssertionFailedError e) {
|
||||
node1Failure = e;
|
||||
rollback();
|
||||
}
|
||||
finally {
|
||||
// Let node2 write
|
||||
writeLatch2.countDown();
|
||||
completionLatch.countDown();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Thread node2 = new Thread() {
|
||||
|
||||
public void run() {
|
||||
|
||||
try {
|
||||
long txTimestamp = System.currentTimeMillis();
|
||||
BatchModeTransactionManager.getInstance().begin();
|
||||
|
||||
assertNull("node1 starts clean", remoteAccessStrategy.get(KEY, txTimestamp));
|
||||
|
||||
// Let node1 write
|
||||
writeLatch1.countDown();
|
||||
// Wait for node1 to finish
|
||||
writeLatch2.await();
|
||||
|
||||
if (useMinimalAPI) {
|
||||
remoteAccessStrategy.putFromLoad(KEY, VALUE1, txTimestamp, new Integer(1), true);
|
||||
}
|
||||
else {
|
||||
remoteAccessStrategy.putFromLoad(KEY, VALUE1, txTimestamp, new Integer(1));
|
||||
}
|
||||
|
||||
BatchModeTransactionManager.getInstance().commit();
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.error("node2 caught exception", e);
|
||||
node2Exception = e;
|
||||
rollback();
|
||||
}
|
||||
catch (AssertionFailedError e) {
|
||||
node2Failure = e;
|
||||
rollback();
|
||||
}
|
||||
finally {
|
||||
completionLatch.countDown();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
node1.setDaemon(true);
|
||||
node2.setDaemon(true);
|
||||
|
||||
node1.start();
|
||||
node2.start();
|
||||
|
||||
assertTrue("Threads completed", completionLatch.await(2, TimeUnit.SECONDS));
|
||||
|
||||
if (node1Failure != null)
|
||||
throw node1Failure;
|
||||
if (node2Failure != null)
|
||||
throw node2Failure;
|
||||
|
||||
assertEquals("node1 saw no exceptions", null, node1Exception);
|
||||
assertEquals("node2 saw no exceptions", null, node2Exception);
|
||||
|
||||
long txTimestamp = System.currentTimeMillis();
|
||||
assertEquals("Correct node1 value", VALUE2, localAccessStrategy.get(KEY, txTimestamp));
|
||||
|
||||
if (isUsingInvalidation()) {
|
||||
if (isUsingOptimisticLocking())
|
||||
// The node is "deleted" but it's ghost data version prevents the stale node2 PFER
|
||||
assertEquals("Correct node2 value", null, remoteAccessStrategy.get(KEY, txTimestamp));
|
||||
else {
|
||||
// no data version to prevent the PFER; we count on db locks preventing this
|
||||
assertEquals("Expected node2 value", VALUE1, remoteAccessStrategy.get(KEY, txTimestamp));
|
||||
}
|
||||
}
|
||||
else {
|
||||
// The node1 update is replicated, preventing the node2 PFER
|
||||
assertEquals("Correct node2 value", VALUE2, remoteAccessStrategy.get(KEY, txTimestamp));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link TransactionalAccess#insert(java.lang.Object, java.lang.Object, java.lang.Object)}.
|
||||
*/
|
||||
public void testInsert() throws Exception {
|
||||
|
||||
final CountDownLatch readLatch = new CountDownLatch(1);
|
||||
final CountDownLatch commitLatch = new CountDownLatch(1);
|
||||
final CountDownLatch completionLatch = new CountDownLatch(2);
|
||||
|
||||
Thread inserter = new Thread() {
|
||||
|
||||
public void run() {
|
||||
|
||||
try {
|
||||
long txTimestamp = System.currentTimeMillis();
|
||||
BatchModeTransactionManager.getInstance().begin();
|
||||
|
||||
assertNull("Correct initial value", localAccessStrategy.get(KEY, txTimestamp));
|
||||
|
||||
localAccessStrategy.insert(KEY, VALUE1, new Integer(1));
|
||||
|
||||
readLatch.countDown();
|
||||
commitLatch.await();
|
||||
|
||||
BatchModeTransactionManager.getInstance().commit();
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.error("node1 caught exception", e);
|
||||
node1Exception = e;
|
||||
rollback();
|
||||
}
|
||||
catch (AssertionFailedError e) {
|
||||
node1Failure = e;
|
||||
rollback();
|
||||
}
|
||||
finally {
|
||||
completionLatch.countDown();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Thread reader = new Thread() {
|
||||
|
||||
public void run() {
|
||||
|
||||
try {
|
||||
long txTimestamp = System.currentTimeMillis();
|
||||
BatchModeTransactionManager.getInstance().begin();
|
||||
|
||||
readLatch.await();
|
||||
Object expected = isUsingOptimisticLocking() ? null : VALUE1;
|
||||
|
||||
assertEquals("Correct initial value", expected, localAccessStrategy.get(KEY, txTimestamp));
|
||||
|
||||
BatchModeTransactionManager.getInstance().commit();
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.error("node1 caught exception", e);
|
||||
node1Exception = e;
|
||||
rollback();
|
||||
}
|
||||
catch (AssertionFailedError e) {
|
||||
node1Failure = e;
|
||||
rollback();
|
||||
}
|
||||
finally {
|
||||
commitLatch.countDown();
|
||||
completionLatch.countDown();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
inserter.setDaemon(true);
|
||||
reader.setDaemon(true);
|
||||
inserter.start();
|
||||
reader.start();
|
||||
|
||||
if (isUsingOptimisticLocking())
|
||||
assertTrue("Threads completed", completionLatch.await(1, TimeUnit.SECONDS));
|
||||
else {
|
||||
// Reader should be blocking for lock
|
||||
assertFalse("Threads completed", completionLatch.await(250, TimeUnit.MILLISECONDS));
|
||||
commitLatch.countDown();
|
||||
assertTrue("Threads completed", completionLatch.await(1, TimeUnit.SECONDS));
|
||||
}
|
||||
|
||||
if (node1Failure != null)
|
||||
throw node1Failure;
|
||||
if (node2Failure != null)
|
||||
throw node2Failure;
|
||||
|
||||
assertEquals("node1 saw no exceptions", null, node1Exception);
|
||||
assertEquals("node2 saw no exceptions", null, node2Exception);
|
||||
|
||||
long txTimestamp = System.currentTimeMillis();
|
||||
assertEquals("Correct node1 value", VALUE1, localAccessStrategy.get(KEY, txTimestamp));
|
||||
Object expected = isUsingInvalidation() ? null : VALUE1;
|
||||
assertEquals("Correct node2 value", expected, remoteAccessStrategy.get(KEY, txTimestamp));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link TransactionalAccess#update(java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object)}.
|
||||
*/
|
||||
public void testUpdate() throws Exception {
|
||||
|
||||
// Set up initial state
|
||||
localAccessStrategy.putFromLoad(KEY, VALUE1, System.currentTimeMillis(), new Integer(1));
|
||||
remoteAccessStrategy.putFromLoad(KEY, VALUE1, System.currentTimeMillis(), new Integer(1));
|
||||
|
||||
// Let the async put propagate
|
||||
sleep(250);
|
||||
|
||||
final CountDownLatch readLatch = new CountDownLatch(1);
|
||||
final CountDownLatch commitLatch = new CountDownLatch(1);
|
||||
final CountDownLatch completionLatch = new CountDownLatch(2);
|
||||
|
||||
Thread updater = new Thread() {
|
||||
|
||||
public void run() {
|
||||
|
||||
try {
|
||||
long txTimestamp = System.currentTimeMillis();
|
||||
BatchModeTransactionManager.getInstance().begin();
|
||||
|
||||
assertEquals("Correct initial value", VALUE1, localAccessStrategy.get(KEY, txTimestamp));
|
||||
|
||||
localAccessStrategy.update(KEY, VALUE2, new Integer(2), new Integer(1));
|
||||
|
||||
readLatch.countDown();
|
||||
commitLatch.await();
|
||||
|
||||
BatchModeTransactionManager.getInstance().commit();
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.error("node1 caught exception", e);
|
||||
node1Exception = e;
|
||||
rollback();
|
||||
}
|
||||
catch (AssertionFailedError e) {
|
||||
node1Failure = e;
|
||||
rollback();
|
||||
}
|
||||
finally {
|
||||
completionLatch.countDown();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Thread reader = new Thread() {
|
||||
|
||||
public void run() {
|
||||
try {
|
||||
long txTimestamp = System.currentTimeMillis();
|
||||
BatchModeTransactionManager.getInstance().begin();
|
||||
|
||||
readLatch.await();
|
||||
|
||||
// This will block w/ pessimistic locking and then
|
||||
// read the new value; w/ optimistic it shouldn't
|
||||
// block and will read the old value
|
||||
Object expected = isUsingOptimisticLocking() ? VALUE1 : VALUE2;
|
||||
assertEquals("Correct value", expected, localAccessStrategy.get(KEY, txTimestamp));
|
||||
|
||||
BatchModeTransactionManager.getInstance().commit();
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.error("node1 caught exception", e);
|
||||
node1Exception = e;
|
||||
rollback();
|
||||
}
|
||||
catch (AssertionFailedError e) {
|
||||
node1Failure = e;
|
||||
rollback();
|
||||
}
|
||||
finally {
|
||||
commitLatch.countDown();
|
||||
completionLatch.countDown();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
updater.setDaemon(true);
|
||||
reader.setDaemon(true);
|
||||
updater.start();
|
||||
reader.start();
|
||||
|
||||
if (isUsingOptimisticLocking())
|
||||
// Should complete promptly
|
||||
assertTrue(completionLatch.await(1, TimeUnit.SECONDS));
|
||||
else {
|
||||
// Reader thread should be blocking
|
||||
assertFalse(completionLatch.await(250, TimeUnit.MILLISECONDS));
|
||||
// Let the writer commit down
|
||||
commitLatch.countDown();
|
||||
assertTrue(completionLatch.await(1, TimeUnit.SECONDS));
|
||||
}
|
||||
|
||||
if (node1Failure != null)
|
||||
throw node1Failure;
|
||||
if (node2Failure != null)
|
||||
throw node2Failure;
|
||||
|
||||
assertEquals("node1 saw no exceptions", null, node1Exception);
|
||||
assertEquals("node2 saw no exceptions", null, node2Exception);
|
||||
|
||||
long txTimestamp = System.currentTimeMillis();
|
||||
assertEquals("Correct node1 value", VALUE2, localAccessStrategy.get(KEY, txTimestamp));
|
||||
Object expected = isUsingInvalidation() ? null : VALUE2;
|
||||
assertEquals("Correct node2 value", expected, remoteAccessStrategy.get(KEY, txTimestamp));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link TransactionalAccess#remove(java.lang.Object)}.
|
||||
*/
|
||||
public void testRemove() {
|
||||
evictOrRemoveTest(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link TransactionalAccess#removeAll()}.
|
||||
*/
|
||||
public void testRemoveAll() {
|
||||
evictOrRemoveAllTest(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link TransactionalAccess#evict(java.lang.Object)}.
|
||||
*
|
||||
* FIXME add testing of the "immediately without regard for transaction
|
||||
* isolation" bit in the EntityRegionAccessStrategy API.
|
||||
*/
|
||||
public void testEvict() {
|
||||
evictOrRemoveTest(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link TransactionalAccess#evictAll()}.
|
||||
*
|
||||
* FIXME add testing of the "immediately without regard for transaction
|
||||
* isolation" bit in the EntityRegionAccessStrategy API.
|
||||
*/
|
||||
public void testEvictAll() {
|
||||
evictOrRemoveAllTest(true);
|
||||
}
|
||||
|
||||
private void evictOrRemoveTest(boolean evict) {
|
||||
assertNull("local is clean", localAccessStrategy.get(KEY, System.currentTimeMillis()));
|
||||
assertNull("remote is clean", remoteAccessStrategy.get(KEY, System.currentTimeMillis()));
|
||||
|
||||
localAccessStrategy.putFromLoad(KEY, VALUE1, System.currentTimeMillis(), new Integer(1));
|
||||
assertEquals(VALUE1, localAccessStrategy.get(KEY, System.currentTimeMillis()));
|
||||
remoteAccessStrategy.putFromLoad(KEY, VALUE1, System.currentTimeMillis(), new Integer(1));
|
||||
assertEquals(VALUE1, remoteAccessStrategy.get(KEY, System.currentTimeMillis()));
|
||||
|
||||
// Wait for async propagation
|
||||
sleep(250);
|
||||
|
||||
if (evict)
|
||||
localAccessStrategy.evict(KEY);
|
||||
else
|
||||
localAccessStrategy.remove(KEY);
|
||||
|
||||
assertEquals(null, localAccessStrategy.get(KEY, System.currentTimeMillis()));
|
||||
|
||||
// sleep(1000);
|
||||
|
||||
assertEquals(null, remoteAccessStrategy.get(KEY, System.currentTimeMillis()));
|
||||
}
|
||||
|
||||
private void evictOrRemoveAllTest(boolean evict) {
|
||||
|
||||
Fqn regionFqn = getRegionFqn(REGION_NAME, REGION_PREFIX);
|
||||
|
||||
Node regionRoot = localCache.getRoot().getChild(regionFqn);
|
||||
assertFalse(regionRoot == null);
|
||||
assertEquals(0, regionRoot.getChildrenNames().size());
|
||||
assertTrue(regionRoot.isResident());
|
||||
|
||||
if (isUsingOptimisticLocking()) {
|
||||
assertEquals(NonLockingDataVersion.class, ((NodeSPI) regionRoot).getVersion().getClass());
|
||||
}
|
||||
|
||||
regionRoot = remoteCache.getRoot().getChild(regionFqn);
|
||||
assertFalse(regionRoot == null);
|
||||
assertEquals(0, regionRoot.getChildrenNames().size());
|
||||
assertTrue(regionRoot.isResident());
|
||||
|
||||
if (isUsingOptimisticLocking()) {
|
||||
assertEquals(NonLockingDataVersion.class, ((NodeSPI) regionRoot).getVersion().getClass());
|
||||
}
|
||||
|
||||
assertNull("local is clean", localAccessStrategy.get(KEY, System.currentTimeMillis()));
|
||||
assertNull("remote is clean", remoteAccessStrategy.get(KEY, System.currentTimeMillis()));
|
||||
|
||||
localAccessStrategy.putFromLoad(KEY, VALUE1, System.currentTimeMillis(), new Integer(1));
|
||||
assertEquals(VALUE1, localAccessStrategy.get(KEY, System.currentTimeMillis()));
|
||||
remoteAccessStrategy.putFromLoad(KEY, VALUE1, System.currentTimeMillis(), new Integer(1));
|
||||
assertEquals(VALUE1, remoteAccessStrategy.get(KEY, System.currentTimeMillis()));
|
||||
|
||||
// Wait for async propagation
|
||||
sleep(250);
|
||||
|
||||
|
||||
|
||||
if (isUsingOptimisticLocking()) {
|
||||
regionRoot = localCache.getRoot().getChild(regionFqn);
|
||||
assertEquals(NonLockingDataVersion.class, ((NodeSPI) regionRoot).getVersion().getClass());
|
||||
regionRoot = remoteCache.getRoot().getChild(regionFqn);
|
||||
assertEquals(NonLockingDataVersion.class, ((NodeSPI) regionRoot).getVersion().getClass());
|
||||
}
|
||||
|
||||
if (evict)
|
||||
localAccessStrategy.evictAll();
|
||||
else
|
||||
localAccessStrategy.removeAll();
|
||||
|
||||
regionRoot = localCache.getRoot().getChild(regionFqn);
|
||||
assertFalse(regionRoot == null);
|
||||
assertEquals(0, regionRoot.getChildrenNames().size());
|
||||
assertTrue(regionRoot.isResident());
|
||||
|
||||
regionRoot = remoteCache.getRoot().getChild(regionFqn);
|
||||
assertFalse(regionRoot == null);
|
||||
if (isUsingInvalidation()) {
|
||||
// JBC seems broken: see http://www.jboss.com/index.html?module=bb&op=viewtopic&t=121408
|
||||
// FIXME replace with the following when JBCACHE-1199 and JBCACHE-1200 are done:
|
||||
//assertFalse(regionRoot.isValid());
|
||||
checkNodeIsEmpty(regionRoot);
|
||||
}
|
||||
else {
|
||||
// Same assertion, just different assertion msg
|
||||
assertEquals(0, regionRoot.getChildrenNames().size());
|
||||
}
|
||||
assertTrue(regionRoot.isResident());
|
||||
|
||||
assertNull("local is clean", localAccessStrategy.get(KEY, System.currentTimeMillis()));
|
||||
assertNull("remote is clean", remoteAccessStrategy.get(KEY, System.currentTimeMillis()));
|
||||
}
|
||||
|
||||
private void checkNodeIsEmpty(Node node) {
|
||||
assertEquals("Known issue JBCACHE-1200. node " + node.getFqn() + " should not have keys", 0, node.getKeys().size());
|
||||
for (Iterator it = node.getChildren().iterator(); it.hasNext(); ) {
|
||||
checkNodeIsEmpty((Node) it.next());
|
||||
}
|
||||
}
|
||||
|
||||
protected void rollback() {
|
||||
try {
|
||||
BatchModeTransactionManager.getInstance().rollback();
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class AccessStrategyTestSetup extends TestSetup {
|
||||
|
||||
private String configName;
|
||||
|
||||
public AccessStrategyTestSetup(Test test, String configName) {
|
||||
super(test);
|
||||
this.configName = configName;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
localCfg = createConfiguration(configName);
|
||||
localRegionFactory = CacheTestUtil.startRegionFactory(localCfg);
|
||||
localCache = localRegionFactory.getCacheInstanceManager().getEntityCacheInstance();
|
||||
|
||||
remoteCfg = createConfiguration(configName);
|
||||
remoteRegionFactory = CacheTestUtil.startRegionFactory(remoteCfg);
|
||||
remoteCache = remoteRegionFactory.getCacheInstanceManager().getEntityCacheInstance();
|
||||
|
||||
invalidation = CacheHelper.isClusteredInvalidation(localCache);
|
||||
synchronous = CacheHelper.isSynchronous(localCache);
|
||||
optimistic = localCache.getConfiguration().getNodeLockingScheme() == org.jboss.cache.config.Configuration.NodeLockingScheme.OPTIMISTIC;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void tearDown() throws Exception {
|
||||
super.tearDown();
|
||||
|
||||
if (localRegionFactory != null)
|
||||
localRegionFactory.stop();
|
||||
|
||||
if (remoteRegionFactory != null)
|
||||
remoteRegionFactory.stop();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* 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.test.cache.jbc2.entity;
|
||||
|
||||
import org.hibernate.cache.access.AccessType;
|
||||
import org.jboss.cache.transaction.BatchModeTransactionManager;
|
||||
|
||||
/**
|
||||
* Base class for tests of TRANSACTIONAL access.
|
||||
*
|
||||
* @author <a href="brian.stansberry@jboss.com">Brian Stansberry</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public abstract class AbstractReadOnlyAccessTestCase extends AbstractEntityRegionAccessStrategyTestCase {
|
||||
|
||||
/**
|
||||
* Create a new AbstractTransactionalAccessTestCase.
|
||||
*
|
||||
*/
|
||||
public AbstractReadOnlyAccessTestCase(String name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AccessType getAccessType() {
|
||||
return AccessType.READ_ONLY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void testPutFromLoad() throws Exception {
|
||||
putFromLoadTest(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void testPutFromLoadMinimal() throws Exception {
|
||||
putFromLoadTest(true);
|
||||
}
|
||||
|
||||
private void putFromLoadTest(boolean minimal) throws Exception {
|
||||
long txTimestamp = System.currentTimeMillis();
|
||||
BatchModeTransactionManager.getInstance().begin();
|
||||
assertNull(localAccessStrategy.get(KEY, System.currentTimeMillis()));
|
||||
if (minimal)
|
||||
localAccessStrategy.putFromLoad(KEY, VALUE1, txTimestamp, new Integer(1), true);
|
||||
else
|
||||
localAccessStrategy.putFromLoad(KEY, VALUE1, txTimestamp, new Integer(1));
|
||||
|
||||
sleep(250);
|
||||
Object expected = isUsingInvalidation() ? null : VALUE1;
|
||||
assertEquals(expected, remoteAccessStrategy.get(KEY, System.currentTimeMillis()));
|
||||
|
||||
BatchModeTransactionManager.getInstance().commit();
|
||||
assertEquals(VALUE1, localAccessStrategy.get(KEY, System.currentTimeMillis()));
|
||||
assertEquals(expected, remoteAccessStrategy.get(KEY, System.currentTimeMillis()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void testUpdate() throws Exception {
|
||||
try {
|
||||
localAccessStrategy.update(KEY, VALUE2, new Integer(2), new Integer(1));
|
||||
fail("Call to update did not throw exception");
|
||||
}
|
||||
catch (UnsupportedOperationException good) {}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,137 @@
|
|||
/*
|
||||
* 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.test.cache.jbc2.entity;
|
||||
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import junit.framework.AssertionFailedError;
|
||||
|
||||
import org.hibernate.cache.access.AccessType;
|
||||
import org.jboss.cache.transaction.BatchModeTransactionManager;
|
||||
|
||||
/**
|
||||
* Base class for tests of TRANSACTIONAL access.
|
||||
*
|
||||
* @author <a href="brian.stansberry@jboss.com">Brian Stansberry</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public abstract class AbstractTransactionalAccessTestCase extends AbstractEntityRegionAccessStrategyTestCase {
|
||||
|
||||
/**
|
||||
* Create a new AbstractTransactionalAccessTestCase.
|
||||
*
|
||||
*/
|
||||
public AbstractTransactionalAccessTestCase(String name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AccessType getAccessType() {
|
||||
return AccessType.TRANSACTIONAL;
|
||||
}
|
||||
|
||||
public void testContestedPutFromLoad() throws Exception {
|
||||
|
||||
localAccessStrategy.putFromLoad(KEY, VALUE1, System.currentTimeMillis(), new Integer(1));
|
||||
|
||||
final CountDownLatch pferLatch = new CountDownLatch(1);
|
||||
final CountDownLatch pferCompletionLatch = new CountDownLatch(1);
|
||||
final CountDownLatch commitLatch = new CountDownLatch(1);
|
||||
final CountDownLatch completionLatch = new CountDownLatch(1);
|
||||
|
||||
Thread blocker = new Thread() {
|
||||
|
||||
public void run() {
|
||||
|
||||
try {
|
||||
long txTimestamp = System.currentTimeMillis();
|
||||
BatchModeTransactionManager.getInstance().begin();
|
||||
|
||||
assertEquals("Correct initial value", VALUE1, localAccessStrategy.get(KEY, txTimestamp));
|
||||
|
||||
localAccessStrategy.update(KEY, VALUE2, new Integer(2), new Integer(1));
|
||||
|
||||
pferLatch.countDown();
|
||||
commitLatch.await();
|
||||
|
||||
BatchModeTransactionManager.getInstance().commit();
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.error("node1 caught exception", e);
|
||||
node1Exception = e;
|
||||
rollback();
|
||||
}
|
||||
catch (AssertionFailedError e) {
|
||||
node1Failure = e;
|
||||
rollback();
|
||||
}
|
||||
finally {
|
||||
completionLatch.countDown();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Thread putter = new Thread() {
|
||||
|
||||
public void run() {
|
||||
|
||||
try {
|
||||
long txTimestamp = System.currentTimeMillis();
|
||||
BatchModeTransactionManager.getInstance().begin();
|
||||
|
||||
localAccessStrategy.putFromLoad(KEY, VALUE1, txTimestamp, new Integer(1));
|
||||
|
||||
BatchModeTransactionManager.getInstance().commit();
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.error("node1 caught exception", e);
|
||||
node1Exception = e;
|
||||
rollback();
|
||||
}
|
||||
catch (AssertionFailedError e) {
|
||||
node1Failure = e;
|
||||
rollback();
|
||||
}
|
||||
finally {
|
||||
pferCompletionLatch.countDown();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
blocker.start();
|
||||
assertTrue("Active tx has done an update", pferLatch.await(1, TimeUnit.SECONDS));
|
||||
putter.start();
|
||||
assertTrue("putFromLoadreturns promtly", pferCompletionLatch.await(10, TimeUnit.MILLISECONDS));
|
||||
|
||||
commitLatch.countDown();
|
||||
|
||||
assertTrue("Threads completed", completionLatch.await(1, TimeUnit.SECONDS));
|
||||
|
||||
if (node1Failure != null)
|
||||
throw node1Failure;
|
||||
if (node2Failure != null)
|
||||
throw node2Failure;
|
||||
|
||||
assertEquals("node1 saw no exceptions", null, node1Exception);
|
||||
assertEquals("node2 saw no exceptions", null, node2Exception);
|
||||
|
||||
long txTimestamp = System.currentTimeMillis();
|
||||
assertEquals("Correct node1 value", VALUE2, localAccessStrategy.get(KEY, txTimestamp));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,98 @@
|
|||
/*
|
||||
* 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.test.cache.jbc2.entity;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import org.hibernate.cache.CacheDataDescription;
|
||||
import org.hibernate.cache.CacheException;
|
||||
import org.hibernate.cache.EntityRegion;
|
||||
import org.hibernate.cache.Region;
|
||||
import org.hibernate.cache.RegionFactory;
|
||||
import org.hibernate.cache.access.AccessType;
|
||||
import org.hibernate.cache.jbc2.BasicRegionAdapter;
|
||||
import org.hibernate.cache.jbc2.CacheInstanceManager;
|
||||
import org.hibernate.cache.jbc2.JBossCacheRegionFactory;
|
||||
import org.hibernate.cache.jbc2.entity.EntityRegionImpl;
|
||||
import org.hibernate.test.cache.jbc2.AbstractEntityCollectionRegionTestCase;
|
||||
import org.jboss.cache.Cache;
|
||||
import org.jboss.cache.Fqn;
|
||||
|
||||
/**
|
||||
* Tests of EntityRegionImpl.
|
||||
*
|
||||
* @author <a href="brian.stansberry@jboss.com">Brian Stansberry</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class EntityRegionImplTestCase extends AbstractEntityCollectionRegionTestCase {
|
||||
|
||||
/**
|
||||
* Create a new EntityRegionImplTestCase.
|
||||
*
|
||||
* @param name
|
||||
*/
|
||||
public EntityRegionImplTestCase(String name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
protected void supportedAccessTypeTest(RegionFactory regionFactory, Properties properties) {
|
||||
|
||||
EntityRegion region = regionFactory.buildEntityRegion("test", properties, null);
|
||||
|
||||
assertNull("Got TRANSACTIONAL", region.buildAccessStrategy(AccessType.TRANSACTIONAL).lockRegion());
|
||||
|
||||
try
|
||||
{
|
||||
region.buildAccessStrategy(AccessType.READ_ONLY).lockRegion();
|
||||
fail("Did not get READ_ONLY");
|
||||
}
|
||||
catch (UnsupportedOperationException good) {}
|
||||
|
||||
try
|
||||
{
|
||||
region.buildAccessStrategy(AccessType.NONSTRICT_READ_WRITE);
|
||||
fail("Incorrectly got NONSTRICT_READ_WRITE");
|
||||
}
|
||||
catch (CacheException good) {}
|
||||
|
||||
try
|
||||
{
|
||||
region.buildAccessStrategy(AccessType.READ_WRITE);
|
||||
fail("Incorrectly got READ_WRITE");
|
||||
}
|
||||
catch (CacheException good) {}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Region createRegion(JBossCacheRegionFactory regionFactory, String regionName, Properties properties, CacheDataDescription cdd) {
|
||||
return regionFactory.buildEntityRegion(regionName, properties, cdd);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Cache getJBossCache(JBossCacheRegionFactory regionFactory) {
|
||||
CacheInstanceManager mgr = regionFactory.getCacheInstanceManager();
|
||||
return mgr.getEntityCacheInstance();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Fqn getRegionFqn(String regionName, String regionPrefix) {
|
||||
return BasicRegionAdapter.getTypeLastRegionFqn(regionName, regionPrefix, EntityRegionImpl.TYPE);
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* 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.test.cache.jbc2.entity;
|
||||
|
||||
import junit.framework.Test;
|
||||
import junit.framework.TestSuite;
|
||||
|
||||
/**
|
||||
* Tests TRANSACTIONAL access when optimistic locking and invalidation are used.
|
||||
*
|
||||
* @author <a href="brian.stansberry@jboss.com">Brian Stansberry</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class OptimisticInvalidatedTransactionalTestCase extends AbstractTransactionalAccessTestCase {
|
||||
|
||||
/**
|
||||
* Create a new OptimisticInvalidatedTransactionalTestCase.
|
||||
*
|
||||
* @param name
|
||||
*/
|
||||
public OptimisticInvalidatedTransactionalTestCase(String name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
public static Test suite() throws Exception {
|
||||
TestSuite suite = createFailureExpectedSuite(OptimisticInvalidatedTransactionalTestCase.class);
|
||||
return getTestSetup(suite, "optimistic-entity");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void testCacheConfiguration() {
|
||||
assertTrue("Using Invalidation", isUsingInvalidation());
|
||||
assertTrue("Using Optimistic locking", isUsingOptimisticLocking());
|
||||
assertTrue("Synchronous mode", isSynchronous());
|
||||
}
|
||||
|
||||
// Known failures
|
||||
|
||||
public void testEvictAllFailureExpected() {
|
||||
super.testEvictAll();
|
||||
}
|
||||
|
||||
public void testRemoveAllFailureExpected() {
|
||||
super.testRemoveAll();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,98 @@
|
|||
/*
|
||||
* 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.test.cache.jbc2.entity;
|
||||
|
||||
import org.hibernate.cache.access.AccessType;
|
||||
import org.hibernate.cache.access.EntityRegionAccessStrategy;
|
||||
import org.hibernate.cache.jbc2.entity.TransactionalAccess;
|
||||
|
||||
/**
|
||||
* Tests for the "extra API" in EntityRegionAccessStrategy; in this
|
||||
* version using Optimistic locking with READ_ONLY access.
|
||||
* <p>
|
||||
* By "extra API" we mean those methods that are superfluous to the
|
||||
* function of the JBC integration, where the impl is a no-op or a static
|
||||
* false return value, UnsupportedOperationException, etc.
|
||||
*
|
||||
* @author <a href="brian.stansberry@jboss.com">Brian Stansberry</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class OptimisticReadOnlyExtraAPITestCase extends OptimisticTransactionalExtraAPITestCase {
|
||||
|
||||
private static EntityRegionAccessStrategy localAccessStrategy;
|
||||
|
||||
/**
|
||||
* Create a new TransactionalAccessTestCase.
|
||||
*
|
||||
* @param name
|
||||
*/
|
||||
public OptimisticReadOnlyExtraAPITestCase(String name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AccessType getAccessType() {
|
||||
return AccessType.READ_ONLY;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected EntityRegionAccessStrategy getEntityAccessStrategy() {
|
||||
return localAccessStrategy;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setEntityRegionAccessStrategy(EntityRegionAccessStrategy strategy) {
|
||||
localAccessStrategy = strategy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link TransactionalAccess#lockItem(java.lang.Object, java.lang.Object)}.
|
||||
*/
|
||||
@Override
|
||||
public void testLockItem() {
|
||||
try {
|
||||
getEntityAccessStrategy().lockItem(KEY, new Integer(1));
|
||||
fail("Call to lockItem did not throw exception");
|
||||
}
|
||||
catch (UnsupportedOperationException expected) {}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link TransactionalAccess#lockRegion()}.
|
||||
*/
|
||||
@Override
|
||||
public void testLockRegion() {
|
||||
try {
|
||||
getEntityAccessStrategy().lockRegion();
|
||||
fail("Call to lockRegion did not throw exception");
|
||||
}
|
||||
catch (UnsupportedOperationException expected) {}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link TransactionalAccess#afterUpdate(java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object, org.hibernate.cache.access.SoftLock)}.
|
||||
*/
|
||||
@Override
|
||||
public void testAfterUpdate() {
|
||||
try {
|
||||
getEntityAccessStrategy().afterUpdate(KEY, VALUE2, new Integer(1), new Integer(2), new MockSoftLock());
|
||||
fail("Call to afterUpdate did not throw exception");
|
||||
}
|
||||
catch (UnsupportedOperationException expected) {}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* 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.test.cache.jbc2.entity;
|
||||
|
||||
import junit.framework.Test;
|
||||
import junit.framework.TestSuite;
|
||||
|
||||
/**
|
||||
* Tests READ_ONLY access when optimistic locking and invalidation are used.
|
||||
*
|
||||
* @author <a href="brian.stansberry@jboss.com">Brian Stansberry</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class OptimisticReadOnlyTestCase extends AbstractReadOnlyAccessTestCase {
|
||||
|
||||
/**
|
||||
* Create a new PessimisticTransactionalAccessTestCase.
|
||||
*
|
||||
* @param name
|
||||
*/
|
||||
public OptimisticReadOnlyTestCase(String name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
public static Test suite() throws Exception {
|
||||
TestSuite suite = createFailureExpectedSuite(OptimisticReadOnlyTestCase.class);
|
||||
return getTestSetup(suite, "optimistic-entity");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void testCacheConfiguration() {
|
||||
assertTrue("Using Invalidation", isUsingInvalidation());
|
||||
assertTrue("Using Optimistic locking", isUsingOptimisticLocking());
|
||||
assertTrue("Synchronous mode", isSynchronous());
|
||||
}
|
||||
|
||||
// Known failures
|
||||
|
||||
public void testEvictAllFailureExpected() {
|
||||
super.testEvictAll();
|
||||
}
|
||||
|
||||
public void testRemoveAllFailureExpected() {
|
||||
super.testRemoveAll();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* 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.test.cache.jbc2.entity;
|
||||
|
||||
import junit.framework.Test;
|
||||
|
||||
/**
|
||||
* Tests TRANSACTIONAL access when optimistic locking and replication are used.
|
||||
*
|
||||
* @author <a href="brian.stansberry@jboss.com">Brian Stansberry</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class OptimisticReplicatedTransactionalTestCase extends AbstractTransactionalAccessTestCase {
|
||||
|
||||
/**
|
||||
* Create a new PessimisticTransactionalAccessTestCase.
|
||||
*
|
||||
* @param name
|
||||
*/
|
||||
public OptimisticReplicatedTransactionalTestCase(String name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
public static Test suite() throws Exception {
|
||||
return getTestSetup(OptimisticReplicatedTransactionalTestCase.class, "optimistic-shared");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void testCacheConfiguration() {
|
||||
assertFalse("Using Invalidation", isUsingInvalidation());
|
||||
assertTrue("Using Optimistic locking", isUsingOptimisticLocking());
|
||||
assertTrue("Synchronous mode", isSynchronous());
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,161 @@
|
|||
/*
|
||||
* 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.test.cache.jbc2.entity;
|
||||
|
||||
import org.hibernate.cache.EntityRegion;
|
||||
import org.hibernate.cache.access.AccessType;
|
||||
import org.hibernate.cache.access.EntityRegionAccessStrategy;
|
||||
import org.hibernate.cache.access.SoftLock;
|
||||
import org.hibernate.cache.jbc2.JBossCacheRegionFactory;
|
||||
import org.hibernate.cache.jbc2.MultiplexedJBossCacheRegionFactory;
|
||||
import org.hibernate.cache.jbc2.builder.MultiplexingCacheInstanceManager;
|
||||
import org.hibernate.cache.jbc2.entity.TransactionalAccess;
|
||||
import org.hibernate.cfg.Configuration;
|
||||
import org.hibernate.test.cache.jbc2.AbstractJBossCacheTestCase;
|
||||
import org.hibernate.test.util.CacheTestUtil;
|
||||
import org.jboss.cache.Cache;
|
||||
|
||||
/**
|
||||
* Tests for the "extra API" in EntityRegionAccessStrategy; in this base
|
||||
* version using Optimistic locking with TRANSACTIONAL access.
|
||||
* <p>
|
||||
* By "extra API" we mean those methods that are superfluous to the
|
||||
* function of the JBC integration, where the impl is a no-op or a static
|
||||
* false return value, UnsupportedOperationException, etc.
|
||||
*
|
||||
* @author <a href="brian.stansberry@jboss.com">Brian Stansberry</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class OptimisticTransactionalExtraAPITestCase extends AbstractJBossCacheTestCase {
|
||||
|
||||
public static final String REGION_NAME = "test/com.foo.test";
|
||||
public static final String KEY = "KEY";
|
||||
public static final String VALUE1 = "VALUE1";
|
||||
public static final String VALUE2 = "VALUE2";
|
||||
|
||||
private static EntityRegionAccessStrategy localAccessStrategy;
|
||||
|
||||
private static boolean optimistic;
|
||||
|
||||
/**
|
||||
* Create a new TransactionalAccessTestCase.
|
||||
*
|
||||
* @param name
|
||||
*/
|
||||
public OptimisticTransactionalExtraAPITestCase(String name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
|
||||
if (getEntityAccessStrategy() == null) {
|
||||
Configuration cfg = createConfiguration();
|
||||
JBossCacheRegionFactory rf = CacheTestUtil.startRegionFactory(cfg, getCacheTestSupport());
|
||||
Cache localCache = rf.getCacheInstanceManager().getEntityCacheInstance();
|
||||
optimistic = localCache.getConfiguration().getNodeLockingScheme() == org.jboss.cache.config.Configuration.NodeLockingScheme.OPTIMISTIC;
|
||||
EntityRegion localEntityRegion = rf.buildEntityRegion(REGION_NAME, cfg.getProperties(), null);
|
||||
setEntityRegionAccessStrategy(localEntityRegion.buildAccessStrategy(getAccessType()));
|
||||
}
|
||||
}
|
||||
|
||||
protected void tearDown() throws Exception {
|
||||
|
||||
super.tearDown();
|
||||
}
|
||||
|
||||
protected Configuration createConfiguration() {
|
||||
Configuration cfg = CacheTestUtil.buildConfiguration(REGION_PREFIX, MultiplexedJBossCacheRegionFactory.class, true, false);
|
||||
cfg.setProperty(MultiplexingCacheInstanceManager.ENTITY_CACHE_RESOURCE_PROP, getCacheConfigName());
|
||||
return cfg;
|
||||
}
|
||||
|
||||
protected String getCacheConfigName() {
|
||||
return "optimistic-entity";
|
||||
}
|
||||
|
||||
protected boolean isUsingOptimisticLocking() {
|
||||
return optimistic;
|
||||
}
|
||||
|
||||
protected AccessType getAccessType() {
|
||||
return AccessType.TRANSACTIONAL;
|
||||
}
|
||||
|
||||
protected EntityRegionAccessStrategy getEntityAccessStrategy() {
|
||||
return localAccessStrategy;
|
||||
}
|
||||
|
||||
protected void setEntityRegionAccessStrategy(EntityRegionAccessStrategy strategy) {
|
||||
localAccessStrategy = strategy;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is just a setup test where we assert that the cache config is
|
||||
* as we expected.
|
||||
*/
|
||||
public void testCacheConfiguration() {
|
||||
assertTrue("Using Optimistic locking", isUsingOptimisticLocking());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link TransactionalAccess#lockItem(java.lang.Object, java.lang.Object)}.
|
||||
*/
|
||||
public void testLockItem() {
|
||||
assertNull(getEntityAccessStrategy().lockItem(KEY, new Integer(1)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link TransactionalAccess#lockRegion()}.
|
||||
*/
|
||||
public void testLockRegion() {
|
||||
assertNull(getEntityAccessStrategy().lockRegion());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link TransactionalAccess#unlockItem(java.lang.Object, org.hibernate.cache.access.SoftLock)}.
|
||||
*/
|
||||
public void testUnlockItem() {
|
||||
getEntityAccessStrategy().unlockItem(KEY, new MockSoftLock());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link TransactionalAccess#unlockRegion(org.hibernate.cache.access.SoftLock)}.
|
||||
*/
|
||||
public void testUnlockRegion() {
|
||||
getEntityAccessStrategy().unlockItem(KEY, new MockSoftLock());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link TransactionalAccess#afterInsert(java.lang.Object, java.lang.Object, java.lang.Object)}.
|
||||
*/
|
||||
public void testAfterInsert() {
|
||||
assertFalse("afterInsert always returns false", getEntityAccessStrategy().afterInsert(KEY, VALUE1, new Integer(1)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link TransactionalAccess#afterUpdate(java.lang.Object, java.lang.Object, java.lang.Object, java.lang.Object, org.hibernate.cache.access.SoftLock)}.
|
||||
*/
|
||||
public void testAfterUpdate() {
|
||||
assertFalse("afterInsert always returns false", getEntityAccessStrategy().afterUpdate(KEY, VALUE2, new Integer(1), new Integer(2), new MockSoftLock()));
|
||||
}
|
||||
|
||||
public static class MockSoftLock implements SoftLock {
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* 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.test.cache.jbc2.entity;
|
||||
|
||||
import junit.framework.Test;
|
||||
import junit.framework.TestSuite;
|
||||
|
||||
/**
|
||||
* Tests TRANSACTIONAL access when pessimistic locking and invalidation are used.
|
||||
*
|
||||
* @author <a href="brian.stansberry@jboss.com">Brian Stansberry</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class PessimisticInvalidatedTransactionalTestCase extends AbstractTransactionalAccessTestCase {
|
||||
|
||||
/**
|
||||
* Create a new PessimisticTransactionalAccessTestCase.
|
||||
*
|
||||
* @param name
|
||||
*/
|
||||
public PessimisticInvalidatedTransactionalTestCase(String name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
public static Test suite() throws Exception {
|
||||
TestSuite suite = createFailureExpectedSuite(PessimisticInvalidatedTransactionalTestCase.class);
|
||||
return getTestSetup(suite, "pessimistic-entity");
|
||||
}
|
||||
|
||||
// Known failures
|
||||
|
||||
public void testEvictAllFailureExpected() {
|
||||
super.testEvictAll();
|
||||
}
|
||||
|
||||
public void testRemoveAllFailureExpected() {
|
||||
super.testRemoveAll();
|
||||
}
|
||||
|
||||
// Overrides
|
||||
|
||||
@Override
|
||||
public void testCacheConfiguration() {
|
||||
assertTrue("Using Invalidation", isUsingInvalidation());
|
||||
assertFalse("Using Optimistic locking", isUsingOptimisticLocking());
|
||||
assertTrue("Synchronous mode", isSynchronous());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* 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.test.cache.jbc2.entity;
|
||||
|
||||
import org.hibernate.cache.access.EntityRegionAccessStrategy;
|
||||
|
||||
/**
|
||||
* Tests for the "extra API" in EntityRegionAccessStrategy; in this
|
||||
* version using pessimistic locking with READ_ONLY access.
|
||||
* <p>
|
||||
* By "extra API" we mean those methods that are superfluous to the
|
||||
* function of the JBC integration, where the impl is a no-op or a static
|
||||
* false return value, UnsupportedOperationException, etc.
|
||||
*
|
||||
* @author <a href="brian.stansberry@jboss.com">Brian Stansberry</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class PessimisticReadOnlyExtraAPITestCase extends OptimisticReadOnlyExtraAPITestCase {
|
||||
|
||||
private static EntityRegionAccessStrategy localAccessStrategy;
|
||||
|
||||
/**
|
||||
* Create a new PessimisticAccessStrategyExtraAPITestCase.
|
||||
*
|
||||
* @param name
|
||||
*/
|
||||
public PessimisticReadOnlyExtraAPITestCase(String name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getCacheConfigName() {
|
||||
return "pessimistic-entity";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected EntityRegionAccessStrategy getEntityAccessStrategy() {
|
||||
return localAccessStrategy;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setEntityRegionAccessStrategy(EntityRegionAccessStrategy strategy) {
|
||||
localAccessStrategy = strategy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void testCacheConfiguration() {
|
||||
assertFalse("Using Optimistic locking", isUsingOptimisticLocking());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* 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.test.cache.jbc2.entity;
|
||||
|
||||
import junit.framework.Test;
|
||||
import junit.framework.TestSuite;
|
||||
|
||||
import org.hibernate.cache.access.AccessType;
|
||||
|
||||
/**
|
||||
* Tests READ_ONLY access when pessimistic locking and invalidation are used.
|
||||
*
|
||||
* @author <a href="brian.stansberry@jboss.com">Brian Stansberry</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class PessimisticReadOnlyTestCase extends AbstractReadOnlyAccessTestCase {
|
||||
|
||||
/**
|
||||
* Create a new PessimisticTransactionalAccessTestCase.
|
||||
*
|
||||
* @param name
|
||||
*/
|
||||
public PessimisticReadOnlyTestCase(String name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
public static Test suite() throws Exception {
|
||||
TestSuite suite = createFailureExpectedSuite(PessimisticReadOnlyTestCase.class);
|
||||
return getTestSetup(suite, "pessimistic-entity");
|
||||
}
|
||||
|
||||
// Known failures
|
||||
|
||||
public void testEvictAllFailureExpected() {
|
||||
super.testEvictAll();
|
||||
}
|
||||
|
||||
public void testRemoveAllFailureExpected() {
|
||||
super.testRemoveAll();
|
||||
}
|
||||
|
||||
// Overrides
|
||||
|
||||
|
||||
@Override
|
||||
public void testCacheConfiguration() {
|
||||
assertTrue("Using Invalidation", isUsingInvalidation());
|
||||
assertFalse("Using Optimistic locking", isUsingOptimisticLocking());
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* 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.test.cache.jbc2.entity;
|
||||
|
||||
import junit.framework.Test;
|
||||
|
||||
/**
|
||||
* Tests TRANSACTIONAL access when pessimistic locking and replication are used.
|
||||
*
|
||||
* @author <a href="brian.stansberry@jboss.com">Brian Stansberry</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class PessimisticReplicatedTransactionalTestCase extends AbstractTransactionalAccessTestCase {
|
||||
|
||||
/**
|
||||
* Create a new PessimisticTransactionalAccessTestCase.
|
||||
*
|
||||
* @param name
|
||||
*/
|
||||
public PessimisticReplicatedTransactionalTestCase(String name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
public static Test suite() throws Exception {
|
||||
return getTestSetup(PessimisticReplicatedTransactionalTestCase.class, "pessimistic-shared");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void testCacheConfiguration() {
|
||||
assertFalse("Using Invalidation", isUsingInvalidation());
|
||||
assertFalse("Using Optimistic locking", isUsingOptimisticLocking());
|
||||
assertTrue("Synchronous mode", isSynchronous());
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* 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.test.cache.jbc2.entity;
|
||||
|
||||
import org.hibernate.cache.access.EntityRegionAccessStrategy;
|
||||
|
||||
/**
|
||||
* Tests for the "extra API" in EntityRegionAccessStrategy; in this base
|
||||
* version using Optimistic locking with TRANSACTIONAL access.
|
||||
* <p>
|
||||
* By "extra API" we mean those methods that are superfluous to the
|
||||
* function of the JBC integration, where the impl is a no-op or a static
|
||||
* false return value, UnsupportedOperationException, etc.
|
||||
*
|
||||
* @author <a href="brian.stansberry@jboss.com">Brian Stansberry</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class PessimisticTransactionalExtraAPITestCase extends OptimisticTransactionalExtraAPITestCase {
|
||||
|
||||
private static EntityRegionAccessStrategy localAccessStrategy;
|
||||
|
||||
/**
|
||||
* Create a new PessimisticAccessStrategyExtraAPITestCase.
|
||||
*
|
||||
* @param name
|
||||
*/
|
||||
public PessimisticTransactionalExtraAPITestCase(String name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getCacheConfigName() {
|
||||
return "pessimistic-entity";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected EntityRegionAccessStrategy getEntityAccessStrategy() {
|
||||
return localAccessStrategy;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setEntityRegionAccessStrategy(EntityRegionAccessStrategy strategy) {
|
||||
localAccessStrategy = strategy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void testCacheConfiguration() {
|
||||
assertFalse("Using Optimistic locking", isUsingOptimisticLocking());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,103 @@
|
|||
package org.hibernate.test.cache.jbc2.functional;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.Transaction;
|
||||
import org.hibernate.cache.ReadWriteCache;
|
||||
import org.hibernate.stat.SecondLevelCacheStatistics;
|
||||
import org.hibernate.stat.Statistics;
|
||||
|
||||
/**
|
||||
* Common requirement entity caching testing for each
|
||||
* {@link org.hibernate.cache.RegionFactory} impl.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public abstract class AbstractEntityCacheFunctionalTestCase extends CacheTestCaseBase {
|
||||
|
||||
// note that a lot of the functionality here is intended to be used
|
||||
// in creating specific tests for each CacheProvider that would extend
|
||||
// from a base test case (this) for common requirement testing...
|
||||
|
||||
public AbstractEntityCacheFunctionalTestCase(String x) {
|
||||
super(x);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean getUseQueryCache() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void testEmptySecondLevelCacheEntry() throws Exception {
|
||||
getSessions().evictEntity(Item.class.getName());
|
||||
Statistics stats = getSessions().getStatistics();
|
||||
stats.clear();
|
||||
SecondLevelCacheStatistics statistics = stats.getSecondLevelCacheStatistics(Item.class.getName());
|
||||
Map cacheEntries = statistics.getEntries();
|
||||
assertEquals(0, cacheEntries.size());
|
||||
}
|
||||
|
||||
public void testStaleWritesLeaveCacheConsistent() {
|
||||
Session s = openSession();
|
||||
Transaction txn = s.beginTransaction();
|
||||
VersionedItem item = new VersionedItem();
|
||||
item.setName("steve");
|
||||
item.setDescription("steve's item");
|
||||
s.save(item);
|
||||
txn.commit();
|
||||
s.close();
|
||||
|
||||
Long initialVersion = item.getVersion();
|
||||
|
||||
// manually revert the version property
|
||||
item.setVersion(new Long(item.getVersion().longValue() - 1));
|
||||
|
||||
try {
|
||||
s = openSession();
|
||||
txn = s.beginTransaction();
|
||||
s.update(item);
|
||||
txn.commit();
|
||||
s.close();
|
||||
fail("expected stale write to fail");
|
||||
} catch (Throwable expected) {
|
||||
// expected behavior here
|
||||
if (txn != null) {
|
||||
try {
|
||||
txn.rollback();
|
||||
} catch (Throwable ignore) {
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
if (s != null && s.isOpen()) {
|
||||
try {
|
||||
s.close();
|
||||
} catch (Throwable ignore) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check the version value in the cache...
|
||||
SecondLevelCacheStatistics slcs = sfi().getStatistics().getSecondLevelCacheStatistics(
|
||||
VersionedItem.class.getName());
|
||||
|
||||
Object entry = slcs.getEntries().get(item.getId());
|
||||
Long cachedVersionValue;
|
||||
if (entry instanceof ReadWriteCache.Lock) {
|
||||
// FIXME don't know what to test here
|
||||
cachedVersionValue = new Long(((ReadWriteCache.Lock) entry).getUnlockTimestamp());
|
||||
} else {
|
||||
cachedVersionValue = (Long) ((Map) entry).get("_version");
|
||||
assertEquals(initialVersion.longValue(), cachedVersionValue.longValue());
|
||||
}
|
||||
|
||||
// cleanup
|
||||
s = openSession();
|
||||
txn = s.beginTransaction();
|
||||
item = (VersionedItem) s.load(VersionedItem.class, item.getId());
|
||||
s.delete(item);
|
||||
txn.commit();
|
||||
s.close();
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,97 @@
|
|||
/*
|
||||
* 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.test.cache.jbc2.functional;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.Transaction;
|
||||
import org.hibernate.cache.ReadWriteCache;
|
||||
import org.hibernate.stat.SecondLevelCacheStatistics;
|
||||
|
||||
/**
|
||||
* A QueryCacheEnabledCacheProviderTestCase.
|
||||
*
|
||||
* @author <a href="brian.stansberry@jboss.com">Brian Stansberry</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public abstract class AbstractQueryCacheFunctionalTestCase extends AbstractEntityCacheFunctionalTestCase {
|
||||
|
||||
/**
|
||||
* Create a new QueryCacheEnabledCacheProviderTestCase.
|
||||
*
|
||||
* @param x
|
||||
*/
|
||||
public AbstractQueryCacheFunctionalTestCase(String x) {
|
||||
super(x);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean getUseQueryCache() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public void testQueryCacheInvalidation() {
|
||||
Session s = openSession();
|
||||
Transaction t = s.beginTransaction();
|
||||
Item i = new Item();
|
||||
i.setName("widget");
|
||||
i.setDescription("A really top-quality, full-featured widget.");
|
||||
s.persist(i);
|
||||
t.commit();
|
||||
s.close();
|
||||
|
||||
SecondLevelCacheStatistics slcs = s.getSessionFactory().getStatistics().getSecondLevelCacheStatistics(
|
||||
Item.class.getName());
|
||||
|
||||
assertEquals(slcs.getPutCount(), 1);
|
||||
assertEquals(slcs.getElementCountInMemory(), 1);
|
||||
assertEquals(slcs.getEntries().size(), 1);
|
||||
|
||||
s = openSession();
|
||||
t = s.beginTransaction();
|
||||
i = (Item) s.get(Item.class, i.getId());
|
||||
|
||||
assertEquals(slcs.getHitCount(), 1);
|
||||
assertEquals(slcs.getMissCount(), 0);
|
||||
|
||||
i.setDescription("A bog standard item");
|
||||
|
||||
t.commit();
|
||||
s.close();
|
||||
|
||||
assertEquals(slcs.getPutCount(), 2);
|
||||
|
||||
Object entry = slcs.getEntries().get(i.getId());
|
||||
Map map;
|
||||
if (entry instanceof ReadWriteCache.Item) {
|
||||
map = (Map) ((ReadWriteCache.Item) entry).getValue();
|
||||
} else {
|
||||
map = (Map) entry;
|
||||
}
|
||||
assertTrue(map.get("description").equals("A bog standard item"));
|
||||
assertTrue(map.get("name").equals("widget"));
|
||||
|
||||
// cleanup
|
||||
s = openSession();
|
||||
t = s.beginTransaction();
|
||||
s.delete(i);
|
||||
t.commit();
|
||||
s.close();
|
||||
}
|
||||
|
||||
}
|
81
cache-jbosscache2/src/test/java/org/hibernate/test/cache/jbc2/functional/CacheTestCaseBase.java
vendored
Executable file
81
cache-jbosscache2/src/test/java/org/hibernate/test/cache/jbc2/functional/CacheTestCaseBase.java
vendored
Executable file
|
@ -0,0 +1,81 @@
|
|||
package org.hibernate.test.cache.jbc2.functional;
|
||||
|
||||
import org.hibernate.cache.RegionFactory;
|
||||
import org.hibernate.cfg.Configuration;
|
||||
import org.hibernate.cfg.Environment;
|
||||
import org.hibernate.junit.functional.FunctionalTestCase;
|
||||
import org.hibernate.test.tm.DummyConnectionProvider;
|
||||
import org.hibernate.test.tm.DummyTransactionManagerLookup;
|
||||
|
||||
/**
|
||||
* Provides common configuration setups for cache testing.
|
||||
*
|
||||
* @author Brian Stansberry
|
||||
*/
|
||||
public abstract class CacheTestCaseBase extends FunctionalTestCase {
|
||||
|
||||
// note that a lot of the functionality here is intended to be used
|
||||
// in creating specific tests for each CacheProvider that would extend
|
||||
// from a base test case (this) for common requirement testing...
|
||||
|
||||
public CacheTestCaseBase(String x) {
|
||||
super(x);
|
||||
}
|
||||
|
||||
public String[] getMappings() {
|
||||
return new String[] { "cache/jbc2/functional/Item.hbm.xml" };
|
||||
}
|
||||
|
||||
public void configure(Configuration cfg) {
|
||||
super.configure(cfg);
|
||||
|
||||
cfg.setProperty(Environment.CACHE_REGION_PREFIX, "test");
|
||||
cfg.setProperty(Environment.USE_SECOND_LEVEL_CACHE, "true");
|
||||
cfg.setProperty(Environment.GENERATE_STATISTICS, "true");
|
||||
cfg.setProperty(Environment.USE_STRUCTURED_CACHE, "true");
|
||||
cfg.setProperty(Environment.CACHE_REGION_FACTORY, getCacheRegionFactory().getName());
|
||||
|
||||
cfg.setProperty(Environment.USE_QUERY_CACHE, String.valueOf(getUseQueryCache()));
|
||||
cfg.setProperty(Environment.CONNECTION_PROVIDER, DummyConnectionProvider.class.getName());
|
||||
cfg.setProperty(Environment.TRANSACTION_MANAGER_STRATEGY, DummyTransactionManagerLookup.class.getName());
|
||||
|
||||
configureCacheFactory(cfg);
|
||||
}
|
||||
|
||||
public String getCacheConcurrencyStrategy() {
|
||||
return "transactional";
|
||||
}
|
||||
|
||||
/**
|
||||
* The cache provider to be tested.
|
||||
*
|
||||
* @return The cache provider.
|
||||
*/
|
||||
protected void configureCacheFactory(Configuration cfg) {
|
||||
if (getConfigResourceKey() != null) {
|
||||
cfg.setProperty(getConfigResourceKey(), getConfigResourceLocation());
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract Class<? extends RegionFactory> getCacheRegionFactory();
|
||||
|
||||
protected abstract boolean getUseQueryCache();
|
||||
|
||||
/**
|
||||
* For provider-specific configuration, the name of the property key the
|
||||
* provider expects.
|
||||
*
|
||||
* @return The provider-specific config key.
|
||||
*/
|
||||
protected String getConfigResourceKey() {
|
||||
return Environment.CACHE_REGION_FACTORY;
|
||||
}
|
||||
|
||||
/**
|
||||
* For provider-specific configuration, the resource location of that config
|
||||
* resource.
|
||||
*
|
||||
* @return The config resource location.
|
||||
*/
|
||||
protected abstract String getConfigResourceLocation();
|
||||
}
|
26
cache-jbosscache2/src/test/java/org/hibernate/test/cache/jbc2/functional/Item.hbm.xml
vendored
Executable file
26
cache-jbosscache2/src/test/java/org/hibernate/test/cache/jbc2/functional/Item.hbm.xml
vendored
Executable file
|
@ -0,0 +1,26 @@
|
|||
<?xml version="1.0"?>
|
||||
<!DOCTYPE hibernate-mapping PUBLIC
|
||||
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
|
||||
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
|
||||
|
||||
<hibernate-mapping
|
||||
package="org.hibernate.test.cache.jbc2.functional">
|
||||
|
||||
<class name="Item" table="Items">
|
||||
<id name="id">
|
||||
<generator class="increment"/>
|
||||
</id>
|
||||
<property name="name" not-null="true"/>
|
||||
<property name="description" not-null="true"/>
|
||||
</class>
|
||||
|
||||
<class name="VersionedItem" table="VersionedItems">
|
||||
<id name="id">
|
||||
<generator class="increment"/>
|
||||
</id>
|
||||
<version name="version" type="long"/>
|
||||
<property name="name" not-null="true"/>
|
||||
<property name="description" not-null="true"/>
|
||||
</class>
|
||||
|
||||
</hibernate-mapping>
|
35
cache-jbosscache2/src/test/java/org/hibernate/test/cache/jbc2/functional/Item.java
vendored
Executable file
35
cache-jbosscache2/src/test/java/org/hibernate/test/cache/jbc2/functional/Item.java
vendored
Executable file
|
@ -0,0 +1,35 @@
|
|||
//$Id: Item.java 5686 2005-02-12 07:27:32Z steveebersole $
|
||||
package org.hibernate.test.cache.jbc2.functional;
|
||||
|
||||
/**
|
||||
* @author Gavin King
|
||||
*/
|
||||
public class Item {
|
||||
private Long id;
|
||||
private String name;
|
||||
private String description;
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
41
cache-jbosscache2/src/test/java/org/hibernate/test/cache/jbc2/functional/OptimisticJBossCacheTestDisabled.java
vendored
Executable file
41
cache-jbosscache2/src/test/java/org/hibernate/test/cache/jbc2/functional/OptimisticJBossCacheTestDisabled.java
vendored
Executable file
|
@ -0,0 +1,41 @@
|
|||
package org.hibernate.test.cache.jbc2.functional;
|
||||
|
||||
import junit.framework.Test;
|
||||
|
||||
import org.hibernate.cache.RegionFactory;
|
||||
import org.hibernate.cache.jbc2.JBossCacheRegionFactory;
|
||||
import org.hibernate.cache.jbc2.builder.SharedCacheInstanceManager;
|
||||
import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
|
||||
|
||||
/**
|
||||
* FIXME Move to hibernate-testsuite project and rename class x- "Disabled"
|
||||
*
|
||||
* @author Brian Stansberry
|
||||
*/
|
||||
public class OptimisticJBossCacheTestDisabled extends AbstractQueryCacheFunctionalTestCase {
|
||||
|
||||
// note that a lot of the fucntionality here is intended to be used
|
||||
// in creating specific tests for each CacheProvider that would extend
|
||||
// from a base test case (this) for common requirement testing...
|
||||
|
||||
public OptimisticJBossCacheTestDisabled(String x) {
|
||||
super(x);
|
||||
}
|
||||
|
||||
public static Test suite() {
|
||||
return new FunctionalTestClassTestSuite(OptimisticJBossCacheTestDisabled.class);
|
||||
}
|
||||
|
||||
protected Class<? extends RegionFactory> getCacheRegionFactory() {
|
||||
return JBossCacheRegionFactory.class;
|
||||
}
|
||||
|
||||
protected String getConfigResourceKey() {
|
||||
return SharedCacheInstanceManager.CACHE_RESOURCE_PROP;
|
||||
}
|
||||
|
||||
protected String getConfigResourceLocation() {
|
||||
return "org/hibernate/test/cache/jbc2/functional/optimistic-treecache.xml";
|
||||
}
|
||||
|
||||
}
|
41
cache-jbosscache2/src/test/java/org/hibernate/test/cache/jbc2/functional/PessimisticJBossCacheTestDisabled.java
vendored
Executable file
41
cache-jbosscache2/src/test/java/org/hibernate/test/cache/jbc2/functional/PessimisticJBossCacheTestDisabled.java
vendored
Executable file
|
@ -0,0 +1,41 @@
|
|||
package org.hibernate.test.cache.jbc2.functional;
|
||||
|
||||
import junit.framework.Test;
|
||||
|
||||
import org.hibernate.cache.RegionFactory;
|
||||
import org.hibernate.cache.jbc2.JBossCacheRegionFactory;
|
||||
import org.hibernate.cache.jbc2.builder.SharedCacheInstanceManager;
|
||||
import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
|
||||
|
||||
/**
|
||||
* FIXME Move to hibernate-testsuite project and rename class x- "Disabled"
|
||||
*
|
||||
* @author Brian Stansberry
|
||||
*/
|
||||
public class PessimisticJBossCacheTestDisabled extends AbstractQueryCacheFunctionalTestCase {
|
||||
|
||||
// note that a lot of the fucntionality here is intended to be used
|
||||
// in creating specific tests for each CacheProvider that would extend
|
||||
// from a base test case (this) for common requirement testing...
|
||||
|
||||
public PessimisticJBossCacheTestDisabled(String x) {
|
||||
super(x);
|
||||
}
|
||||
|
||||
public static Test suite() {
|
||||
return new FunctionalTestClassTestSuite(PessimisticJBossCacheTestDisabled.class);
|
||||
}
|
||||
|
||||
protected Class<? extends RegionFactory> getCacheRegionFactory() {
|
||||
return JBossCacheRegionFactory.class;
|
||||
}
|
||||
|
||||
protected String getConfigResourceKey() {
|
||||
return SharedCacheInstanceManager.CACHE_RESOURCE_PROP;
|
||||
}
|
||||
|
||||
protected String getConfigResourceLocation() {
|
||||
return "org/hibernate/test/cache/jbc2/functional/pessimistic-treecache.xml";
|
||||
}
|
||||
|
||||
}
|
16
cache-jbosscache2/src/test/java/org/hibernate/test/cache/jbc2/functional/VersionedItem.java
vendored
Executable file
16
cache-jbosscache2/src/test/java/org/hibernate/test/cache/jbc2/functional/VersionedItem.java
vendored
Executable file
|
@ -0,0 +1,16 @@
|
|||
package org.hibernate.test.cache.jbc2.functional;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class VersionedItem extends Item {
|
||||
private Long version;
|
||||
|
||||
public Long getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public void setVersion(Long version) {
|
||||
this.version = version;
|
||||
}
|
||||
}
|
138
cache-jbosscache2/src/test/java/org/hibernate/test/cache/jbc2/functional/optimistic-treecache.xml
vendored
Executable file
138
cache-jbosscache2/src/test/java/org/hibernate/test/cache/jbc2/functional/optimistic-treecache.xml
vendored
Executable file
|
@ -0,0 +1,138 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<!-- ===================================================================== -->
|
||||
<!-- -->
|
||||
<!-- Sample JBoss Cache Service Configuration -->
|
||||
<!-- Recommended for use as Hibernate's 2nd Level Cache -->
|
||||
<!-- For use with JBossCache >= 2.0.0 ONLY!!! -->
|
||||
<!-- -->
|
||||
<!-- ===================================================================== -->
|
||||
|
||||
<server>
|
||||
|
||||
<classpath codebase="./lib" archives="jboss-cache.jar, jgroups.jar"/>
|
||||
|
||||
|
||||
<!-- ==================================================================== -->
|
||||
<!-- Defines TreeCache configuration -->
|
||||
<!-- ==================================================================== -->
|
||||
|
||||
<mbean code="org.jboss.cache.jmx.CacheJmxWrapper"
|
||||
name="jboss.cache:service=TreeCache">
|
||||
|
||||
<depends>jboss:service=Naming</depends>
|
||||
<depends>jboss:service=TransactionManager</depends>
|
||||
|
||||
<!--
|
||||
TransactionManager configuration not required for Hibernate!
|
||||
Hibernate will plug in its own transaction manager integration.
|
||||
-->
|
||||
|
||||
|
||||
<!--
|
||||
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">REPL_SYNC</attribute>
|
||||
|
||||
<!-- Name of cluster. Needs to be the same for all clusters, in order
|
||||
to find each other
|
||||
-->
|
||||
<attribute name="ClusterName">TreeCache-Cluster</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"/>
|
||||
<MERGE2 min_interval="10000" max_interval="20000"/>
|
||||
<FD shun="true"/>
|
||||
<FD_SOCK/>
|
||||
<VERIFY_SUSPECT timeout="1500"/>
|
||||
<pbcast.NAKACK gc_lag="50" retransmit_timeout="600,1200,2400,4800"
|
||||
max_xmit_size="8192"/>
|
||||
<UNICAST timeout="600,1200,2400" window_size="100" min_threshold="10"/>
|
||||
<pbcast.STABLE desired_avg_gossip="20000"/>
|
||||
<FRAG frag_size="8192"/>
|
||||
<pbcast.GMS join_timeout="5000" join_retry_timeout="2000"
|
||||
shun="true" print_local_addr="true"/>
|
||||
<pbcast.STATE_TRANSFER/>
|
||||
</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>
|
||||
|
||||
<!--
|
||||
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>
|
||||
|
||||
<!-- Specific eviction policy configurations. This is LRU -->
|
||||
<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_">
|
||||
<attribute name="maxNodes">5000</attribute>
|
||||
<attribute name="timeToLiveSeconds">1000</attribute>
|
||||
</region>
|
||||
<!-- Don't ever evict modification timestamps -->
|
||||
<region name="/TS">
|
||||
<attribute name="maxNodes">0</attribute>
|
||||
<attribute name="timeToLiveSeconds">0</attribute>
|
||||
</region>
|
||||
</config>
|
||||
</attribute>
|
||||
|
||||
</mbean>
|
||||
</server>
|
118
cache-jbosscache2/src/test/java/org/hibernate/test/cache/jbc2/functional/pessimistic-treecache.xml
vendored
Executable file
118
cache-jbosscache2/src/test/java/org/hibernate/test/cache/jbc2/functional/pessimistic-treecache.xml
vendored
Executable file
|
@ -0,0 +1,118 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<!-- ===================================================================== -->
|
||||
<!-- -->
|
||||
<!-- Sample TreeCache Service Configuration -->
|
||||
<!-- -->
|
||||
<!-- ===================================================================== -->
|
||||
|
||||
<server>
|
||||
|
||||
<classpath codebase="./lib" archives="jboss-cache.jar, jgroups.jar"/>
|
||||
|
||||
|
||||
<!-- ==================================================================== -->
|
||||
<!-- Defines TreeCache configuration -->
|
||||
<!-- ==================================================================== -->
|
||||
|
||||
<mbean code="org.jboss.cache.jmx.CacheJmxWrapper"
|
||||
name="jboss.cache:service=TreeCache">
|
||||
|
||||
<depends>jboss:service=Naming</depends>
|
||||
<depends>jboss:service=TransactionManager</depends>
|
||||
|
||||
<!--
|
||||
TransactionManager configuration not required for Hibernate!
|
||||
Hibernate will plug in its own transaction manager integration.
|
||||
-->
|
||||
|
||||
<!--
|
||||
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>
|
||||
|
||||
<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"/>
|
||||
<MERGE2 min_interval="10000" max_interval="20000"/>
|
||||
<FD shun="true"/>
|
||||
<VERIFY_SUSPECT timeout="1500"/>
|
||||
<pbcast.NAKACK gc_lag="50" retransmit_timeout="600,1200,2400,4800"/>
|
||||
<pbcast.STABLE desired_avg_gossip="20000"/>
|
||||
<UNICAST timeout="600,1200,2400" window_size="100" min_threshold="10"/>
|
||||
<FRAG frag_size="8192"/>
|
||||
<pbcast.GMS join_timeout="5000" join_retry_timeout="2000"
|
||||
shun="true" print_local_addr="true"/>
|
||||
<pbcast.STATE_TRANSFER/>
|
||||
</config>
|
||||
</attribute>
|
||||
|
||||
<!-- Must be true if any entity deployment uses a scoped classloader -->
|
||||
<attribute name="UseRegionBasedMarshalling">true</attribute>
|
||||
<!-- Must match the value of "useRegionBasedMarshalling" -->
|
||||
<attribute name="InactiveOnStartup">true</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="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>
|
||||
|
||||
<!-- Specific eviction policy configurations. This is LRU -->
|
||||
<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_">
|
||||
<attribute name="maxNodes">5000</attribute>
|
||||
<attribute name="timeToLiveSeconds">1000</attribute>
|
||||
</region>
|
||||
<!-- Don't ever evict modification timestamps -->
|
||||
<region name="/TS">
|
||||
<attribute name="maxNodes">0</attribute>
|
||||
<attribute name="timeToLiveSeconds">0</attribute>
|
||||
</region>
|
||||
</config>
|
||||
</attribute>
|
||||
</mbean>
|
||||
|
||||
|
||||
</server>
|
320
cache-jbosscache2/src/test/java/org/hibernate/test/cache/jbc2/query/QueryRegionImplTestCase.java
vendored
Normal file
320
cache-jbosscache2/src/test/java/org/hibernate/test/cache/jbc2/query/QueryRegionImplTestCase.java
vendored
Normal file
|
@ -0,0 +1,320 @@
|
|||
/*
|
||||
* 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.test.cache.jbc2.query;
|
||||
|
||||
import java.util.Properties;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import junit.framework.AssertionFailedError;
|
||||
|
||||
import org.hibernate.cache.CacheDataDescription;
|
||||
import org.hibernate.cache.QueryResultsRegion;
|
||||
import org.hibernate.cache.Region;
|
||||
import org.hibernate.cache.jbc2.BasicRegionAdapter;
|
||||
import org.hibernate.cache.jbc2.CacheInstanceManager;
|
||||
import org.hibernate.cache.jbc2.JBossCacheRegionFactory;
|
||||
import org.hibernate.cache.jbc2.MultiplexedJBossCacheRegionFactory;
|
||||
import org.hibernate.cache.jbc2.builder.MultiplexingCacheInstanceManager;
|
||||
import org.hibernate.cfg.Configuration;
|
||||
import org.hibernate.test.cache.jbc2.AbstractRegionImplTestCase;
|
||||
import org.hibernate.test.util.CacheTestUtil;
|
||||
import org.jboss.cache.Cache;
|
||||
import org.jboss.cache.Fqn;
|
||||
import org.jboss.cache.notifications.annotation.CacheListener;
|
||||
import org.jboss.cache.notifications.annotation.NodeVisited;
|
||||
import org.jboss.cache.notifications.event.NodeVisitedEvent;
|
||||
import org.jboss.cache.transaction.BatchModeTransactionManager;
|
||||
|
||||
/**
|
||||
* Tests of QueryResultRegionImpl.
|
||||
*
|
||||
* @author <a href="brian.stansberry@jboss.com">Brian Stansberry</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class QueryRegionImplTestCase extends AbstractRegionImplTestCase {
|
||||
|
||||
private static final String KEY = "Key";
|
||||
private static final String VALUE1 = "value1";
|
||||
private static final String VALUE2 = "value2";
|
||||
|
||||
/**
|
||||
* Create a new EntityRegionImplTestCase.
|
||||
*
|
||||
* @param name
|
||||
*/
|
||||
public QueryRegionImplTestCase(String name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Region createRegion(JBossCacheRegionFactory regionFactory, String regionName, Properties properties, CacheDataDescription cdd) {
|
||||
return regionFactory.buildQueryResultsRegion(regionName, properties);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Cache getJBossCache(JBossCacheRegionFactory regionFactory) {
|
||||
CacheInstanceManager mgr = regionFactory.getCacheInstanceManager();
|
||||
return mgr.getQueryCacheInstance();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Fqn getRegionFqn(String regionName, String regionPrefix) {
|
||||
return Fqn.fromString(BasicRegionAdapter.escapeRegionName(regionName, regionPrefix));
|
||||
}
|
||||
|
||||
public void testPutDoesNotBlockGetOptimistic() throws Exception {
|
||||
putDoesNotBlockGetTest("optimistic-shared");
|
||||
}
|
||||
|
||||
public void testPutDoesNotBlockGetPessimistic() throws Exception {
|
||||
putDoesNotBlockGetTest("pessimistic-shared");
|
||||
}
|
||||
|
||||
private void putDoesNotBlockGetTest(String configName) throws Exception {
|
||||
|
||||
Configuration cfg = CacheTestUtil.buildConfiguration("test", MultiplexedJBossCacheRegionFactory.class, false, true);
|
||||
cfg.setProperty(MultiplexingCacheInstanceManager.QUERY_CACHE_RESOURCE_PROP, configName);
|
||||
// Use the local-query config for timestamps as well to save time
|
||||
cfg.setProperty(MultiplexingCacheInstanceManager.TIMESTAMP_CACHE_RESOURCE_PROP, configName);
|
||||
JBossCacheRegionFactory regionFactory = CacheTestUtil.startRegionFactory(cfg, getCacheTestSupport());
|
||||
|
||||
final QueryResultsRegion region = regionFactory.buildQueryResultsRegion("test/com.foo.test", cfg.getProperties());
|
||||
|
||||
region.put(KEY, VALUE1);
|
||||
assertEquals(VALUE1, region.get(KEY));
|
||||
|
||||
final CountDownLatch readerLatch = new CountDownLatch(1);
|
||||
final CountDownLatch writerLatch = new CountDownLatch(1);
|
||||
final CountDownLatch completionLatch = new CountDownLatch(1);
|
||||
final ExceptionHolder holder = new ExceptionHolder();
|
||||
|
||||
Thread reader = new Thread() {
|
||||
|
||||
public void run() {
|
||||
try {
|
||||
BatchModeTransactionManager.getInstance().begin();
|
||||
assertTrue(VALUE2.equals(region.get(KEY)) == false);
|
||||
BatchModeTransactionManager.getInstance().commit();
|
||||
}
|
||||
catch (AssertionFailedError e) {
|
||||
holder.a1 = e;
|
||||
rollback();
|
||||
}
|
||||
catch (Exception e) {
|
||||
holder.e1 = e;
|
||||
rollback();
|
||||
}
|
||||
finally {
|
||||
readerLatch.countDown();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Thread writer = new Thread() {
|
||||
|
||||
public void run() {
|
||||
try {
|
||||
BatchModeTransactionManager.getInstance().begin();
|
||||
region.put(KEY, VALUE2);
|
||||
writerLatch.await();
|
||||
BatchModeTransactionManager.getInstance().commit();
|
||||
}
|
||||
catch (Exception e) {
|
||||
holder.e2 = e;
|
||||
rollback();
|
||||
}
|
||||
finally {
|
||||
completionLatch.countDown();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
reader.setDaemon(true);
|
||||
writer.setDaemon(true);
|
||||
|
||||
writer.start();
|
||||
assertFalse("Writer is blocking", completionLatch.await(100, TimeUnit.MILLISECONDS));
|
||||
|
||||
// Start the reader
|
||||
reader.start();
|
||||
assertTrue("Reader finished promptly", readerLatch.await(100, TimeUnit.MILLISECONDS));
|
||||
|
||||
writerLatch.countDown();
|
||||
assertTrue("Reader finished promptly", completionLatch.await(100, TimeUnit.MILLISECONDS));
|
||||
|
||||
assertEquals(VALUE2, region.get(KEY));
|
||||
|
||||
if (holder.a1 != null)
|
||||
throw holder.a1;
|
||||
else if (holder.a2 != null)
|
||||
throw holder.a2;
|
||||
|
||||
assertEquals("writer saw no exceptions", null, holder.e1);
|
||||
assertEquals("reader saw no exceptions", null, holder.e2);
|
||||
}
|
||||
|
||||
public void testGetDoesNotBlockPutOptimistic() throws Exception {
|
||||
getDoesNotBlockPutTest("optimistic-shared");
|
||||
}
|
||||
|
||||
public void testGetDoesNotBlockPutPessimistic() throws Exception {
|
||||
getDoesNotBlockPutTest("pessimistic-shared");
|
||||
}
|
||||
|
||||
private void getDoesNotBlockPutTest(String configName) throws Exception {
|
||||
|
||||
Configuration cfg = CacheTestUtil.buildConfiguration("test", MultiplexedJBossCacheRegionFactory.class, false, true);
|
||||
cfg.setProperty(MultiplexingCacheInstanceManager.QUERY_CACHE_RESOURCE_PROP, configName);
|
||||
// Use the local-query config for timestamps as well to save time
|
||||
cfg.setProperty(MultiplexingCacheInstanceManager.TIMESTAMP_CACHE_RESOURCE_PROP, configName);
|
||||
JBossCacheRegionFactory regionFactory = CacheTestUtil.startRegionFactory(cfg, getCacheTestSupport());
|
||||
|
||||
final QueryResultsRegion region = regionFactory.buildQueryResultsRegion("test/com.foo.test", cfg.getProperties());
|
||||
|
||||
region.put(KEY, VALUE1);
|
||||
assertEquals(VALUE1, region.get(KEY));
|
||||
|
||||
final Fqn rootFqn = getRegionFqn("test/com.foo.test", "test");
|
||||
final Cache jbc = getJBossCache(regionFactory);
|
||||
|
||||
final CountDownLatch blockerLatch = new CountDownLatch(1);
|
||||
final CountDownLatch writerLatch = new CountDownLatch(1);
|
||||
final CountDownLatch completionLatch = new CountDownLatch(1);
|
||||
final ExceptionHolder holder = new ExceptionHolder();
|
||||
|
||||
Thread blocker = new Thread() {
|
||||
|
||||
public void run() {
|
||||
Fqn toBlock = new Fqn(rootFqn, KEY);
|
||||
GetBlocker blocker = new GetBlocker(blockerLatch,toBlock);
|
||||
try {
|
||||
jbc.addCacheListener(blocker);
|
||||
|
||||
BatchModeTransactionManager.getInstance().begin();
|
||||
region.get(KEY);
|
||||
BatchModeTransactionManager.getInstance().commit();
|
||||
}
|
||||
catch (Exception e) {
|
||||
holder.e1 = e;
|
||||
rollback();
|
||||
}
|
||||
finally {
|
||||
jbc.removeCacheListener(blocker);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Thread writer = new Thread() {
|
||||
|
||||
public void run() {
|
||||
try {
|
||||
writerLatch.await();
|
||||
|
||||
BatchModeTransactionManager.getInstance().begin();
|
||||
region.put(KEY, VALUE2);
|
||||
BatchModeTransactionManager.getInstance().commit();
|
||||
}
|
||||
catch (Exception e) {
|
||||
holder.e2 = e;
|
||||
rollback();
|
||||
}
|
||||
finally {
|
||||
completionLatch.countDown();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
blocker.setDaemon(true);
|
||||
writer.setDaemon(true);
|
||||
|
||||
boolean unblocked = false;
|
||||
try {
|
||||
blocker.start();
|
||||
writer.start();
|
||||
|
||||
assertFalse("Blocker is blocking", completionLatch.await(100, TimeUnit.MILLISECONDS));
|
||||
// Start the writer
|
||||
writerLatch.countDown();
|
||||
assertTrue("Writer finished promptly", completionLatch.await(100, TimeUnit.MILLISECONDS));
|
||||
|
||||
blockerLatch.countDown();
|
||||
unblocked = true;
|
||||
|
||||
if ("PESSIMISTIC".equals(jbc.getConfiguration().getNodeLockingSchemeString())) {
|
||||
assertEquals(VALUE1, region.get(KEY));
|
||||
}
|
||||
else {
|
||||
assertEquals(VALUE2, region.get(KEY));
|
||||
}
|
||||
|
||||
if (holder.a1 != null)
|
||||
throw holder.a1;
|
||||
else if (holder.a2 != null)
|
||||
throw holder.a2;
|
||||
|
||||
assertEquals("blocker saw no exceptions", null, holder.e1);
|
||||
assertEquals("writer saw no exceptions", null, holder.e2);
|
||||
}
|
||||
finally {
|
||||
if (!unblocked)
|
||||
blockerLatch.countDown();
|
||||
}
|
||||
}
|
||||
|
||||
private void rollback() {
|
||||
try {
|
||||
BatchModeTransactionManager.getInstance().rollback();
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@CacheListener
|
||||
public class GetBlocker {
|
||||
|
||||
private CountDownLatch latch;
|
||||
private Fqn fqn;
|
||||
|
||||
GetBlocker(CountDownLatch latch, Fqn fqn) {
|
||||
this.latch = latch;
|
||||
this.fqn = fqn;
|
||||
}
|
||||
|
||||
@NodeVisited
|
||||
public void nodeVisisted(NodeVisitedEvent event) {
|
||||
|
||||
if (event.isPre() && event.getFqn().equals(fqn)) {
|
||||
try {
|
||||
latch.await();
|
||||
}
|
||||
catch (InterruptedException e) {
|
||||
log.error("Interrupted waiting for latch", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class ExceptionHolder {
|
||||
Exception e1;
|
||||
Exception e2;
|
||||
AssertionFailedError a1;
|
||||
AssertionFailedError a2;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* 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.test.cache.jbc2.timestamp;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import org.hibernate.cache.CacheDataDescription;
|
||||
import org.hibernate.cache.Region;
|
||||
import org.hibernate.cache.jbc2.BasicRegionAdapter;
|
||||
import org.hibernate.cache.jbc2.CacheInstanceManager;
|
||||
import org.hibernate.cache.jbc2.JBossCacheRegionFactory;
|
||||
import org.hibernate.cache.jbc2.timestamp.TimestampsRegionImpl;
|
||||
import org.hibernate.test.cache.jbc2.AbstractRegionImplTestCase;
|
||||
import org.jboss.cache.Cache;
|
||||
import org.jboss.cache.Fqn;
|
||||
|
||||
/**
|
||||
* Tests of TimestampsRegionImpl.
|
||||
*
|
||||
* @author <a href="brian.stansberry@jboss.com">Brian Stansberry</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class TimestampsRegionImplTestCase extends AbstractRegionImplTestCase {
|
||||
|
||||
/**
|
||||
* Create a new EntityRegionImplTestCase.
|
||||
*
|
||||
* @param name
|
||||
*/
|
||||
public TimestampsRegionImplTestCase(String name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Region createRegion(JBossCacheRegionFactory regionFactory, String regionName, Properties properties, CacheDataDescription cdd) {
|
||||
return regionFactory.buildTimestampsRegion(regionName, properties);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Cache getJBossCache(JBossCacheRegionFactory regionFactory) {
|
||||
CacheInstanceManager mgr = regionFactory.getCacheInstanceManager();
|
||||
return mgr.getTimestampsCacheInstance();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Fqn getRegionFqn(String regionName, String regionPrefix) {
|
||||
return BasicRegionAdapter.getTypeFirstRegionFqn(regionName, regionPrefix, TimestampsRegionImpl.TYPE);
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
//$Id: DummyConnectionProvider.java 6501 2005-04-24 00:18:28Z oneovthafew $
|
||||
package org.hibernate.test.tm;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.connection.ConnectionProvider;
|
||||
import org.hibernate.connection.ConnectionProviderFactory;
|
||||
|
||||
/**
|
||||
* FIXME Get this class into hibernate-testing so we don't have to maintain
|
||||
* a copy here. Can't use the hibernate-testsuite version as that would
|
||||
* lead to circular project dependencies.
|
||||
*
|
||||
* @author Gavin King
|
||||
*/
|
||||
public class DummyConnectionProvider implements ConnectionProvider {
|
||||
|
||||
ConnectionProvider cp;
|
||||
boolean isTransaction;
|
||||
|
||||
public void configure(Properties props) throws HibernateException {
|
||||
cp = ConnectionProviderFactory.newConnectionProvider();
|
||||
}
|
||||
|
||||
public Connection getConnection() throws SQLException {
|
||||
DummyTransactionManager dtm = DummyTransactionManager.INSTANCE;
|
||||
if (dtm != null && dtm.getCurrent() != null && dtm.getCurrent().getConnection() != null) {
|
||||
isTransaction = true;
|
||||
return dtm.getCurrent().getConnection();
|
||||
} else {
|
||||
isTransaction = false;
|
||||
return cp.getConnection();
|
||||
}
|
||||
}
|
||||
|
||||
public void closeConnection(Connection conn) throws SQLException {
|
||||
if (!isTransaction)
|
||||
conn.close();
|
||||
}
|
||||
|
||||
public void close() throws HibernateException {
|
||||
|
||||
}
|
||||
|
||||
public boolean supportsAggressiveRelease() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,143 @@
|
|||
//$Id: DummyTransaction.java 8411 2005-10-14 23:29:04Z maxcsaucdk $
|
||||
package org.hibernate.test.tm;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.transaction.HeuristicMixedException;
|
||||
import javax.transaction.HeuristicRollbackException;
|
||||
import javax.transaction.RollbackException;
|
||||
import javax.transaction.Status;
|
||||
import javax.transaction.Synchronization;
|
||||
import javax.transaction.SystemException;
|
||||
import javax.transaction.Transaction;
|
||||
import javax.transaction.xa.XAResource;
|
||||
|
||||
/**
|
||||
* FIXME Get this class into hibernate-testing so we don't have to maintain
|
||||
* a copy here. Can't use the hibernate-testsuite version as that would
|
||||
* lead to circular project dependencies.
|
||||
*
|
||||
* @author Gavin King
|
||||
*/
|
||||
public class DummyTransaction implements Transaction {
|
||||
|
||||
int status;
|
||||
private Connection connection;
|
||||
List synchronizations = new ArrayList();
|
||||
private DummyTransactionManager transactionManager;
|
||||
|
||||
DummyTransaction(DummyTransactionManager transactionManager) {
|
||||
status = Status.STATUS_NO_TRANSACTION;
|
||||
this.transactionManager = transactionManager;
|
||||
}
|
||||
|
||||
public void begin() throws SystemException {
|
||||
try {
|
||||
connection = transactionManager.connections.getConnection();
|
||||
} catch (SQLException sqle) {
|
||||
|
||||
sqle.printStackTrace();
|
||||
throw new SystemException(sqle.toString());
|
||||
}
|
||||
status = Status.STATUS_ACTIVE;
|
||||
}
|
||||
|
||||
public void commit() throws RollbackException, HeuristicMixedException, HeuristicRollbackException,
|
||||
SecurityException, IllegalStateException, SystemException {
|
||||
|
||||
if (status == Status.STATUS_MARKED_ROLLBACK) {
|
||||
rollback();
|
||||
} else {
|
||||
status = Status.STATUS_PREPARING;
|
||||
|
||||
for (int i = 0; i < synchronizations.size(); i++) {
|
||||
Synchronization s = (Synchronization) synchronizations.get(i);
|
||||
s.beforeCompletion();
|
||||
}
|
||||
|
||||
status = Status.STATUS_COMMITTING;
|
||||
|
||||
try {
|
||||
connection.commit();
|
||||
connection.close();
|
||||
} catch (SQLException sqle) {
|
||||
status = Status.STATUS_UNKNOWN;
|
||||
throw new SystemException();
|
||||
}
|
||||
|
||||
status = Status.STATUS_COMMITTED;
|
||||
|
||||
for (int i = 0; i < synchronizations.size(); i++) {
|
||||
Synchronization s = (Synchronization) synchronizations.get(i);
|
||||
s.afterCompletion(status);
|
||||
}
|
||||
|
||||
// status = Status.STATUS_NO_TRANSACTION;
|
||||
transactionManager.endCurrent(this);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public boolean delistResource(XAResource arg0, int arg1) throws IllegalStateException, SystemException {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean enlistResource(XAResource arg0) throws RollbackException, IllegalStateException, SystemException {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
public int getStatus() throws SystemException {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void registerSynchronization(Synchronization sync) throws RollbackException, IllegalStateException,
|
||||
SystemException {
|
||||
synchronizations.add(sync);
|
||||
}
|
||||
|
||||
public void rollback() throws IllegalStateException, SystemException {
|
||||
|
||||
status = Status.STATUS_ROLLING_BACK;
|
||||
|
||||
// Synch.beforeCompletion() should *not* be called for rollbacks
|
||||
// for ( int i=0; i<synchronizations.size(); i++ ) {
|
||||
// Synchronization s = (Synchronization) synchronizations.get(i);
|
||||
// s.beforeCompletion();
|
||||
// }
|
||||
|
||||
status = Status.STATUS_ROLLEDBACK;
|
||||
|
||||
try {
|
||||
connection.rollback();
|
||||
connection.close();
|
||||
} catch (SQLException sqle) {
|
||||
status = Status.STATUS_UNKNOWN;
|
||||
throw new SystemException();
|
||||
}
|
||||
|
||||
for (int i = 0; i < synchronizations.size(); i++) {
|
||||
Synchronization s = (Synchronization) synchronizations.get(i);
|
||||
s.afterCompletion(status);
|
||||
}
|
||||
|
||||
// status = Status.STATUS_NO_TRANSACTION;
|
||||
transactionManager.endCurrent(this);
|
||||
}
|
||||
|
||||
public void setRollbackOnly() throws IllegalStateException, SystemException {
|
||||
status = Status.STATUS_MARKED_ROLLBACK;
|
||||
}
|
||||
|
||||
void setConnection(Connection connection) {
|
||||
this.connection = connection;
|
||||
}
|
||||
|
||||
public Connection getConnection() {
|
||||
return connection;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
//$Id: DummyTransactionManager.java 7003 2005-06-03 16:09:59Z steveebersole $
|
||||
package org.hibernate.test.tm;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import javax.transaction.HeuristicMixedException;
|
||||
import javax.transaction.HeuristicRollbackException;
|
||||
import javax.transaction.InvalidTransactionException;
|
||||
import javax.transaction.NotSupportedException;
|
||||
import javax.transaction.RollbackException;
|
||||
import javax.transaction.SystemException;
|
||||
import javax.transaction.Transaction;
|
||||
import javax.transaction.TransactionManager;
|
||||
|
||||
import org.hibernate.connection.ConnectionProvider;
|
||||
import org.hibernate.connection.ConnectionProviderFactory;
|
||||
|
||||
/**
|
||||
* FIXME Get this class into hibernate-testing so we don't have to maintain
|
||||
* a copy here. Can't use the hibernate-testsuite version as that would
|
||||
* lead to circular project dependencies.
|
||||
*
|
||||
* @author Gavin King
|
||||
*/
|
||||
public class DummyTransactionManager implements TransactionManager {
|
||||
|
||||
public static DummyTransactionManager INSTANCE;
|
||||
|
||||
private DummyTransaction current;
|
||||
ConnectionProvider connections;
|
||||
|
||||
public DummyTransactionManager(Properties props) {
|
||||
connections = ConnectionProviderFactory.newConnectionProvider();
|
||||
}
|
||||
|
||||
public void begin() throws NotSupportedException, SystemException {
|
||||
current = new DummyTransaction(this);
|
||||
current.begin();
|
||||
}
|
||||
|
||||
public void commit() throws RollbackException, HeuristicMixedException, HeuristicRollbackException,
|
||||
SecurityException, IllegalStateException, SystemException {
|
||||
current.commit();
|
||||
}
|
||||
|
||||
public int getStatus() throws SystemException {
|
||||
return current.getStatus();
|
||||
}
|
||||
|
||||
public Transaction getTransaction() throws SystemException {
|
||||
return current;
|
||||
}
|
||||
|
||||
public void resume(Transaction tx) throws InvalidTransactionException, IllegalStateException, SystemException {
|
||||
current = (DummyTransaction) tx;
|
||||
}
|
||||
|
||||
public void rollback() throws IllegalStateException, SecurityException, SystemException {
|
||||
current.rollback();
|
||||
|
||||
}
|
||||
|
||||
public void setRollbackOnly() throws IllegalStateException, SystemException {
|
||||
current.setRollbackOnly();
|
||||
}
|
||||
|
||||
public void setTransactionTimeout(int t) throws SystemException {
|
||||
}
|
||||
|
||||
public Transaction suspend() throws SystemException {
|
||||
Transaction result = current;
|
||||
current = null;
|
||||
return result;
|
||||
}
|
||||
|
||||
public DummyTransaction getCurrent() {
|
||||
return current;
|
||||
}
|
||||
|
||||
void endCurrent(DummyTransaction tx) {
|
||||
if (current == tx)
|
||||
current = null;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
//$Id: DummyTransactionManagerLookup.java 5693 2005-02-13 01:59:07Z oneovthafew $
|
||||
package org.hibernate.test.tm;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import javax.transaction.TransactionManager;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.transaction.TransactionManagerLookup;
|
||||
|
||||
/**
|
||||
* FIXME Get this class into hibernate-testing so we don't have to maintain
|
||||
* a copy here. Can't use the hibernate-testsuite version as that would
|
||||
* lead to circular project dependencies.
|
||||
*
|
||||
* @author Gavin King
|
||||
*/
|
||||
public class DummyTransactionManagerLookup implements TransactionManagerLookup {
|
||||
|
||||
public TransactionManager getTransactionManager(Properties props) throws HibernateException {
|
||||
if (DummyTransactionManager.INSTANCE == null) {
|
||||
DummyTransactionManager.INSTANCE = new DummyTransactionManager(props);
|
||||
}
|
||||
return DummyTransactionManager.INSTANCE;
|
||||
}
|
||||
|
||||
public String getUserTransactionName() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
//$Id: DummyTransactionManagerLookup.java 5693 2005-02-13 01:59:07Z oneovthafew $
|
||||
package org.hibernate.test.tm.jbc2;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import javax.transaction.TransactionManager;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.transaction.TransactionManagerLookup;
|
||||
import org.jboss.cache.transaction.BatchModeTransactionManager;
|
||||
|
||||
/**
|
||||
* Uses the JBoss Cache BatchModeTransactionManager. Should not be used in
|
||||
* any tests that simulate usage of database connections.
|
||||
*
|
||||
* @author Brian Stansberry
|
||||
*/
|
||||
public class BatchModeTransactionManagerLookup
|
||||
implements TransactionManagerLookup {
|
||||
|
||||
public TransactionManager getTransactionManager(Properties props) throws HibernateException {
|
||||
try {
|
||||
return BatchModeTransactionManager.getInstance();
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new HibernateException("Failed getting BatchModeTransactionManager", e);
|
||||
}
|
||||
}
|
||||
|
||||
public String getUserTransactionName() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,108 @@
|
|||
/*
|
||||
* 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.test.util;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
|
||||
import org.hibernate.cache.RegionFactory;
|
||||
import org.jboss.cache.Cache;
|
||||
|
||||
/**
|
||||
* Support class for tracking and cleaning up objects used in tests.
|
||||
*
|
||||
* @author <a href="brian.stansberry@jboss.com">Brian Stansberry</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class CacheTestSupport {
|
||||
|
||||
private Set<Cache> caches = new HashSet();
|
||||
private Set<RegionFactory> factories = new HashSet();
|
||||
private Exception exception;
|
||||
|
||||
public void registerCache(Cache cache) {
|
||||
caches.add(cache);
|
||||
}
|
||||
|
||||
public void registerFactory(RegionFactory factory) {
|
||||
factories.add(factory);
|
||||
}
|
||||
|
||||
public void unregisterCache(Cache cache) {
|
||||
caches.remove(cache);
|
||||
}
|
||||
|
||||
public void unregisterFactory(RegionFactory factory) {
|
||||
factories.remove(factory);
|
||||
}
|
||||
|
||||
public void setUp() throws Exception {
|
||||
cleanUp();
|
||||
throwStoredException();
|
||||
}
|
||||
|
||||
public void tearDown() throws Exception {
|
||||
cleanUp();
|
||||
throwStoredException();
|
||||
}
|
||||
|
||||
private void cleanUp() {
|
||||
for (Iterator it = factories.iterator(); it.hasNext(); ) {
|
||||
try {
|
||||
((RegionFactory) it.next()).stop();
|
||||
}
|
||||
catch (Exception e) {
|
||||
storeException(e);
|
||||
}
|
||||
finally {
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
factories.clear();
|
||||
|
||||
for (Iterator it = caches.iterator(); it.hasNext(); ) {
|
||||
try {
|
||||
Cache cache = (Cache) it.next();
|
||||
cache.stop();
|
||||
cache.destroy();
|
||||
}
|
||||
catch (Exception e) {
|
||||
storeException(e);
|
||||
}
|
||||
finally {
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
caches.clear();
|
||||
}
|
||||
|
||||
private void storeException(Exception e) {
|
||||
if (this.exception == null) {
|
||||
this.exception = e;
|
||||
}
|
||||
}
|
||||
|
||||
private void throwStoredException() throws Exception {
|
||||
if (exception != null) {
|
||||
Exception toThrow = exception;
|
||||
exception = null;
|
||||
throw toThrow;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,109 @@
|
|||
/*
|
||||
* 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.test.util;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import org.hibernate.cache.jbc2.JBossCacheRegionFactory;
|
||||
import org.hibernate.cache.jbc2.SharedJBossCacheRegionFactory;
|
||||
import org.hibernate.cache.jbc2.builder.SharedCacheInstanceManager;
|
||||
import org.hibernate.cfg.Configuration;
|
||||
import org.hibernate.cfg.Environment;
|
||||
import org.hibernate.cfg.Settings;
|
||||
import org.hibernate.test.tm.jbc2.BatchModeTransactionManagerLookup;
|
||||
|
||||
/**
|
||||
* Utilities for cache testing.
|
||||
*
|
||||
* @author <a href="brian.stansberry@jboss.com">Brian Stansberry</a>
|
||||
* @version $Revision: 1 $
|
||||
*/
|
||||
public class CacheTestUtil {
|
||||
|
||||
public static String LOCAL_OPTIMISIC_CACHE;
|
||||
public static String LOCAL_PESSIMISTIC_CACHE;
|
||||
|
||||
static {
|
||||
String pkg = CacheTestUtil.class.getPackage().getName().replace('.', '/');
|
||||
LOCAL_OPTIMISIC_CACHE = pkg + "/optimistic-local-cache.xml";
|
||||
LOCAL_PESSIMISTIC_CACHE = pkg + "/pessimistic-local-cache.xml";
|
||||
}
|
||||
|
||||
public static Configuration buildConfiguration(String regionPrefix, Class regionFactory, boolean use2ndLevel, boolean useQueries) {
|
||||
|
||||
Configuration cfg = new Configuration();
|
||||
cfg.setProperty(Environment.GENERATE_STATISTICS, "true");
|
||||
cfg.setProperty(Environment.USE_STRUCTURED_CACHE, "true");
|
||||
// cfg.setProperty(Environment.CONNECTION_PROVIDER, DummyConnectionProvider.class.getName());
|
||||
cfg.setProperty(Environment.TRANSACTION_MANAGER_STRATEGY, BatchModeTransactionManagerLookup.class.getName());
|
||||
|
||||
cfg.setProperty(Environment.CACHE_REGION_FACTORY, regionFactory.getName());
|
||||
cfg.setProperty(Environment.CACHE_REGION_PREFIX, regionPrefix);
|
||||
cfg.setProperty(Environment.USE_SECOND_LEVEL_CACHE, String.valueOf(use2ndLevel));
|
||||
cfg.setProperty(Environment.USE_QUERY_CACHE, String.valueOf(useQueries));
|
||||
|
||||
return cfg;
|
||||
}
|
||||
|
||||
public static Configuration buildLocalOnlyConfiguration(String regionPrefix, boolean optimistic, boolean use2ndLevel, boolean useQueries) {
|
||||
Configuration cfg = buildConfiguration(regionPrefix, SharedJBossCacheRegionFactory.class, use2ndLevel, useQueries);
|
||||
|
||||
String resource = CacheTestUtil.class.getPackage().getName().replace('.', '/') + "/";
|
||||
resource += optimistic ? "optimistic" : "pessimistic";
|
||||
resource += "-local-cache.xml";
|
||||
|
||||
cfg.setProperty(SharedCacheInstanceManager.CACHE_RESOURCE_PROP, resource);
|
||||
|
||||
return cfg;
|
||||
}
|
||||
|
||||
public static JBossCacheRegionFactory startRegionFactory(Configuration cfg)
|
||||
throws ClassNotFoundException, InstantiationException, IllegalAccessException {
|
||||
|
||||
Settings settings = cfg.buildSettings();
|
||||
Properties properties = cfg.getProperties();
|
||||
|
||||
String factoryType = cfg.getProperty(Environment.CACHE_REGION_FACTORY);
|
||||
Class factoryClass = Thread.currentThread().getContextClassLoader().loadClass(factoryType);
|
||||
JBossCacheRegionFactory regionFactory = (JBossCacheRegionFactory) factoryClass.newInstance();
|
||||
|
||||
regionFactory.start(settings, properties);
|
||||
|
||||
return regionFactory;
|
||||
}
|
||||
|
||||
public static JBossCacheRegionFactory startRegionFactory(Configuration cfg, CacheTestSupport testSupport)
|
||||
throws ClassNotFoundException, InstantiationException, IllegalAccessException {
|
||||
|
||||
JBossCacheRegionFactory factory = startRegionFactory(cfg);
|
||||
testSupport.registerFactory(factory);
|
||||
return factory;
|
||||
}
|
||||
|
||||
public static void stopRegionFactory(JBossCacheRegionFactory factory, CacheTestSupport testSupport) {
|
||||
|
||||
factory.stop();
|
||||
testSupport.unregisterFactory(factory);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prevent instantiation.
|
||||
*/
|
||||
private CacheTestUtil() {
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,138 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<!-- ===================================================================== -->
|
||||
<!-- -->
|
||||
<!-- Sample JBoss Cache Service Configuration -->
|
||||
<!-- Recommended for use as Hibernate's 2nd Level Cache -->
|
||||
<!-- For use with JBossCache >= 2.0.0 ONLY!!! -->
|
||||
<!-- -->
|
||||
<!-- ===================================================================== -->
|
||||
|
||||
<server>
|
||||
|
||||
<classpath codebase="./lib" archives="jboss-cache.jar, jgroups.jar"/>
|
||||
|
||||
|
||||
<!-- ==================================================================== -->
|
||||
<!-- Defines TreeCache configuration -->
|
||||
<!-- ==================================================================== -->
|
||||
|
||||
<mbean code="org.jboss.cache.jmx.CacheJmxWrapper"
|
||||
name="jboss.cache:service=TreeCache">
|
||||
|
||||
<depends>jboss:service=Naming</depends>
|
||||
<depends>jboss:service=TransactionManager</depends>
|
||||
|
||||
<!--
|
||||
TransactionManager configuration not required for Hibernate!
|
||||
Hibernate will plug in its own transaction manager integration.
|
||||
-->
|
||||
|
||||
|
||||
<!--
|
||||
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">REPL_SYNC</attribute>
|
||||
|
||||
<!-- Name of cluster. Needs to be the same for all clusters, in order
|
||||
to find each other
|
||||
-->
|
||||
<attribute name="ClusterName">TreeCache-Cluster</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"/>
|
||||
<MERGE2 min_interval="10000" max_interval="20000"/>
|
||||
<FD shun="true"/>
|
||||
<FD_SOCK/>
|
||||
<VERIFY_SUSPECT timeout="1500"/>
|
||||
<pbcast.NAKACK gc_lag="50" retransmit_timeout="600,1200,2400,4800"
|
||||
max_xmit_size="8192"/>
|
||||
<UNICAST timeout="600,1200,2400" window_size="100" min_threshold="10"/>
|
||||
<pbcast.STABLE desired_avg_gossip="20000"/>
|
||||
<FRAG frag_size="8192"/>
|
||||
<pbcast.GMS join_timeout="5000" join_retry_timeout="2000"
|
||||
shun="true" print_local_addr="true"/>
|
||||
<pbcast.STATE_TRANSFER/>
|
||||
</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>
|
||||
|
||||
<!--
|
||||
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>
|
||||
|
||||
<!-- Specific eviction policy configurations. This is LRU -->
|
||||
<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_">
|
||||
<attribute name="maxNodes">5000</attribute>
|
||||
<attribute name="timeToLiveSeconds">1000</attribute>
|
||||
</region>
|
||||
<!-- Don't ever evict modification timestamps -->
|
||||
<region name="/TS">
|
||||
<attribute name="maxNodes">0</attribute>
|
||||
<attribute name="timeToLiveSeconds">0</attribute>
|
||||
</region>
|
||||
</config>
|
||||
</attribute>
|
||||
|
||||
</mbean>
|
||||
</server>
|
|
@ -0,0 +1,118 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<!-- ===================================================================== -->
|
||||
<!-- -->
|
||||
<!-- Sample TreeCache Service Configuration -->
|
||||
<!-- -->
|
||||
<!-- ===================================================================== -->
|
||||
|
||||
<server>
|
||||
|
||||
<classpath codebase="./lib" archives="jboss-cache.jar, jgroups.jar"/>
|
||||
|
||||
|
||||
<!-- ==================================================================== -->
|
||||
<!-- Defines TreeCache configuration -->
|
||||
<!-- ==================================================================== -->
|
||||
|
||||
<mbean code="org.jboss.cache.jmx.CacheJmxWrapper"
|
||||
name="jboss.cache:service=TreeCache">
|
||||
|
||||
<depends>jboss:service=Naming</depends>
|
||||
<depends>jboss:service=TransactionManager</depends>
|
||||
|
||||
<!--
|
||||
TransactionManager configuration not required for Hibernate!
|
||||
Hibernate will plug in its own transaction manager integration.
|
||||
-->
|
||||
|
||||
<!--
|
||||
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>
|
||||
|
||||
<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"/>
|
||||
<MERGE2 min_interval="10000" max_interval="20000"/>
|
||||
<FD shun="true"/>
|
||||
<VERIFY_SUSPECT timeout="1500"/>
|
||||
<pbcast.NAKACK gc_lag="50" retransmit_timeout="600,1200,2400,4800"/>
|
||||
<pbcast.STABLE desired_avg_gossip="20000"/>
|
||||
<UNICAST timeout="600,1200,2400" window_size="100" min_threshold="10"/>
|
||||
<FRAG frag_size="8192"/>
|
||||
<pbcast.GMS join_timeout="5000" join_retry_timeout="2000"
|
||||
shun="true" print_local_addr="true"/>
|
||||
<pbcast.STATE_TRANSFER/>
|
||||
</config>
|
||||
</attribute>
|
||||
|
||||
<!-- Must be true if any entity deployment uses a scoped classloader -->
|
||||
<attribute name="UseRegionBasedMarshalling">true</attribute>
|
||||
<!-- Must match the value of "useRegionBasedMarshalling" -->
|
||||
<attribute name="InactiveOnStartup">true</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="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>
|
||||
|
||||
<!-- Specific eviction policy configurations. This is LRU -->
|
||||
<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_">
|
||||
<attribute name="maxNodes">5000</attribute>
|
||||
<attribute name="timeToLiveSeconds">1000</attribute>
|
||||
</region>
|
||||
<!-- Don't ever evict modification timestamps -->
|
||||
<region name="/TS">
|
||||
<attribute name="maxNodes">0</attribute>
|
||||
<attribute name="timeToLiveSeconds">0</attribute>
|
||||
</region>
|
||||
</config>
|
||||
</attribute>
|
||||
</mbean>
|
||||
|
||||
|
||||
</server>
|
|
@ -0,0 +1,8 @@
|
|||
<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
|
||||
<hibernate-configuration>
|
||||
<session-factory name="foo">
|
||||
<property name="show_sql">true</property>
|
||||
<mapping resource="org/hibernate/test/legacy/Simple.hbm.xml"/>
|
||||
<class-cache class="org.hibernate.test.legacy.Simple" region="Simple" usage="read-write"/>
|
||||
</session-factory>
|
||||
</hibernate-configuration>
|
|
@ -0,0 +1,30 @@
|
|||
################################################################################
|
||||
# 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): Steve Ebersole #
|
||||
################################################################################
|
||||
hibernate.dialect org.hibernate.dialect.HSQLDialect
|
||||
hibernate.connection.driver_class org.hsqldb.jdbcDriver
|
||||
hibernate.connection.url jdbc:hsqldb:target/test/db/hsqldb/hibernate
|
||||
hibernate.connection.username sa
|
||||
hibernate.connection.password
|
||||
hibernate.connection.isolation
|
||||
|
||||
hibernate.connection.pool_size 5
|
||||
|
||||
hibernate.format_sql true
|
||||
|
||||
hibernate.max_fetch_depth 5
|
||||
|
||||
hibernate.cache.region_prefix hibernate.test
|
||||
hibernate.cache.provider_class org.hibernate.cache.HashtableCacheProvider
|
|
@ -0,0 +1,9 @@
|
|||
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
|
|
@ -0,0 +1,113 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<!-- ===================================================================== -->
|
||||
<!-- -->
|
||||
<!-- Sample TreeCache Service Configuration -->
|
||||
<!-- -->
|
||||
<!-- ===================================================================== -->
|
||||
|
||||
<server>
|
||||
|
||||
<classpath codebase="./lib" archives="jboss-cache.jar, jgroups.jar"/>
|
||||
|
||||
|
||||
<!-- ==================================================================== -->
|
||||
<!-- Defines TreeCache configuration -->
|
||||
<!-- ==================================================================== -->
|
||||
|
||||
<mbean code="org.jboss.cache.jmx.CacheJmxWrapper"
|
||||
name="jboss.cache:service=TreeCache">
|
||||
|
||||
<depends>jboss:service=Naming</depends>
|
||||
<depends>jboss:service=TransactionManager</depends>
|
||||
|
||||
<!-- TransactionManager configuration not required for Hibernate!
|
||||
Hibernate will plug in its own transaction manager integration.
|
||||
-->
|
||||
|
||||
<!-- Node locking scheme:
|
||||
OPTIMISTIC
|
||||
PESSIMISTIC (default)
|
||||
-->
|
||||
<attribute name="NodeLockingScheme">PESSIMISTIC</attribute>
|
||||
|
||||
<!--
|
||||
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_SYNC is highly recommended as the mode for use
|
||||
with entity and collection caches.
|
||||
-->
|
||||
<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">TestSharedCache</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>
|
||||
|
||||
<!--
|
||||
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>
|
||||
|
||||
<!-- Specific eviction policy configurations. This is LRU -->
|
||||
<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_">
|
||||
<attribute name="maxNodes">5000</attribute>
|
||||
<attribute name="timeToLiveSeconds">1000</attribute>
|
||||
</region>
|
||||
<!-- Don't ever evict modification timestamps -->
|
||||
<region name="/TS">
|
||||
<attribute name="maxNodes">0</attribute>
|
||||
<attribute name="timeToLiveSeconds">0</attribute>
|
||||
</region>
|
||||
</config>
|
||||
</attribute>
|
||||
|
||||
</mbean>
|
||||
|
||||
|
||||
</server>
|
Loading…
Reference in New Issue