[HHH-4103] Initial commit.
git-svn-id: https://svn.jboss.org/repos/hibernate/core/trunk@17386 1b8cb986-b30d-0410-93ca-fae66ebed9b2
This commit is contained in:
parent
ce8df153eb
commit
9ccd912bde
|
@ -0,0 +1,160 @@
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<groupId>org.hibernate</groupId>
|
||||||
|
<artifactId>hibernate-parent</artifactId>
|
||||||
|
<version>3.5.0-SNAPSHOT</version>
|
||||||
|
<relativePath>../parent/pom.xml</relativePath>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<groupId>org.hibernate</groupId>
|
||||||
|
<artifactId>hibernate-infinispan</artifactId>
|
||||||
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
|
<name>Hibernate Infinispan Integration</name>
|
||||||
|
<description>Integration of Hibernate with Infinispan</description>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<version.infinispan>4.0.0-SNAPSHOT</version.infinispan>
|
||||||
|
<version.hsqldb>1.8.0.2</version.hsqldb>
|
||||||
|
<version.cglib>2.2</version.cglib>
|
||||||
|
<version.javassist>3.4.GA</version.javassist>
|
||||||
|
<skipUnitTests>true</skipUnitTests>
|
||||||
|
<!--
|
||||||
|
Following is the default jgroups mcast address. If you find the testsuite runs very slowly, there
|
||||||
|
may be problems with multicast on the interface JGroups uses by default on your machine. You can
|
||||||
|
try to resolve setting 'jgroups.bind_addr' as a system-property to the jvm launching maven and
|
||||||
|
setting the value to an interface where you know multicast works
|
||||||
|
-->
|
||||||
|
<jgroups.bind_addr>127.0.0.1</jgroups.bind_addr>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>${groupId}</groupId>
|
||||||
|
<artifactId>hibernate-core</artifactId>
|
||||||
|
<version>${version}</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.infinispan</groupId>
|
||||||
|
<artifactId>infinispan-core</artifactId>
|
||||||
|
<version>${version.infinispan}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- test dependencies -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>${groupId}</groupId>
|
||||||
|
<artifactId>hibernate-testing</artifactId>
|
||||||
|
<version>${version}</version>
|
||||||
|
<!-- <scope>test</scope> TODO fix this -->
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.infinispan</groupId>
|
||||||
|
<artifactId>infinispan-core</artifactId>
|
||||||
|
<version>${version.infinispan}</version>
|
||||||
|
<type>test-jar</type>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>hsqldb</groupId>
|
||||||
|
<artifactId>hsqldb</artifactId>
|
||||||
|
<version>${version.hsqldb}</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<!-- this is optional on core :( and needed for testing -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>cglib</groupId>
|
||||||
|
<artifactId>cglib</artifactId>
|
||||||
|
<version>${version.cglib}</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>javassist</groupId>
|
||||||
|
<artifactId>javassist</artifactId>
|
||||||
|
<version>${version.javassist}</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<source>1.5</source>
|
||||||
|
<target>1.5</target>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-surefire-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<excludes>
|
||||||
|
<!-- Skip a long-running test of a prototype class -->
|
||||||
|
<exclude>**/ClusteredConcurrentTimestampRegionTestCase.java</exclude>
|
||||||
|
</excludes>
|
||||||
|
<systemProperties>
|
||||||
|
<property>
|
||||||
|
<name>hibernate.test.validatefailureexpected</name>
|
||||||
|
<value>true</value>
|
||||||
|
</property>
|
||||||
|
<property>
|
||||||
|
<name>jgroups.bind_addr</name>
|
||||||
|
<value>${jgroups.bind_addr}</value>
|
||||||
|
</property>
|
||||||
|
<!-- There are problems with multicast and IPv6 on some
|
||||||
|
OS/JDK combos, so we tell Java to use IPv4. If you
|
||||||
|
have problems with multicast when running the tests
|
||||||
|
you can try setting this to 'false', although typically
|
||||||
|
that won't be helpful.
|
||||||
|
-->
|
||||||
|
<property>
|
||||||
|
<name>java.net.preferIPv4Stack</name>
|
||||||
|
<value>true</value>
|
||||||
|
</property>
|
||||||
|
<!-- Tell JGroups to only wait a short time for PING
|
||||||
|
responses before determining coordinator. Speeds cluster
|
||||||
|
formation during integration tests. (This is too
|
||||||
|
low a value for a real system; only use for tests.)
|
||||||
|
-->
|
||||||
|
<property>
|
||||||
|
<name>jgroups.ping.timeout</name>
|
||||||
|
<value>500</value>
|
||||||
|
</property>
|
||||||
|
<!-- Tell JGroups to only require one PING response
|
||||||
|
before determining coordinator. Speeds cluster
|
||||||
|
formation during integration tests. (This is too
|
||||||
|
low a value for a real system; only use for tests.)
|
||||||
|
-->
|
||||||
|
<property>
|
||||||
|
<name>jgroups.ping.num_initial_members</name>
|
||||||
|
<value>1</value>
|
||||||
|
</property>
|
||||||
|
<!-- Disable the JGroups message bundling feature
|
||||||
|
to speed tests and avoid FLUSH issue -->
|
||||||
|
<property>
|
||||||
|
<name>jgroups.udp.enable_bundling</name>
|
||||||
|
<value>false</value>
|
||||||
|
</property>
|
||||||
|
</systemProperties>
|
||||||
|
<skipExec>${skipUnitTests}</skipExec>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
|
||||||
|
<profiles>
|
||||||
|
<profile>
|
||||||
|
<id>test</id>
|
||||||
|
<activation>
|
||||||
|
<activeByDefault>false</activeByDefault>
|
||||||
|
</activation>
|
||||||
|
<properties>
|
||||||
|
<skipUnitTests>false</skipUnitTests>
|
||||||
|
</properties>
|
||||||
|
</profile>
|
||||||
|
</profiles>
|
||||||
|
</project>
|
429
cache-infinispan/src/main/java/org/hibernate/cache/infinispan/InfinispanRegionFactory.java
vendored
Normal file
429
cache-infinispan/src/main/java/org/hibernate/cache/infinispan/InfinispanRegionFactory.java
vendored
Normal file
|
@ -0,0 +1,429 @@
|
||||||
|
package org.hibernate.cache.infinispan;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Enumeration;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Properties;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import javax.transaction.TransactionManager;
|
||||||
|
|
||||||
|
import org.hibernate.cache.CacheDataDescription;
|
||||||
|
import org.hibernate.cache.CacheException;
|
||||||
|
import org.hibernate.cache.CollectionRegion;
|
||||||
|
import org.hibernate.cache.EntityRegion;
|
||||||
|
import org.hibernate.cache.QueryResultsRegion;
|
||||||
|
import org.hibernate.cache.RegionFactory;
|
||||||
|
import org.hibernate.cache.TimestampsRegion;
|
||||||
|
import org.hibernate.cache.infinispan.collection.CollectionRegionImpl;
|
||||||
|
import org.hibernate.cache.infinispan.entity.EntityRegionImpl;
|
||||||
|
import org.hibernate.cache.infinispan.query.QueryResultsRegionImpl;
|
||||||
|
import org.hibernate.cache.infinispan.timestamp.TimestampsRegionImpl;
|
||||||
|
import org.hibernate.cache.infinispan.timestamp.TimestampTypeOverrides;
|
||||||
|
import org.hibernate.cache.infinispan.tm.HibernateTransactionManagerLookup;
|
||||||
|
import org.hibernate.cfg.Settings;
|
||||||
|
import org.hibernate.util.PropertiesHelper;
|
||||||
|
import org.infinispan.Cache;
|
||||||
|
import org.infinispan.config.Configuration;
|
||||||
|
import org.infinispan.manager.CacheManager;
|
||||||
|
import org.infinispan.manager.DefaultCacheManager;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A {@link RegionFactory} for <a href="http://www.jboss.org/infinispan">Infinispan</a>-backed cache
|
||||||
|
* regions.
|
||||||
|
*
|
||||||
|
* @author Chris Bredesen
|
||||||
|
* @author Galder Zamarreño
|
||||||
|
* @since 3.5
|
||||||
|
*/
|
||||||
|
public class InfinispanRegionFactory implements RegionFactory {
|
||||||
|
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(InfinispanRegionFactory.class);
|
||||||
|
|
||||||
|
private static final String PREFIX = "hibernate.cache.infinispan.";
|
||||||
|
|
||||||
|
private static final String CONFIG_SUFFIX = ".cfg";
|
||||||
|
|
||||||
|
private static final String STRATEGY_SUFFIX = ".eviction.strategy";
|
||||||
|
|
||||||
|
private static final String WAKE_UP_INTERVAL_SUFFIX = ".eviction.wake_up_interval";
|
||||||
|
|
||||||
|
private static final String MAX_ENTRIES_SUFFIX = ".eviction.max_entries";
|
||||||
|
|
||||||
|
private static final String LIFESPAN_SUFFIX = ".eviction.lifespan";
|
||||||
|
|
||||||
|
private static final String MAX_IDLE_SUFFIX = ".eviction.max_idle";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Classpath or filesystem resource containing Infinispan configurations the factory should use.
|
||||||
|
*
|
||||||
|
* @see #DEF_INFINISPAN_CONFIG_RESOURCE
|
||||||
|
*/
|
||||||
|
public static final String INFINISPAN_CONFIG_RESOURCE_PROP = "hibernate.cache.infinispan.cfg";
|
||||||
|
|
||||||
|
private static final String ENTITY_KEY = "entity";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Name of the configuration that should be used for entity caches.
|
||||||
|
*
|
||||||
|
* @see #DEF_ENTITY_RESOURCE
|
||||||
|
*/
|
||||||
|
public static final String ENTITY_CACHE_RESOURCE_PROP = PREFIX + ENTITY_KEY + CONFIG_SUFFIX;
|
||||||
|
|
||||||
|
private static final String COLLECTION_KEY = "collection";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Name of the configuration that should be used for collection caches.
|
||||||
|
* No default value, as by default we try to use the same Infinispan cache
|
||||||
|
* instance we use for entity caching.
|
||||||
|
*
|
||||||
|
* @see #ENTITY_CACHE_RESOURCE_PROP
|
||||||
|
* @see #DEF_ENTITY_RESOURCE
|
||||||
|
*/
|
||||||
|
public static final String COLLECTION_CACHE_RESOURCE_PROP = PREFIX + COLLECTION_KEY + CONFIG_SUFFIX;
|
||||||
|
|
||||||
|
private static final String TIMESTAMPS_KEY = "timestamps";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Name of the configuration that should be used for timestamp caches.
|
||||||
|
*
|
||||||
|
* @see #DEF_TS_RESOURCE
|
||||||
|
*/
|
||||||
|
public static final String TIMESTAMPS_CACHE_RESOURCE_PROP = PREFIX + TIMESTAMPS_KEY + CONFIG_SUFFIX;
|
||||||
|
|
||||||
|
private static final String QUERY_KEY = "query";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Name of the configuration that should be used for query caches.
|
||||||
|
*
|
||||||
|
* @see #DEF_QUERY_RESOURCE
|
||||||
|
*/
|
||||||
|
public static final String QUERY_CACHE_RESOURCE_PROP = PREFIX + QUERY_KEY + CONFIG_SUFFIX;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default value for {@link #INFINISPAN_RESOURCE_PROP}. Specifies the "infinispan-configs.xml" file in this package.
|
||||||
|
*/
|
||||||
|
public static final String DEF_INFINISPAN_CONFIG_RESOURCE = "org/hibernate/cache/infinispan/builder/infinispan-configs.xml";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default value for {@link #ENTITY_CACHE_RESOURCE_PROP}.
|
||||||
|
*/
|
||||||
|
public static final String DEF_ENTITY_RESOURCE = "entity";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default value for {@link #TIMESTAMPS_CACHE_RESOURCE_PROP}.
|
||||||
|
*/
|
||||||
|
public static final String DEF_TIMESTAMPS_RESOURCE = "timestamps";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default value for {@link #QUERY_CACHE_RESOURCE_PROP}.
|
||||||
|
*/
|
||||||
|
public static final String DEF_QUERY_RESOURCE = "local-query";
|
||||||
|
|
||||||
|
private CacheManager manager;
|
||||||
|
|
||||||
|
private final Map<String, TypeOverrides> typeOverrides = new HashMap<String, TypeOverrides>();
|
||||||
|
|
||||||
|
private final Set<String> definedConfigurations = new HashSet<String>();
|
||||||
|
|
||||||
|
private org.infinispan.transaction.lookup.TransactionManagerLookup transactionManagerlookup;
|
||||||
|
|
||||||
|
private TransactionManager transactionManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new instance using the default configuration.
|
||||||
|
*/
|
||||||
|
public InfinispanRegionFactory() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new instance using conifguration properties in <code>props</code>.
|
||||||
|
*
|
||||||
|
* @param props
|
||||||
|
* Environmental properties; currently unused.
|
||||||
|
*/
|
||||||
|
public InfinispanRegionFactory(Properties props) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
public CollectionRegion buildCollectionRegion(String regionName, Properties properties, CacheDataDescription metadata) throws CacheException {
|
||||||
|
log.debug("Building collection cache region [" + regionName + "]");
|
||||||
|
Cache cache = getCache(regionName, COLLECTION_KEY, properties);
|
||||||
|
return new CollectionRegionImpl(cache, regionName, metadata, transactionManager);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** {@inheritDoc} */
|
||||||
|
public EntityRegion buildEntityRegion(String regionName, Properties properties, CacheDataDescription metadata) throws CacheException {
|
||||||
|
if (log.isDebugEnabled()) log.debug("Building entity cache region [" + regionName + "]");
|
||||||
|
Cache cache = getCache(regionName, ENTITY_KEY, properties);
|
||||||
|
return new EntityRegionImpl(cache, regionName, metadata, transactionManager);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public QueryResultsRegion buildQueryResultsRegion(String regionName, Properties properties)
|
||||||
|
throws CacheException {
|
||||||
|
log.debug("Building query results cache region [" + regionName + "]");
|
||||||
|
String cacheName = typeOverrides.get(QUERY_KEY).getCacheName();
|
||||||
|
return new QueryResultsRegionImpl(manager.getCache(cacheName), regionName, properties, transactionManager);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public TimestampsRegion buildTimestampsRegion(String regionName, Properties properties)
|
||||||
|
throws CacheException {
|
||||||
|
log.debug("Building timestamps cache region [" + regionName + "]");
|
||||||
|
String cacheName = typeOverrides.get(TIMESTAMPS_KEY).getCacheName();
|
||||||
|
return new TimestampsRegionImpl(manager.getCache(cacheName), regionName, transactionManager);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public boolean isMinimalPutsEnabledByDefault() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public long nextTimestamp() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCacheManager(CacheManager manager) {
|
||||||
|
this.manager = manager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CacheManager getCacheManager() {
|
||||||
|
return manager;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public void start(Settings settings, Properties properties) throws CacheException {
|
||||||
|
log.debug("Starting Infinispan CacheManager");
|
||||||
|
try {
|
||||||
|
transactionManagerlookup = new HibernateTransactionManagerLookup(settings, properties);
|
||||||
|
transactionManager = transactionManagerlookup.getTransactionManager();
|
||||||
|
|
||||||
|
String configLoc = PropertiesHelper.getString(INFINISPAN_CONFIG_RESOURCE_PROP, properties, DEF_INFINISPAN_CONFIG_RESOURCE);
|
||||||
|
manager = createCacheManager(configLoc);
|
||||||
|
initGenericDataTypeOverrides();
|
||||||
|
Enumeration keys = properties.propertyNames();
|
||||||
|
while (keys.hasMoreElements()) {
|
||||||
|
String key = (String) keys.nextElement();
|
||||||
|
int prefixLoc = -1;
|
||||||
|
if ((prefixLoc = key.indexOf(PREFIX)) != -1) {
|
||||||
|
dissectProperty(prefixLoc, key, properties);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
defineGenericDataTypeCacheConfigurations(settings, properties);
|
||||||
|
} catch (CacheException ce) {
|
||||||
|
throw ce;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
throw new CacheException("Unable to start region factory", t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
public void stop() {
|
||||||
|
log.debug("Stopping Infinispan CacheManager");
|
||||||
|
manager.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an unmodifiable map containing configured entity/collection type configuration overrides.
|
||||||
|
* This method should be used primarily for testing/checking purpouses.
|
||||||
|
*
|
||||||
|
* @return an unmodifiable map.
|
||||||
|
*/
|
||||||
|
public Map<String, TypeOverrides> getTypeOverrides() {
|
||||||
|
return Collections.unmodifiableMap(typeOverrides);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<String> getDefinedConfigurations() {
|
||||||
|
return Collections.unmodifiableSet(definedConfigurations);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected CacheManager createCacheManager(String configLoc) throws CacheException {
|
||||||
|
try {
|
||||||
|
return new DefaultCacheManager(configLoc);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new CacheException("Unable to create default cache manager", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Map<String, TypeOverrides> initGenericDataTypeOverrides() {
|
||||||
|
TypeOverrides entityOverrides = new TypeOverrides();
|
||||||
|
entityOverrides.setCacheName(DEF_ENTITY_RESOURCE);
|
||||||
|
typeOverrides.put(ENTITY_KEY, entityOverrides);
|
||||||
|
TypeOverrides collectionOverrides = new TypeOverrides();
|
||||||
|
collectionOverrides.setCacheName(DEF_ENTITY_RESOURCE);
|
||||||
|
typeOverrides.put(COLLECTION_KEY, collectionOverrides);
|
||||||
|
TypeOverrides timestampOverrides = new TimestampTypeOverrides();
|
||||||
|
timestampOverrides.setCacheName(DEF_TIMESTAMPS_RESOURCE);
|
||||||
|
typeOverrides.put(TIMESTAMPS_KEY, timestampOverrides);
|
||||||
|
TypeOverrides queryOverrides = new TypeOverrides();
|
||||||
|
queryOverrides.setCacheName(DEF_QUERY_RESOURCE);
|
||||||
|
typeOverrides.put(QUERY_KEY, queryOverrides);
|
||||||
|
return typeOverrides;
|
||||||
|
}
|
||||||
|
|
||||||
|
// private boolean isGenericDataTypeProperty(String property) {
|
||||||
|
// return property.startsWith(PREFIX + ENTITY_KEY) || property.startsWith(PREFIX + COLLECTION_KEY)
|
||||||
|
// || property.startsWith(PREFIX + QUERY_KEY) || property.startsWith(PREFIX + TIMESTAMP_KEY);
|
||||||
|
// }
|
||||||
|
|
||||||
|
private void dissectProperty(int prefixLoc, String key, Properties properties) {
|
||||||
|
TypeOverrides cfgOverride = null;
|
||||||
|
int suffixLoc = -1;
|
||||||
|
if (!key.equals(INFINISPAN_CONFIG_RESOURCE_PROP) && (suffixLoc = key.indexOf(CONFIG_SUFFIX)) != -1) {
|
||||||
|
cfgOverride = getOrCreateConfig(prefixLoc, key, suffixLoc);
|
||||||
|
cfgOverride.setCacheName(PropertiesHelper.extractPropertyValue(key, properties));
|
||||||
|
} else if ((suffixLoc = key.indexOf(STRATEGY_SUFFIX)) != -1) {
|
||||||
|
cfgOverride = getOrCreateConfig(prefixLoc, key, suffixLoc);
|
||||||
|
cfgOverride.setEvictionStrategy(PropertiesHelper.extractPropertyValue(key, properties));
|
||||||
|
} else if ((suffixLoc = key.indexOf(WAKE_UP_INTERVAL_SUFFIX)) != -1) {
|
||||||
|
cfgOverride = getOrCreateConfig(prefixLoc, key, suffixLoc);
|
||||||
|
cfgOverride.setEvictionWakeUpInterval(Long.parseLong(PropertiesHelper.extractPropertyValue(key, properties)));
|
||||||
|
} else if ((suffixLoc = key.indexOf(MAX_ENTRIES_SUFFIX)) != -1) {
|
||||||
|
cfgOverride = getOrCreateConfig(prefixLoc, key, suffixLoc);
|
||||||
|
cfgOverride.setEvictionMaxEntries(PropertiesHelper.getInt(key, properties, -1));
|
||||||
|
} else if ((suffixLoc = key.indexOf(LIFESPAN_SUFFIX)) != -1) {
|
||||||
|
cfgOverride = getOrCreateConfig(prefixLoc, key, suffixLoc);
|
||||||
|
cfgOverride.setExpirationLifespan(Long.parseLong(PropertiesHelper.extractPropertyValue(key, properties)));
|
||||||
|
} else if ((suffixLoc = key.indexOf(MAX_IDLE_SUFFIX)) != -1) {
|
||||||
|
cfgOverride = getOrCreateConfig(prefixLoc, key, suffixLoc);
|
||||||
|
cfgOverride.setExpirationMaxIdle(Long.parseLong(PropertiesHelper.extractPropertyValue(key, properties)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// private Configuration overrideCacheConfig(TypeOverrides config, Configuration baseCacheCfg) {
|
||||||
|
// // If eviction strategy is different from null, an override has been defined
|
||||||
|
// EvictionStrategy strategy = config.getEvictionStrategy();
|
||||||
|
// if (strategy != null) baseCacheCfg.setEvictionStrategy(strategy);
|
||||||
|
// // If eviction wake up interval is different from min value, an override has been defined
|
||||||
|
// // Checking for -1 might not be enough because user might have defined -1 in the config.
|
||||||
|
// // Same applies to other configuration options.
|
||||||
|
// long wakeUpInterval = config.getEvictionWakeUpInterval();
|
||||||
|
// if (wakeUpInterval != Long.MIN_VALUE) baseCacheCfg.setEvictionWakeUpInterval(wakeUpInterval);
|
||||||
|
// int maxEntries = config.getEvictionMaxEntries();
|
||||||
|
// if (maxEntries != Integer.MIN_VALUE) baseCacheCfg.setEvictionMaxEntries(maxEntries);
|
||||||
|
// long lifespan = config.getExpirationLifespan();
|
||||||
|
// if (lifespan != Long.MIN_VALUE) baseCacheCfg.setExpirationLifespan(lifespan);
|
||||||
|
// long maxIdle = config.getExpirationMaxIdle();
|
||||||
|
// if (maxIdle != Long.MIN_VALUE) baseCacheCfg.setExpirationMaxIdle(maxIdle);
|
||||||
|
// return baseCacheCfg;
|
||||||
|
// }
|
||||||
|
|
||||||
|
private TypeOverrides getOrCreateConfig(int prefixLoc, String key, int suffixLoc) {
|
||||||
|
String name = key.substring(prefixLoc + PREFIX.length(), suffixLoc);
|
||||||
|
TypeOverrides cfgOverride = typeOverrides.get(name);
|
||||||
|
if (cfgOverride == null) {
|
||||||
|
cfgOverride = new TypeOverrides();
|
||||||
|
typeOverrides.put(name, cfgOverride);
|
||||||
|
}
|
||||||
|
return cfgOverride;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void defineGenericDataTypeCacheConfigurations(Settings settings, Properties properties) throws CacheException {
|
||||||
|
String[] defaultGenericDataTypes = new String[]{ENTITY_KEY, COLLECTION_KEY, TIMESTAMPS_KEY, QUERY_KEY};
|
||||||
|
for (String type : defaultGenericDataTypes) {
|
||||||
|
TypeOverrides override = typeOverrides.get(type);
|
||||||
|
String cacheName = override.getCacheName();
|
||||||
|
Configuration newCacheCfg = override.createInfinispanConfiguration();
|
||||||
|
// Apply overrides
|
||||||
|
Configuration cacheConfig = manager.defineConfiguration(cacheName, cacheName, newCacheCfg);
|
||||||
|
// Configure transaction manager
|
||||||
|
cacheConfig = configureTransactionManager(cacheConfig, cacheName, properties);
|
||||||
|
manager.defineConfiguration(cacheName, cacheName, cacheConfig);
|
||||||
|
definedConfigurations.add(cacheName);
|
||||||
|
override.validateInfinispanConfiguration(cacheConfig);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Cache getCache(String regionName, String typeKey, Properties properties) {
|
||||||
|
TypeOverrides regionOverride = typeOverrides.get(regionName);
|
||||||
|
if (!definedConfigurations.contains(regionName)) {
|
||||||
|
String templateCacheName = null;
|
||||||
|
Configuration regionCacheCfg = null;
|
||||||
|
if (regionOverride != null) {
|
||||||
|
if (log.isDebugEnabled()) log.debug("Entity cache region specific configuration exists: " + regionOverride);
|
||||||
|
regionCacheCfg = regionOverride.createInfinispanConfiguration();
|
||||||
|
String cacheName = regionOverride.getCacheName();
|
||||||
|
if (cacheName != null) // Region specific override with a given cache name
|
||||||
|
templateCacheName = cacheName;
|
||||||
|
else // Region specific override without cache name, so template cache name is generic for data type.
|
||||||
|
templateCacheName = typeOverrides.get(typeKey).getCacheName();
|
||||||
|
} else {
|
||||||
|
// No region specific overrides, template cache name is generic for data type.
|
||||||
|
templateCacheName = typeOverrides.get(typeKey).getCacheName();
|
||||||
|
regionCacheCfg = typeOverrides.get(typeKey).createInfinispanConfiguration();
|
||||||
|
}
|
||||||
|
// Configure transaction manager
|
||||||
|
regionCacheCfg = configureTransactionManager(regionCacheCfg, templateCacheName, properties);
|
||||||
|
// Apply overrides
|
||||||
|
manager.defineConfiguration(regionName, templateCacheName, regionCacheCfg);
|
||||||
|
definedConfigurations.add(regionName);
|
||||||
|
}
|
||||||
|
return manager.getCache(regionName);
|
||||||
|
|
||||||
|
// if (regionOverride != null) {
|
||||||
|
// if (log.isDebugEnabled()) log.debug("Entity cache region specific configuration exists: " + regionOverride);
|
||||||
|
// String cacheName = regionOverride.getCacheName();
|
||||||
|
// if (cacheName != null) {
|
||||||
|
// // Region specific override with a given cache name
|
||||||
|
// if (!definedConfigurations.contains(regionName)) {
|
||||||
|
// templateCacheName = cacheName;
|
||||||
|
// regionCacheCfg = regionOverride.createInfinispanConfiguration();
|
||||||
|
// manager.defineConfiguration(regionName, templateCacheName, regionCacheCfg);
|
||||||
|
// definedConfigurations.add(regionName);
|
||||||
|
// }
|
||||||
|
// return manager.getCache(regionName);
|
||||||
|
// } else {
|
||||||
|
// // Region specific override without cache name, so template cache name is generic for data type.
|
||||||
|
// if (!definedConfigurations.contains(regionName)) {
|
||||||
|
// templateCacheName = typeOverrides.get(typeKey).getCacheName();
|
||||||
|
// regionCacheCfg = regionOverride.createInfinispanConfiguration();
|
||||||
|
// manager.defineConfiguration(regionName, templateCacheName, regionCacheCfg);
|
||||||
|
// definedConfigurations.add(regionName);
|
||||||
|
// }
|
||||||
|
// return manager.getCache(regionName);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// if (!definedConfigurations.contains(regionName)) {
|
||||||
|
// templateCacheName = typeOverrides.get(typeKey).getCacheName();
|
||||||
|
// regionCacheCfg = typeOverrides.get(typeKey).createInfinispanConfiguration();
|
||||||
|
// manager.defineConfiguration(regionName, templateCacheName, regionCacheCfg);
|
||||||
|
// definedConfigurations.add(regionName);
|
||||||
|
// }
|
||||||
|
// // No region specific overrides, get a cache instance for the generic entity data type region
|
||||||
|
// return manager.getCache(regionName);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Configuration configureTransactionManager(Configuration regionOverrides, String templateCacheName, Properties properties) {
|
||||||
|
// Get existing configuration to verify whether a tm was configured or not.
|
||||||
|
Configuration templateConfig = manager.defineConfiguration(templateCacheName, new Configuration());
|
||||||
|
String ispnTmLookupClassName = templateConfig.getTransactionManagerLookupClass();
|
||||||
|
String hbTmLookupClassName = org.hibernate.cache.infinispan.tm.HibernateTransactionManagerLookup.class.getName();
|
||||||
|
if (ispnTmLookupClassName != null && !ispnTmLookupClassName.equals(hbTmLookupClassName)) {
|
||||||
|
log.debug("Infinispan is configured [" + ispnTmLookupClassName + "] with a different transaction manager lookup " +
|
||||||
|
"class than Hibernate [" + hbTmLookupClassName + "]");
|
||||||
|
} else {
|
||||||
|
regionOverrides.setTransactionManagerLookup(transactionManagerlookup);
|
||||||
|
}
|
||||||
|
return regionOverrides;
|
||||||
|
}
|
||||||
|
}
|
138
cache-infinispan/src/main/java/org/hibernate/cache/infinispan/TypeOverrides.java
vendored
Normal file
138
cache-infinispan/src/main/java/org/hibernate/cache/infinispan/TypeOverrides.java
vendored
Normal file
|
@ -0,0 +1,138 @@
|
||||||
|
/*
|
||||||
|
* JBoss, Home of Professional Open Source.
|
||||||
|
* Copyright 2009, Red Hat, Inc. and/or it's affiliates, and individual contributors
|
||||||
|
* as indicated by the @author tags. See the copyright.txt file in the
|
||||||
|
* distribution for a full listing of individual contributors.
|
||||||
|
*
|
||||||
|
* This is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU Lesser General Public License as
|
||||||
|
* published by the Free Software Foundation; either version 2.1 of
|
||||||
|
* the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This software is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this software; if not, write to the Free
|
||||||
|
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||||
|
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
|
||||||
|
*/
|
||||||
|
package org.hibernate.cache.infinispan;
|
||||||
|
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
import org.hibernate.cache.CacheException;
|
||||||
|
import org.infinispan.config.Configuration;
|
||||||
|
import org.infinispan.eviction.EvictionStrategy;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class represents Infinispan cache parameters that can be configured via hibernate configuration properties
|
||||||
|
* for either general entity/collection/query/timestamp data type caches and overrides for individual entity or
|
||||||
|
* collection caches. Configuration these properties override previously defined properties in XML file.
|
||||||
|
*
|
||||||
|
* @author Galder Zamarreño
|
||||||
|
* @since 3.5
|
||||||
|
*/
|
||||||
|
public class TypeOverrides {
|
||||||
|
|
||||||
|
private String cacheName;
|
||||||
|
|
||||||
|
private EvictionStrategy evictionStrategy;
|
||||||
|
|
||||||
|
private long evictionWakeUpInterval = Long.MIN_VALUE;
|
||||||
|
|
||||||
|
private int evictionMaxEntries = Integer.MIN_VALUE;
|
||||||
|
|
||||||
|
private long expirationLifespan = Long.MIN_VALUE;
|
||||||
|
|
||||||
|
private long expirationMaxIdle = Long.MIN_VALUE;
|
||||||
|
|
||||||
|
public String getCacheName() {
|
||||||
|
return cacheName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCacheName(String cacheName) {
|
||||||
|
this.cacheName = cacheName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public EvictionStrategy getEvictionStrategy() {
|
||||||
|
return evictionStrategy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEvictionStrategy(String evictionStrategy) {
|
||||||
|
this.evictionStrategy = EvictionStrategy.valueOf(uc(evictionStrategy));
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getEvictionWakeUpInterval() {
|
||||||
|
return evictionWakeUpInterval;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEvictionWakeUpInterval(long evictionWakeUpInterval) {
|
||||||
|
this.evictionWakeUpInterval = evictionWakeUpInterval;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getEvictionMaxEntries() {
|
||||||
|
return evictionMaxEntries;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEvictionMaxEntries(int evictionMaxEntries) {
|
||||||
|
this.evictionMaxEntries = evictionMaxEntries;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getExpirationLifespan() {
|
||||||
|
return expirationLifespan;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setExpirationLifespan(long expirationLifespan) {
|
||||||
|
this.expirationLifespan = expirationLifespan;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getExpirationMaxIdle() {
|
||||||
|
return expirationMaxIdle;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setExpirationMaxIdle(long expirationMaxIdle) {
|
||||||
|
this.expirationMaxIdle = expirationMaxIdle;
|
||||||
|
}
|
||||||
|
|
||||||
|
// public boolean isConvertedToInfinispanConfiguration() {
|
||||||
|
// return convertedToInfinispanConfiguration;
|
||||||
|
// }
|
||||||
|
|
||||||
|
public Configuration createInfinispanConfiguration() {
|
||||||
|
Configuration cacheCfg = new Configuration();
|
||||||
|
// If eviction strategy is different from null, an override has been defined
|
||||||
|
if (evictionStrategy != null) cacheCfg.setEvictionStrategy(evictionStrategy);
|
||||||
|
// If eviction wake up interval is different from min value, an override has been defined
|
||||||
|
// Checking for -1 might not be enough because user might have defined -1 in the config.
|
||||||
|
// Same applies to other configuration options.
|
||||||
|
if (evictionWakeUpInterval != Long.MIN_VALUE) cacheCfg.setEvictionWakeUpInterval(evictionWakeUpInterval);
|
||||||
|
if (evictionMaxEntries != Integer.MIN_VALUE) cacheCfg.setEvictionMaxEntries(evictionMaxEntries);
|
||||||
|
if (expirationLifespan != Long.MIN_VALUE) cacheCfg.setExpirationLifespan(expirationLifespan);
|
||||||
|
if (expirationMaxIdle != Long.MIN_VALUE) cacheCfg.setExpirationMaxIdle(expirationMaxIdle);
|
||||||
|
// convertedToInfinispanConfiguration = true;
|
||||||
|
return cacheCfg;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void validateInfinispanConfiguration(Configuration configuration) throws CacheException {
|
||||||
|
// no-op
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return new StringBuilder().append(getClass().getSimpleName()).append('{')
|
||||||
|
.append("cache=").append(cacheName)
|
||||||
|
.append(", strategy=").append(evictionStrategy)
|
||||||
|
.append(", wakeUpInterval=").append(evictionWakeUpInterval)
|
||||||
|
.append(", maxEntries=").append(evictionMaxEntries)
|
||||||
|
.append(", lifespan=").append(expirationLifespan)
|
||||||
|
.append(", maxIdle=").append(expirationMaxIdle)
|
||||||
|
.append('}').toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String uc(String s) {
|
||||||
|
return s == null ? null : s.toUpperCase(Locale.ENGLISH);
|
||||||
|
}
|
||||||
|
}
|
116
cache-infinispan/src/main/java/org/hibernate/cache/infinispan/access/TransactionalAccessDelegate.java
vendored
Executable file
116
cache-infinispan/src/main/java/org/hibernate/cache/infinispan/access/TransactionalAccessDelegate.java
vendored
Executable file
|
@ -0,0 +1,116 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2007, Red Hat, Inc. and/or it's affiliates or third-party contributors as
|
||||||
|
* indicated by the @author tags or express copyright attribution
|
||||||
|
* statements applied by the authors. All third-party contributions are
|
||||||
|
* distributed under license by Red Hat, Inc. and/or it's affiliates.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||||
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
* Lesser General Public License, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this distribution; if not, write to:
|
||||||
|
* Free Software Foundation, Inc.
|
||||||
|
* 51 Franklin Street, Fifth Floor
|
||||||
|
* Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
package org.hibernate.cache.infinispan.access;
|
||||||
|
|
||||||
|
import org.hibernate.cache.CacheException;
|
||||||
|
import org.hibernate.cache.access.CollectionRegionAccessStrategy;
|
||||||
|
import org.hibernate.cache.access.EntityRegionAccessStrategy;
|
||||||
|
import org.hibernate.cache.access.SoftLock;
|
||||||
|
import org.infinispan.Cache;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines the strategy for transactional access to entity or collection data in a Infinispan instance.
|
||||||
|
* <p>
|
||||||
|
* The intent of this class is to encapsulate common code and serve as a delegate for
|
||||||
|
* {@link EntityRegionAccessStrategy} and {@link CollectionRegionAccessStrategy} implementations.
|
||||||
|
*
|
||||||
|
* @author Brian Stansberry
|
||||||
|
* @author Galder Zamarreño
|
||||||
|
* @since 3.5
|
||||||
|
*/
|
||||||
|
public class TransactionalAccessDelegate {
|
||||||
|
|
||||||
|
protected final Cache cache;
|
||||||
|
|
||||||
|
public TransactionalAccessDelegate(Cache cache) {
|
||||||
|
this.cache = cache;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object get(Object key, long txTimestamp) throws CacheException {
|
||||||
|
return cache.get(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean putFromLoad(Object key, Object value, long txTimestamp, Object version) throws CacheException {
|
||||||
|
cache.putForExternalRead(key, value);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean putFromLoad(Object key, Object value, long txTimestamp, Object version, boolean minimalPutOverride)
|
||||||
|
throws CacheException {
|
||||||
|
return putFromLoad(key, value, txTimestamp, version);
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
||||||
|
cache.put(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 {
|
||||||
|
cache.put(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 {
|
||||||
|
cache.remove(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeAll() throws CacheException {
|
||||||
|
cache.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
// public void evict(Object key) throws CacheException {
|
||||||
|
// cache.evict(key);
|
||||||
|
// }
|
||||||
|
|
||||||
|
public void evictAll() throws CacheException {
|
||||||
|
evictOrRemoveAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void evictOrRemoveAll() throws CacheException {
|
||||||
|
cache.clear();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
package org.hibernate.cache.infinispan.collection;
|
||||||
|
|
||||||
|
import javax.transaction.TransactionManager;
|
||||||
|
|
||||||
|
import org.hibernate.cache.CacheDataDescription;
|
||||||
|
import org.hibernate.cache.CacheException;
|
||||||
|
import org.hibernate.cache.CollectionRegion;
|
||||||
|
import org.hibernate.cache.access.AccessType;
|
||||||
|
import org.hibernate.cache.access.CollectionRegionAccessStrategy;
|
||||||
|
import org.hibernate.cache.infinispan.impl.BaseTransactionalDataRegion;
|
||||||
|
import org.infinispan.Cache;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Chris Bredesen
|
||||||
|
* @author Galder Zamarreño
|
||||||
|
* @since 3.5
|
||||||
|
*/
|
||||||
|
public class CollectionRegionImpl extends BaseTransactionalDataRegion implements CollectionRegion {
|
||||||
|
|
||||||
|
public CollectionRegionImpl(Cache<Object, Object> cache, String name, CacheDataDescription metadata, TransactionManager transactionManager) {
|
||||||
|
super(cache, name, metadata, transactionManager);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CollectionRegionAccessStrategy buildAccessStrategy(AccessType accessType) throws CacheException {
|
||||||
|
if (AccessType.READ_ONLY.equals(accessType)) {
|
||||||
|
return new ReadOnlyAccess(this);
|
||||||
|
} else if (AccessType.TRANSACTIONAL.equals(accessType)) {
|
||||||
|
return new TransactionalAccess(this);
|
||||||
|
}
|
||||||
|
throw new CacheException("Unsupported access type [" + accessType.getName() + "]");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
41
cache-infinispan/src/main/java/org/hibernate/cache/infinispan/collection/ReadOnlyAccess.java
vendored
Normal file
41
cache-infinispan/src/main/java/org/hibernate/cache/infinispan/collection/ReadOnlyAccess.java
vendored
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
package org.hibernate.cache.infinispan.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 a
|
||||||
|
* Infinispan instance.
|
||||||
|
* <p/>
|
||||||
|
* The read-only access to a Infinispan really is still transactional, just with
|
||||||
|
* the extra semantic or guarantee that we will not update data.
|
||||||
|
*
|
||||||
|
* @author Chris Bredesen
|
||||||
|
* @author Galder Zamarreño
|
||||||
|
* @since 3.5
|
||||||
|
*/
|
||||||
|
class ReadOnlyAccess extends TransactionalAccess {
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(ReadOnlyAccess.class);
|
||||||
|
|
||||||
|
ReadOnlyAccess(CollectionRegionImpl region) {
|
||||||
|
super(region);
|
||||||
|
}
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
|
||||||
|
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 item");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,74 @@
|
||||||
|
package org.hibernate.cache.infinispan.collection;
|
||||||
|
|
||||||
|
import org.hibernate.cache.CacheException;
|
||||||
|
import org.hibernate.cache.CollectionRegion;
|
||||||
|
import org.hibernate.cache.access.CollectionRegionAccessStrategy;
|
||||||
|
import org.hibernate.cache.access.SoftLock;
|
||||||
|
import org.hibernate.cache.infinispan.access.TransactionalAccessDelegate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transactional collection region access for Infinispan.
|
||||||
|
*
|
||||||
|
* @author Chris Bredesen
|
||||||
|
* @author Galder Zamarreño
|
||||||
|
* @since 3.5
|
||||||
|
*/
|
||||||
|
class TransactionalAccess implements CollectionRegionAccessStrategy {
|
||||||
|
|
||||||
|
private final CollectionRegionImpl region;
|
||||||
|
|
||||||
|
private final TransactionalAccessDelegate delegate;
|
||||||
|
|
||||||
|
TransactionalAccess(CollectionRegionImpl region) {
|
||||||
|
this.region = region;
|
||||||
|
this.delegate = new TransactionalAccessDelegate(region.getCache());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void evict(Object key) throws CacheException {
|
||||||
|
// delegate.evict(key);
|
||||||
|
delegate.remove(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void evictAll() throws CacheException {
|
||||||
|
delegate.evictAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object get(Object key, long txTimestamp) throws CacheException {
|
||||||
|
return delegate.get(key, txTimestamp);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean putFromLoad(Object key, Object value, long txTimestamp, Object version) throws CacheException {
|
||||||
|
return delegate.putFromLoad(key, value, txTimestamp, version);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean putFromLoad(Object key, Object value, long txTimestamp, Object version, boolean minimalPutOverride) throws CacheException {
|
||||||
|
return delegate.putFromLoad(key, value, txTimestamp, version, minimalPutOverride);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void remove(Object key) throws CacheException {
|
||||||
|
delegate.remove(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeAll() throws CacheException {
|
||||||
|
delegate.removeAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
public CollectionRegion getRegion() {
|
||||||
|
return region;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
33
cache-infinispan/src/main/java/org/hibernate/cache/infinispan/entity/EntityRegionImpl.java
vendored
Normal file
33
cache-infinispan/src/main/java/org/hibernate/cache/infinispan/entity/EntityRegionImpl.java
vendored
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
package org.hibernate.cache.infinispan.entity;
|
||||||
|
|
||||||
|
import javax.transaction.TransactionManager;
|
||||||
|
|
||||||
|
import org.hibernate.cache.CacheDataDescription;
|
||||||
|
import org.hibernate.cache.CacheException;
|
||||||
|
import org.hibernate.cache.EntityRegion;
|
||||||
|
import org.hibernate.cache.access.AccessType;
|
||||||
|
import org.hibernate.cache.access.EntityRegionAccessStrategy;
|
||||||
|
import org.hibernate.cache.infinispan.impl.BaseTransactionalDataRegion;
|
||||||
|
import org.infinispan.Cache;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Chris Bredesen
|
||||||
|
* @author Galder Zamarreño
|
||||||
|
* @since 3.5
|
||||||
|
*/
|
||||||
|
public class EntityRegionImpl extends BaseTransactionalDataRegion implements EntityRegion {
|
||||||
|
|
||||||
|
public EntityRegionImpl(Cache<Object, Object> cache, String name, CacheDataDescription metadata, TransactionManager transactionManager) {
|
||||||
|
super(cache, name, metadata, transactionManager);
|
||||||
|
}
|
||||||
|
|
||||||
|
public EntityRegionAccessStrategy buildAccessStrategy(AccessType accessType) throws CacheException {
|
||||||
|
if (AccessType.READ_ONLY.equals(accessType)) {
|
||||||
|
return new ReadOnlyAccess(this);
|
||||||
|
} else if (AccessType.TRANSACTIONAL.equals(accessType)) {
|
||||||
|
return new TransactionalAccess(this);
|
||||||
|
}
|
||||||
|
throw new CacheException("Unsupported access type [" + accessType.getName() + "]");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
49
cache-infinispan/src/main/java/org/hibernate/cache/infinispan/entity/ReadOnlyAccess.java
vendored
Normal file
49
cache-infinispan/src/main/java/org/hibernate/cache/infinispan/entity/ReadOnlyAccess.java
vendored
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
package org.hibernate.cache.infinispan.entity;
|
||||||
|
|
||||||
|
import org.hibernate.cache.CacheException;
|
||||||
|
import org.hibernate.cache.access.SoftLock;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A specialization of {@link TransactionalAccess} that ensures we never update data. Infinispan
|
||||||
|
* access is always transactional.
|
||||||
|
*
|
||||||
|
* @author Chris Bredesen
|
||||||
|
* @author Galder Zamarreño
|
||||||
|
* @since 3.5
|
||||||
|
*/
|
||||||
|
class ReadOnlyAccess extends TransactionalAccess {
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(ReadOnlyAccess.class);
|
||||||
|
|
||||||
|
ReadOnlyAccess(EntityRegionImpl region) {
|
||||||
|
super(region);
|
||||||
|
}
|
||||||
|
|
||||||
|
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 item");
|
||||||
|
}
|
||||||
|
|
||||||
|
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 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");
|
||||||
|
}
|
||||||
|
|
||||||
|
@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");
|
||||||
|
}
|
||||||
|
}
|
89
cache-infinispan/src/main/java/org/hibernate/cache/infinispan/entity/TransactionalAccess.java
vendored
Normal file
89
cache-infinispan/src/main/java/org/hibernate/cache/infinispan/entity/TransactionalAccess.java
vendored
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
package org.hibernate.cache.infinispan.entity;
|
||||||
|
|
||||||
|
import org.hibernate.cache.CacheException;
|
||||||
|
import org.hibernate.cache.EntityRegion;
|
||||||
|
import org.hibernate.cache.access.EntityRegionAccessStrategy;
|
||||||
|
import org.hibernate.cache.access.SoftLock;
|
||||||
|
import org.hibernate.cache.infinispan.access.TransactionalAccessDelegate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transactional entity region access for Infinispan.
|
||||||
|
*
|
||||||
|
* @author Chris Bredesen
|
||||||
|
* @author Galder Zamarreño
|
||||||
|
* @since 3.5
|
||||||
|
*/
|
||||||
|
class TransactionalAccess implements EntityRegionAccessStrategy {
|
||||||
|
|
||||||
|
private final EntityRegionImpl region;
|
||||||
|
|
||||||
|
private final TransactionalAccessDelegate delegate;
|
||||||
|
|
||||||
|
TransactionalAccess(EntityRegionImpl region) {
|
||||||
|
this.region = region;
|
||||||
|
this.delegate = new TransactionalAccessDelegate(region.getCache());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void evict(Object key) throws CacheException {
|
||||||
|
delegate.remove(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void evictAll() throws CacheException {
|
||||||
|
delegate.evictAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object get(Object key, long txTimestamp) throws CacheException {
|
||||||
|
return delegate.get(key, txTimestamp);
|
||||||
|
}
|
||||||
|
|
||||||
|
public EntityRegion getRegion() {
|
||||||
|
return this.region;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean insert(Object key, Object value, Object version) throws CacheException {
|
||||||
|
region.getCache().put(key, value);
|
||||||
|
return true; // TODO this is suspect
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean putFromLoad(Object key, Object value, long txTimestamp, Object version) throws CacheException {
|
||||||
|
return delegate.putFromLoad(key, value, txTimestamp, version);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean putFromLoad(Object key, Object value, long txTimestamp, Object version, boolean minimalPutOverride) throws CacheException {
|
||||||
|
return delegate.putFromLoad(key, value, txTimestamp, version, minimalPutOverride);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void remove(Object key) throws CacheException {
|
||||||
|
delegate.remove(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeAll() throws CacheException {
|
||||||
|
delegate.removeAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean update(Object key, Object value, Object currentVersion, Object previousVersion) throws CacheException {
|
||||||
|
return delegate.update(key, value, currentVersion, previousVersion);
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
38
cache-infinispan/src/main/java/org/hibernate/cache/infinispan/impl/BaseGeneralDataRegion.java
vendored
Normal file
38
cache-infinispan/src/main/java/org/hibernate/cache/infinispan/impl/BaseGeneralDataRegion.java
vendored
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
package org.hibernate.cache.infinispan.impl;
|
||||||
|
|
||||||
|
import javax.transaction.TransactionManager;
|
||||||
|
|
||||||
|
import org.hibernate.cache.CacheException;
|
||||||
|
import org.hibernate.cache.GeneralDataRegion;
|
||||||
|
import org.infinispan.Cache;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Support for Infinispan {@link GeneralDataRegion} implementors.
|
||||||
|
*
|
||||||
|
* @author Chris Bredesen
|
||||||
|
* @author Galder Zamarreño
|
||||||
|
* @since 3.5
|
||||||
|
*/
|
||||||
|
public abstract class BaseGeneralDataRegion extends BaseRegion implements GeneralDataRegion {
|
||||||
|
|
||||||
|
public BaseGeneralDataRegion(Cache<Object, Object> cache, String name, TransactionManager transactionManager) {
|
||||||
|
super(cache, name, transactionManager);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void evict(Object key) throws CacheException {
|
||||||
|
getCache().evict(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void evictAll() throws CacheException {
|
||||||
|
getCache().clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object get(Object key) throws CacheException {
|
||||||
|
return getCache().get(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void put(Object key, Object value) throws CacheException {
|
||||||
|
getCache().put(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
182
cache-infinispan/src/main/java/org/hibernate/cache/infinispan/impl/BaseRegion.java
vendored
Normal file
182
cache-infinispan/src/main/java/org/hibernate/cache/infinispan/impl/BaseRegion.java
vendored
Normal file
|
@ -0,0 +1,182 @@
|
||||||
|
package org.hibernate.cache.infinispan.impl;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import javax.transaction.SystemException;
|
||||||
|
import javax.transaction.Transaction;
|
||||||
|
import javax.transaction.TransactionManager;
|
||||||
|
|
||||||
|
import org.hibernate.cache.CacheException;
|
||||||
|
import org.hibernate.cache.Region;
|
||||||
|
import org.hibernate.cache.infinispan.util.CacheHelper;
|
||||||
|
import org.infinispan.Cache;
|
||||||
|
import org.infinispan.context.Flag;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Support for Infinispan {@link Region}s. Handles common "utility" methods for an underlying named
|
||||||
|
* Cache. In other words, this implementation doesn't actually read or write data. Subclasses are
|
||||||
|
* expected to provide core cache interaction appropriate to the semantics needed.
|
||||||
|
*
|
||||||
|
* @author Chris Bredesen
|
||||||
|
* @author Galder Zamarreño
|
||||||
|
* @since 3.5
|
||||||
|
*/
|
||||||
|
public abstract class BaseRegion implements Region {
|
||||||
|
private final Cache cache;
|
||||||
|
private final String name;
|
||||||
|
protected final TransactionManager transactionManager;
|
||||||
|
|
||||||
|
public BaseRegion(Cache cache, String name, TransactionManager transactionManager) {
|
||||||
|
this.cache = cache;
|
||||||
|
this.name = name;
|
||||||
|
this.transactionManager = transactionManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Cache getCache() {
|
||||||
|
return cache;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getElementCountInMemory() {
|
||||||
|
return cache.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Not supported.
|
||||||
|
*
|
||||||
|
* @return -1
|
||||||
|
*/
|
||||||
|
public long getElementCountOnDisk() {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Not supported.
|
||||||
|
*
|
||||||
|
* @return -1
|
||||||
|
*/
|
||||||
|
public long getSizeInMemory() {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getTimeout() {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long nextTimestamp() {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map toMap() {
|
||||||
|
return cache;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void destroy() throws CacheException {
|
||||||
|
// TODO see if we need to do this even in spite of RF.shutdown()
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean contains(Object key) {
|
||||||
|
return CacheHelper.containsKey(cache, key, Flag.ZERO_LOCK_ACQUISITION_TIMEOUT);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs a JBoss Cache <code>get(Fqn, Object)</code> after first
|
||||||
|
* {@link #suspend suspending any ongoing transaction}. Wraps any exception
|
||||||
|
* in a {@link CacheException}. Ensures any ongoing transaction is resumed.
|
||||||
|
*
|
||||||
|
* @param key The key of the item to get
|
||||||
|
* @param opt any option to add to the get invocation. May be <code>null</code>
|
||||||
|
* @param suppressTimeout should any TimeoutException be suppressed?
|
||||||
|
* @return The retrieved object
|
||||||
|
* @throws CacheException issue managing transaction or talking to cache
|
||||||
|
*/
|
||||||
|
protected Object suspendAndGet(Object key, Flag opt, boolean suppressTimeout) throws CacheException {
|
||||||
|
Transaction tx = suspend();
|
||||||
|
try {
|
||||||
|
if (suppressTimeout)
|
||||||
|
return CacheHelper.getAllowingTimeout(cache, key);
|
||||||
|
else
|
||||||
|
return CacheHelper.get(cache, key);
|
||||||
|
} finally {
|
||||||
|
resume(tx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tell the TransactionManager to suspend any ongoing transaction.
|
||||||
|
*
|
||||||
|
* @return the transaction that was suspended, or <code>null</code> if
|
||||||
|
* there wasn't one
|
||||||
|
*/
|
||||||
|
protected Transaction suspend() {
|
||||||
|
Transaction tx = null;
|
||||||
|
try {
|
||||||
|
if (transactionManager != null) {
|
||||||
|
tx = transactionManager.suspend();
|
||||||
|
}
|
||||||
|
} catch (SystemException se) {
|
||||||
|
throw new CacheException("Could not suspend transaction", se);
|
||||||
|
}
|
||||||
|
return tx;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tell the TransactionManager to resume the given transaction
|
||||||
|
*
|
||||||
|
* @param tx
|
||||||
|
* the transaction to suspend. May be <code>null</code>.
|
||||||
|
*/
|
||||||
|
protected void resume(Transaction tx) {
|
||||||
|
try {
|
||||||
|
if (tx != null)
|
||||||
|
transactionManager.resume(tx);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new CacheException("Could not resume transaction", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// /**
|
||||||
|
// * HACKY WAY TO GET THE TRANSACTION MANAGER, TODO: resolve it!
|
||||||
|
// */
|
||||||
|
// private static TransactionManager getTransactionManager(Properties properties) {
|
||||||
|
//// return cache == null ? null : extractComponent(cache, TransactionManager.class);
|
||||||
|
// return TransactionManagerLookupFactory.getTransactionManager(properties);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public static <T> T extractComponent(Cache cache, Class<T> componentType) {
|
||||||
|
// ComponentRegistry cr = extractComponentRegistry(cache);
|
||||||
|
// return cr.getComponent(componentType);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public static ComponentRegistry extractComponentRegistry(Cache cache) {
|
||||||
|
// return (ComponentRegistry) extractField(cache, "componentRegistry");
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public static Object extractField(Object target, String fieldName) {
|
||||||
|
// return extractField(target.getClass(), target, fieldName);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// public static Object extractField(Class type, Object target, String fieldName) {
|
||||||
|
// Field field;
|
||||||
|
// try {
|
||||||
|
// field = type.getDeclaredField(fieldName);
|
||||||
|
// field.setAccessible(true);
|
||||||
|
// return field.get(target);
|
||||||
|
// }
|
||||||
|
// catch (Exception e) {
|
||||||
|
// if (type.equals(Object.class)) {
|
||||||
|
// e.printStackTrace();
|
||||||
|
// return null;
|
||||||
|
// } else {
|
||||||
|
// // try with superclass!!
|
||||||
|
// return extractField(type.getSuperclass(), target, fieldName);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
package org.hibernate.cache.infinispan.impl;
|
||||||
|
|
||||||
|
import javax.transaction.TransactionManager;
|
||||||
|
|
||||||
|
import org.hibernate.cache.CacheDataDescription;
|
||||||
|
import org.hibernate.cache.TransactionalDataRegion;
|
||||||
|
import org.infinispan.Cache;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Support for Inifinispan {@link TransactionalDataRegion} implementors.
|
||||||
|
*
|
||||||
|
* @author Chris Bredesen
|
||||||
|
* @author Galder Zamarreño
|
||||||
|
* @since 3.5
|
||||||
|
*/
|
||||||
|
public abstract class BaseTransactionalDataRegion extends BaseRegion implements TransactionalDataRegion {
|
||||||
|
|
||||||
|
private final CacheDataDescription metadata;
|
||||||
|
|
||||||
|
public BaseTransactionalDataRegion(Cache<Object, Object> cache, String name, CacheDataDescription metadata, TransactionManager transactionManager) {
|
||||||
|
super(cache, name, transactionManager);
|
||||||
|
this.metadata = metadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CacheDataDescription getCacheDataDescription() {
|
||||||
|
return metadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isTransactionAware() {
|
||||||
|
return transactionManager != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
85
cache-infinispan/src/main/java/org/hibernate/cache/infinispan/query/QueryResultsRegionImpl.java
vendored
Normal file
85
cache-infinispan/src/main/java/org/hibernate/cache/infinispan/query/QueryResultsRegionImpl.java
vendored
Normal file
|
@ -0,0 +1,85 @@
|
||||||
|
package org.hibernate.cache.infinispan.query;
|
||||||
|
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
import javax.transaction.TransactionManager;
|
||||||
|
|
||||||
|
import org.hibernate.cache.CacheException;
|
||||||
|
import org.hibernate.cache.QueryResultsRegion;
|
||||||
|
import org.hibernate.cache.infinispan.impl.BaseTransactionalDataRegion;
|
||||||
|
import org.hibernate.cache.infinispan.util.CacheHelper;
|
||||||
|
import org.hibernate.util.PropertiesHelper;
|
||||||
|
import org.infinispan.Cache;
|
||||||
|
import org.infinispan.context.Flag;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Chris Bredesen
|
||||||
|
* @author Galder Zamarreño
|
||||||
|
* @since 3.5
|
||||||
|
*/
|
||||||
|
public class QueryResultsRegionImpl extends BaseTransactionalDataRegion implements QueryResultsRegion {
|
||||||
|
public static final String QUERY_CACHE_LOCAL_ONLY_PROP = "hibernate.cache.infinispan.query.localonly";
|
||||||
|
|
||||||
|
private boolean localOnly;
|
||||||
|
|
||||||
|
public QueryResultsRegionImpl(Cache<Object, Object> cache, String name, Properties properties, TransactionManager transactionManager) {
|
||||||
|
super(cache, name, null, transactionManager);
|
||||||
|
|
||||||
|
// If JBC is using INVALIDATION, we don't want to propagate changes.
|
||||||
|
// We use the Timestamps cache to manage invalidation
|
||||||
|
localOnly = CacheHelper.isClusteredInvalidation(cache);
|
||||||
|
if (!localOnly) {
|
||||||
|
// We don't want to waste effort setting an option if JBC is
|
||||||
|
// already in LOCAL mode. If JBC is REPL_(A)SYNC then check
|
||||||
|
// if they passed an config option to disable query replication
|
||||||
|
localOnly = CacheHelper.isClusteredReplication(cache)
|
||||||
|
&& PropertiesHelper.getBoolean(QUERY_CACHE_LOCAL_ONLY_PROP, properties, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void evict(Object key) throws CacheException {
|
||||||
|
if (localOnly)
|
||||||
|
CacheHelper.removeKey(getCache(), key, Flag.CACHE_MODE_LOCAL);
|
||||||
|
else
|
||||||
|
CacheHelper.removeKey(getCache(), key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void evictAll() throws CacheException {
|
||||||
|
if (localOnly)
|
||||||
|
CacheHelper.removeAll(getCache(), Flag.CACHE_MODE_LOCAL);
|
||||||
|
else
|
||||||
|
CacheHelper.removeAll(getCache());
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object get(Object key) throws CacheException {
|
||||||
|
// Don't hold the JBC node lock throughout the tx, as that
|
||||||
|
// prevents updates
|
||||||
|
// Add a zero (or low) timeout option so we don't block
|
||||||
|
// waiting for tx's that did a put to commit
|
||||||
|
return suspendAndGet(key, Flag.ZERO_LOCK_ACQUISITION_TIMEOUT, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void put(Object key, Object value) throws CacheException {
|
||||||
|
// Here we don't want to suspend the tx. If we do:
|
||||||
|
// 1) We might be caching query results that reflect uncommitted
|
||||||
|
// changes. No tx == no WL on cache node, so other threads
|
||||||
|
// can prematurely see those query results
|
||||||
|
// 2) No tx == immediate replication. More overhead, plus we
|
||||||
|
// spread issue #1 above around the cluster
|
||||||
|
|
||||||
|
// Add a zero (or quite low) timeout option so we don't block.
|
||||||
|
// Ignore any TimeoutException. Basically we forego caching the
|
||||||
|
// query result in order to avoid blocking.
|
||||||
|
// Reads are done with suspended tx, so they should not hold the
|
||||||
|
// lock for long. Not caching the query result is OK, since
|
||||||
|
// any subsequent read will just see the old result with its
|
||||||
|
// out-of-date timestamp; that result will be discarded and the
|
||||||
|
// db query performed again.
|
||||||
|
if (localOnly)
|
||||||
|
CacheHelper.putAllowingTimeout(getCache(), key, value, Flag.ZERO_LOCK_ACQUISITION_TIMEOUT, Flag.CACHE_MODE_LOCAL);
|
||||||
|
else
|
||||||
|
CacheHelper.putAllowingTimeout(getCache(), key, value, Flag.ZERO_LOCK_ACQUISITION_TIMEOUT);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,48 @@
|
||||||
|
/*
|
||||||
|
* JBoss, Home of Professional Open Source.
|
||||||
|
* Copyright 2009, Red Hat, Inc. and/or it's affiliates, and individual contributors
|
||||||
|
* as indicated by the @author tags. See the copyright.txt file in the
|
||||||
|
* distribution for a full listing of individual contributors.
|
||||||
|
*
|
||||||
|
* This is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU Lesser General Public License as
|
||||||
|
* published by the Free Software Foundation; either version 2.1 of
|
||||||
|
* the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This software is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this software; if not, write to the Free
|
||||||
|
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||||
|
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
|
||||||
|
*/
|
||||||
|
package org.hibernate.cache.infinispan.timestamp;
|
||||||
|
|
||||||
|
import org.hibernate.cache.CacheException;
|
||||||
|
import org.hibernate.cache.infinispan.TypeOverrides;
|
||||||
|
import org.infinispan.config.Configuration;
|
||||||
|
import org.infinispan.config.Configuration.CacheMode;
|
||||||
|
import org.infinispan.eviction.EvictionStrategy;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TimestampTypeOverrides.
|
||||||
|
*
|
||||||
|
* @author Galder Zamarreño
|
||||||
|
* @since 3.5
|
||||||
|
*/
|
||||||
|
public class TimestampTypeOverrides extends TypeOverrides {
|
||||||
|
@Override
|
||||||
|
public void validateInfinispanConfiguration(Configuration configuration) throws CacheException {
|
||||||
|
CacheMode cacheMode = configuration.getCacheMode();
|
||||||
|
if (cacheMode.equals(CacheMode.INVALIDATION_ASYNC) || cacheMode.equals(CacheMode.INVALIDATION_SYNC)) {
|
||||||
|
throw new CacheException("Timestamp cache cannot be configured with invalidation");
|
||||||
|
}
|
||||||
|
EvictionStrategy strategy = configuration.getEvictionStrategy();
|
||||||
|
if (!strategy.equals(EvictionStrategy.NONE)) {
|
||||||
|
throw new CacheException("Timestamp cache cannot be configured with eviction");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
121
cache-infinispan/src/main/java/org/hibernate/cache/infinispan/timestamp/TimestampsRegionImpl.java
vendored
Normal file
121
cache-infinispan/src/main/java/org/hibernate/cache/infinispan/timestamp/TimestampsRegionImpl.java
vendored
Normal file
|
@ -0,0 +1,121 @@
|
||||||
|
package org.hibernate.cache.infinispan.timestamp;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
import javax.transaction.Transaction;
|
||||||
|
import javax.transaction.TransactionManager;
|
||||||
|
|
||||||
|
import org.hibernate.cache.CacheException;
|
||||||
|
import org.hibernate.cache.TimestampsRegion;
|
||||||
|
import org.hibernate.cache.infinispan.impl.BaseGeneralDataRegion;
|
||||||
|
import org.hibernate.cache.infinispan.util.CacheHelper;
|
||||||
|
import org.infinispan.Cache;
|
||||||
|
import org.infinispan.context.Flag;
|
||||||
|
import org.infinispan.notifications.Listener;
|
||||||
|
import org.infinispan.notifications.cachelistener.annotation.CacheEntryModified;
|
||||||
|
import org.infinispan.notifications.cachelistener.annotation.CacheEntryRemoved;
|
||||||
|
import org.infinispan.notifications.cachelistener.event.CacheEntryModifiedEvent;
|
||||||
|
import org.infinispan.notifications.cachelistener.event.CacheEntryRemovedEvent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines the behavior of the timestamps cache region for Infinispan.
|
||||||
|
*
|
||||||
|
* @author Chris Bredesen
|
||||||
|
* @author Galder Zamarreño
|
||||||
|
* @since 3.5
|
||||||
|
*/
|
||||||
|
@Listener
|
||||||
|
public class TimestampsRegionImpl extends BaseGeneralDataRegion implements TimestampsRegion {
|
||||||
|
|
||||||
|
private Map localCache = new ConcurrentHashMap();
|
||||||
|
|
||||||
|
public TimestampsRegionImpl(Cache<Object, Object> cache, String name, TransactionManager transactionManager) {
|
||||||
|
super(cache, name, transactionManager);
|
||||||
|
cache.addListener(this);
|
||||||
|
populateLocalCache();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void evict(Object key) throws CacheException {
|
||||||
|
// TODO Is this a valid operation on a timestamps cache?
|
||||||
|
CacheHelper.removeKey(getCache(), key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void evictAll() throws CacheException {
|
||||||
|
// TODO Is this a valid operation on a timestamps cache?
|
||||||
|
CacheHelper.removeAll(getCache());
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object get(Object key) throws CacheException {
|
||||||
|
Object value = localCache.get(key);
|
||||||
|
if (value == null) {
|
||||||
|
value = suspendAndGet(key, null, false);
|
||||||
|
if (value != null)
|
||||||
|
localCache.put(key, value);
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void put(Object key, Object value) throws CacheException {
|
||||||
|
// Don't hold the JBC node lock throughout the tx, as that
|
||||||
|
// prevents reads and other updates
|
||||||
|
Transaction tx = suspend();
|
||||||
|
try {
|
||||||
|
// We ensure ASYNC semantics (JBCACHE-1175)
|
||||||
|
CacheHelper.put(getCache(), key, value, Flag.FORCE_ASYNCHRONOUS);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new CacheException(e);
|
||||||
|
} finally {
|
||||||
|
resume(tx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void destroy() throws CacheException {
|
||||||
|
localCache.clear();
|
||||||
|
getCache().removeListener(this);
|
||||||
|
super.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Monitors cache events and updates the local cache
|
||||||
|
*
|
||||||
|
* @param event
|
||||||
|
*/
|
||||||
|
@CacheEntryModified
|
||||||
|
public void nodeModified(CacheEntryModifiedEvent event) {
|
||||||
|
if (event.isPre()) return;
|
||||||
|
localCache.put(event.getKey(), event.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Monitors cache events and updates the local cache
|
||||||
|
*
|
||||||
|
* @param event
|
||||||
|
*/
|
||||||
|
@CacheEntryRemoved
|
||||||
|
public void nodeRemoved(CacheEntryRemovedEvent event) {
|
||||||
|
if (event.isPre()) return;
|
||||||
|
localCache.remove(event.getKey());
|
||||||
|
// Fqn fqn = event.getFqn();
|
||||||
|
// Fqn regFqn = getRegionFqn();
|
||||||
|
// if (fqn.size() == regFqn.size() + 1 && fqn.isChildOf(regFqn)) {
|
||||||
|
// Object key = fqn.get(regFqn.size());
|
||||||
|
// localCache.remove(key);
|
||||||
|
// } else if (fqn.equals(regFqn)) {
|
||||||
|
// localCache.clear();
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Brings all data from the distributed cache into our local cache.
|
||||||
|
*/
|
||||||
|
private void populateLocalCache() {
|
||||||
|
Set children = CacheHelper.getKeySet(getCache());
|
||||||
|
for (Object key : children)
|
||||||
|
get(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,54 @@
|
||||||
|
/*
|
||||||
|
* JBoss, Home of Professional Open Source.
|
||||||
|
* Copyright 2009, Red Hat, Inc. and/or it's affiliates, and individual contributors
|
||||||
|
* as indicated by the @author tags. See the copyright.txt file in the
|
||||||
|
* distribution for a full listing of individual contributors.
|
||||||
|
*
|
||||||
|
* This is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU Lesser General Public License as
|
||||||
|
* published by the Free Software Foundation; either version 2.1 of
|
||||||
|
* the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This software is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this software; if not, write to the Free
|
||||||
|
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||||
|
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
|
||||||
|
*/
|
||||||
|
package org.hibernate.cache.infinispan.tm;
|
||||||
|
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
import javax.transaction.TransactionManager;
|
||||||
|
|
||||||
|
import org.hibernate.cfg.Settings;
|
||||||
|
import org.hibernate.transaction.TransactionManagerLookup;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* HibernateTransactionManagerLookup.
|
||||||
|
*
|
||||||
|
* @author Galder Zamarreño
|
||||||
|
* @since 3.5
|
||||||
|
*/
|
||||||
|
public class HibernateTransactionManagerLookup implements org.infinispan.transaction.lookup.TransactionManagerLookup {
|
||||||
|
private final TransactionManagerLookup hibernateLookup;
|
||||||
|
|
||||||
|
private final Properties properties;
|
||||||
|
|
||||||
|
public HibernateTransactionManagerLookup(Settings settings, Properties properties) {
|
||||||
|
if (settings != null)
|
||||||
|
this.hibernateLookup = settings.getTransactionManagerLookup();
|
||||||
|
else
|
||||||
|
this.hibernateLookup = null;
|
||||||
|
this.properties = properties;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TransactionManager getTransactionManager() throws Exception {
|
||||||
|
return hibernateLookup == null ? null : hibernateLookup.getTransactionManager(properties);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
447
cache-infinispan/src/main/java/org/hibernate/cache/infinispan/util/CacheHelper.java
vendored
Normal file
447
cache-infinispan/src/main/java/org/hibernate/cache/infinispan/util/CacheHelper.java
vendored
Normal file
|
@ -0,0 +1,447 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2007, Red Hat, Inc. and/or it's affiliates or third-party contributors as
|
||||||
|
* indicated by the @author tags or express copyright attribution
|
||||||
|
* statements applied by the authors. All third-party contributions are
|
||||||
|
* distributed under license by Red Hat, Inc. and/or it's affiliates.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||||
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
* Lesser General Public License, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this distribution; if not, write to:
|
||||||
|
* Free Software Foundation, Inc.
|
||||||
|
* 51 Franklin Street, Fifth Floor
|
||||||
|
* Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
package org.hibernate.cache.infinispan.util;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.hibernate.cache.CacheException;
|
||||||
|
import org.infinispan.Cache;
|
||||||
|
import org.infinispan.config.Configuration;
|
||||||
|
import org.infinispan.context.Flag;
|
||||||
|
import org.infinispan.util.concurrent.TimeoutException;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper for dealing with Infinisan cache instances.
|
||||||
|
*
|
||||||
|
* @author Steve Ebersole
|
||||||
|
* @author Brian Stansberry
|
||||||
|
* @author Galder Zamarreño
|
||||||
|
* @since 3.5
|
||||||
|
*/
|
||||||
|
public class CacheHelper {
|
||||||
|
|
||||||
|
/** Key under which items are cached */
|
||||||
|
public static final String ITEM = "item";
|
||||||
|
/** Key and value used in a hack to create region root nodes */
|
||||||
|
public static final String DUMMY = "dummy";
|
||||||
|
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(CacheHelper.class);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disallow external instantiation of CacheHelper.
|
||||||
|
*/
|
||||||
|
private CacheHelper() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is this cache participating in a cluster with invalidation?
|
||||||
|
*
|
||||||
|
* @param cache
|
||||||
|
* The cache to check.
|
||||||
|
* @return True if the cache is configured for synchronous/asynchronous invalidation; false
|
||||||
|
* otherwise.
|
||||||
|
*/
|
||||||
|
public static boolean isClusteredInvalidation(Cache cache) {
|
||||||
|
return isClusteredInvalidation(cache.getConfiguration().getCacheMode());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Does this cache mode indicate clustered invalidation?
|
||||||
|
*
|
||||||
|
* @param cacheMode
|
||||||
|
* The cache to check
|
||||||
|
* @return True if the cache mode is confiogured for synchronous/asynchronous invalidation; false
|
||||||
|
* otherwise.
|
||||||
|
*/
|
||||||
|
public static boolean isClusteredInvalidation(Configuration.CacheMode cacheMode) {
|
||||||
|
return cacheMode == Configuration.CacheMode.INVALIDATION_ASYNC
|
||||||
|
|| cacheMode == Configuration.CacheMode.INVALIDATION_SYNC;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is this cache participating in a cluster with replication?
|
||||||
|
*
|
||||||
|
* @param cache
|
||||||
|
* The cache to check.
|
||||||
|
* @return True if the cache is configured for synchronous/asynchronous invalidation; false
|
||||||
|
* otherwise.
|
||||||
|
*/
|
||||||
|
public static boolean isClusteredReplication(Cache cache) {
|
||||||
|
return isClusteredReplication(cache.getConfiguration().getCacheMode());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Does this cache mode indicate clustered replication?
|
||||||
|
*
|
||||||
|
* @param cacheMode
|
||||||
|
* The cache to check
|
||||||
|
* @return True if the cache mode is confiogured for synchronous/asynchronous invalidation; false
|
||||||
|
* otherwise.
|
||||||
|
*/
|
||||||
|
public static boolean isClusteredReplication(Configuration.CacheMode cacheMode) {
|
||||||
|
return cacheMode == Configuration.CacheMode.REPL_ASYNC || cacheMode == Configuration.CacheMode.REPL_SYNC;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isSynchronous(Cache cache) {
|
||||||
|
return isSynchronous(cache.getConfiguration().getCacheMode());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isSynchronous(Configuration.CacheMode cacheMode) {
|
||||||
|
return cacheMode == Configuration.CacheMode.REPL_SYNC || cacheMode == Configuration.CacheMode.INVALIDATION_SYNC;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Set getKeySet(Cache cache) {
|
||||||
|
return cache.keySet();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds an {@link Fqn} from <code>region</code> and <code>key</code> and performs a JBoss Cache
|
||||||
|
* <code>get(Fqn, Object)</code>, wrapping any exception in a {@link CacheException}.
|
||||||
|
*
|
||||||
|
* @param cache
|
||||||
|
* the cache to invoke on
|
||||||
|
* @param region
|
||||||
|
* base Fqn for the cache region
|
||||||
|
* @param key
|
||||||
|
* specific key to append to the <code>region</code> to form the full Fqn
|
||||||
|
*/
|
||||||
|
public static Object get(Cache cache, Object key) throws CacheException {
|
||||||
|
try {
|
||||||
|
return cache.get(key);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new CacheException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds an {@link Fqn} from <code>region</code> and <code>key</code> and performs a JBoss Cache
|
||||||
|
* <code>get(Fqn, Object)</code>, wrapping any exception in a {@link CacheException}.
|
||||||
|
*
|
||||||
|
* @param cache
|
||||||
|
* the cache to invoke on
|
||||||
|
* @param key
|
||||||
|
* specific key to append to the <code>region</code> to form the full Fqn
|
||||||
|
*/
|
||||||
|
public static Object getAllowingTimeout(Cache cache, Object key) throws CacheException {
|
||||||
|
try {
|
||||||
|
return cache.get(key);
|
||||||
|
} catch (TimeoutException ignored) {
|
||||||
|
// ignore it
|
||||||
|
return null;
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new CacheException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds an {@link Fqn} from <code>region</code> and <code>key</code> and performs a JBoss Cache
|
||||||
|
* <code>put(Object, Object)</code>, wrapping any exception in a {@link CacheException}.
|
||||||
|
*
|
||||||
|
* @param cache
|
||||||
|
* the cache to invoke on
|
||||||
|
* @param region
|
||||||
|
* base Fqn for the cache region
|
||||||
|
* @param key
|
||||||
|
* specific key to append to the <code>region</code> to form the full Fqn
|
||||||
|
* @param value
|
||||||
|
* data to store in the cache node
|
||||||
|
*/
|
||||||
|
public static void put(Cache cache, Object key, Object value) throws CacheException {
|
||||||
|
put(cache, key, value, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds an {@link Fqn} from <code>region</code> and <code>key</code> and performs a JBoss Cache
|
||||||
|
* <code>put(Object, Object)</code>, wrapping any exception in a {@link CacheException}.
|
||||||
|
*
|
||||||
|
* @param cache
|
||||||
|
* the cache to invoke on
|
||||||
|
* @param region
|
||||||
|
* base Fqn for the cache region
|
||||||
|
* @param key
|
||||||
|
* specific key to append to the <code>region</code> to form the full Fqn
|
||||||
|
* @param value
|
||||||
|
* data to store in the cache node
|
||||||
|
* @param option
|
||||||
|
* invocation Option to set for this invocation. May be <code>null</code>.
|
||||||
|
*/
|
||||||
|
public static void put(Cache cache, Object key, Object value, Flag option) throws CacheException {
|
||||||
|
try {
|
||||||
|
cache.getAdvancedCache().put(key, value, option);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new CacheException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds an {@link Fqn} from <code>region</code> and <code>key</code> and performs a JBoss Cache
|
||||||
|
* <code>put(Object, Object)</code>, ignoring any {@link TimeoutException} and wrapping any other
|
||||||
|
* exception in a {@link CacheException}.
|
||||||
|
*
|
||||||
|
* @param cache
|
||||||
|
* the cache to invoke on
|
||||||
|
* @param region
|
||||||
|
* base Fqn for the cache region
|
||||||
|
* @param key
|
||||||
|
* specific key to append to the <code>region</code> to form the full Fqn
|
||||||
|
* @param value
|
||||||
|
* data to store in the cache node
|
||||||
|
* @param option
|
||||||
|
* invocation Option to set for this invocation. May be <code>null</code>.
|
||||||
|
*/
|
||||||
|
public static void putAllowingTimeout(Cache cache, Object key, Object value, Flag... option) throws CacheException {
|
||||||
|
try {
|
||||||
|
cache.getAdvancedCache().put(key, value, option);
|
||||||
|
} catch (TimeoutException allowed) {
|
||||||
|
// ignore it
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new CacheException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds an {@link Fqn} from <code>region</code> and <code>key</code> and performs a JBoss Cache
|
||||||
|
* <code>putForExternalRead(Object, Object)</code>, wrapping any exception in a
|
||||||
|
* {@link CacheException}. Ignores any JBoss Cache {@link TimeoutException}.
|
||||||
|
*
|
||||||
|
* @param cache
|
||||||
|
* the cache to invoke on
|
||||||
|
* @param region
|
||||||
|
* base Fqn for the cache region
|
||||||
|
* @param key
|
||||||
|
* specific key to append to the <code>region</code> to form the full Fqn
|
||||||
|
* @param value
|
||||||
|
* data to store in the cache node
|
||||||
|
*/
|
||||||
|
public static boolean putForExternalRead(Cache cache, Object key, Object value) throws CacheException {
|
||||||
|
return putForExternalRead(cache, key, value, (Flag[])null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds an {@link Fqn} from <code>region</code> and <code>key</code> and performs a JBoss Cache
|
||||||
|
* <code>putForExternalRead(Object, Object)</code>, wrapping any exception in a
|
||||||
|
* {@link CacheException}. Ignores any JBoss Cache {@link TimeoutException}.
|
||||||
|
*
|
||||||
|
* @param cache
|
||||||
|
* the cache to invoke on
|
||||||
|
* @param region
|
||||||
|
* base Fqn for the cache region
|
||||||
|
* @param key
|
||||||
|
* specific key to append to the <code>region</code> to form the full Fqn
|
||||||
|
* @param value
|
||||||
|
* data to store in the cache node
|
||||||
|
* @param option
|
||||||
|
* invocation Option to set for this invocation. May be <code>null</code>.
|
||||||
|
*/
|
||||||
|
public static boolean putForExternalRead(Cache cache, Object key, Object value, Flag... option) throws CacheException {
|
||||||
|
try {
|
||||||
|
cache.getAdvancedCache().putForExternalRead(key, value, option);
|
||||||
|
return true;
|
||||||
|
} catch (TimeoutException te) {
|
||||||
|
// ignore!
|
||||||
|
log.debug("ignoring write lock acquisition failure");
|
||||||
|
return false;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
throw new CacheException(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds an {@link Fqn} from <code>region</code> and <code>key</code> and performs a JBoss Cache
|
||||||
|
* <code>removeNode(Fqn)</code>, wrapping any exception in a {@link CacheException}.
|
||||||
|
*
|
||||||
|
* @param cache
|
||||||
|
* the cache to invoke on
|
||||||
|
* @param region
|
||||||
|
* base Fqn for the cache region
|
||||||
|
* @param key
|
||||||
|
* specific key to append to the <code>region</code> to form the full Fqn
|
||||||
|
*/
|
||||||
|
public static void remove(Cache cache, Object key) throws CacheException {
|
||||||
|
remove(cache, key, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds an {@link Fqn} from <code>region</code> and <code>key</code> and performs a JBoss Cache
|
||||||
|
* <code>removeNode(Fqn)</code>, wrapping any exception in a {@link CacheException}.
|
||||||
|
*
|
||||||
|
* @param cache
|
||||||
|
* the cache to invoke on
|
||||||
|
* @param region
|
||||||
|
* base Fqn for the cache region
|
||||||
|
* @param key
|
||||||
|
* specific key to append to the <code>region</code> to form the full Fqn
|
||||||
|
* @param option
|
||||||
|
* invocation Option to set for this invocation. May be <code>null</code>.
|
||||||
|
*/
|
||||||
|
public static void remove(Cache cache, Object key, Flag option) throws CacheException {
|
||||||
|
try {
|
||||||
|
cache.getAdvancedCache().remove(key, option);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new CacheException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs a JBoss Cache <code>removeNode(Fqn)</code>, wrapping any exception in a
|
||||||
|
* {@link CacheException}.
|
||||||
|
*
|
||||||
|
* @param cache
|
||||||
|
* the cache to invoke on
|
||||||
|
* @param region
|
||||||
|
* base Fqn for the cache region
|
||||||
|
*/
|
||||||
|
public static void removeAll(Cache cache) throws CacheException {
|
||||||
|
try {
|
||||||
|
cache.clear();
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new CacheException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs a JBoss Cache <code>removeNode(Fqn)</code>, wrapping any exception in a
|
||||||
|
* {@link CacheException}.
|
||||||
|
*
|
||||||
|
* @param cache
|
||||||
|
* the cache to invoke on
|
||||||
|
* @param region
|
||||||
|
* base Fqn for the cache region
|
||||||
|
* @param option
|
||||||
|
* invocation Option to set for this invocation. May be <code>null</code>.
|
||||||
|
*/
|
||||||
|
public static void removeAll(Cache cache, Flag option) throws CacheException {
|
||||||
|
try {
|
||||||
|
cache.getAdvancedCache().clear(option);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new CacheException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs a JBoss Cache <code>removeNode(Fqn)</code>, wrapping any exception in a
|
||||||
|
* {@link CacheException}.
|
||||||
|
*
|
||||||
|
* @param cache
|
||||||
|
* the cache to invoke on
|
||||||
|
* @param region
|
||||||
|
* base Fqn for the cache region
|
||||||
|
* @param option
|
||||||
|
* invocation Option to set for this invocation. May be <code>null</code>.
|
||||||
|
*/
|
||||||
|
public static void removeKey(Cache cache, Object key, Flag option) throws CacheException {
|
||||||
|
try {
|
||||||
|
cache.getAdvancedCache().remove(key, option);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new CacheException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void removeKey(Cache cache, Object key) throws CacheException {
|
||||||
|
try {
|
||||||
|
cache.remove(key);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new CacheException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// public static void evict(Cache cache, Object key) throws CacheException {
|
||||||
|
// try {
|
||||||
|
// cache.evict(key);
|
||||||
|
// } catch (Exception e) {
|
||||||
|
// throw new CacheException(e);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
public static boolean containsKey(Cache cache, Object key, Flag... flags) {
|
||||||
|
try {
|
||||||
|
return cache.getAdvancedCache().containsKey(key, flags);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new CacheException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// public static Node addNode(Cache cache, Fqn fqn, boolean localOnly, boolean resident) throws CacheException {
|
||||||
|
// try {
|
||||||
|
// Option option = null;
|
||||||
|
// if (localOnly) {
|
||||||
|
// option = new Option();
|
||||||
|
// option.setCacheModeLocal(localOnly);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// Node root = cache.getRoot();
|
||||||
|
// setInvocationOption(cache, option);
|
||||||
|
// // FIXME hack to work around fact that calling
|
||||||
|
// // Node added = root.addChild( fqn ); doesn't
|
||||||
|
// // properly set the version on the node
|
||||||
|
// Node added = null;
|
||||||
|
// if (version == null) {
|
||||||
|
// added = root.addChild(fqn);
|
||||||
|
// } else {
|
||||||
|
// cache.put(fqn, DUMMY, DUMMY);
|
||||||
|
// added = root.getChild(fqn);
|
||||||
|
// }
|
||||||
|
// if (resident)
|
||||||
|
// added.setResident(true);
|
||||||
|
// return added;
|
||||||
|
// } catch (Exception e) {
|
||||||
|
// throw new CacheException(e);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
/**
|
||||||
|
// * Assigns the given Option to the cache's {@link InvocationContext}. Does nothing if
|
||||||
|
// * <code>option</code> is <code>null</code>.
|
||||||
|
// *
|
||||||
|
// * @param cache
|
||||||
|
// * the cache. Cannot be <code>null</code>.
|
||||||
|
// * @param option
|
||||||
|
// * the option. May be <code>null</code>.
|
||||||
|
// *
|
||||||
|
// * @see {@link Cache#getInvocationContext()}
|
||||||
|
// * @see {@link InvocationContext#setOptionOverrides(Option)}
|
||||||
|
// */
|
||||||
|
// public static void setInvocationOption(Cache cache, Option option) {
|
||||||
|
// if (option != null) {
|
||||||
|
// cache.getInvocationContext().setOptionOverrides(option);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// /**
|
||||||
|
// * Creates an {@link Option} using the given {@link DataVersion} and passes it to
|
||||||
|
// * {@link #setInvocationOption(Cache, Option)}.
|
||||||
|
// *
|
||||||
|
// * @param cache
|
||||||
|
// * the cache to set the Option on. Cannot be <code>null</code>.
|
||||||
|
// * @param version
|
||||||
|
// * the DataVersion to set. Cannot be <code>null</code>.
|
||||||
|
// */
|
||||||
|
// public static void setDataVersionOption(Cache cache, DataVersion version) {
|
||||||
|
// Option option = new Option();
|
||||||
|
// option.setDataVersion(version);
|
||||||
|
// setInvocationOption(cache, option);
|
||||||
|
// }
|
||||||
|
}
|
|
@ -0,0 +1,77 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<infinispan xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="urn:infinispan:config:4.0">
|
||||||
|
<global>
|
||||||
|
<transport transportClass = "org.infinispan.remoting.transport.jgroups.JGroupsTransport"
|
||||||
|
clusterName="infinispan-hibernate-cluster" distributedSyncTimeout="50000">
|
||||||
|
<!-- Note that the JGroups transport uses sensible defaults if no configuration property is defined. -->
|
||||||
|
<properties>
|
||||||
|
<!-- TODO: Change to udp.xml once streaming transfer requirement has been removed. -->
|
||||||
|
<property name="configurationFile" value="flush-udp.xml"/>
|
||||||
|
</properties>
|
||||||
|
<!-- See the JGroupsTransport javadocs for more flags -->
|
||||||
|
</transport>
|
||||||
|
<serialization marshallerClass="org.infinispan.marshall.VersionAwareMarshaller" version="4.0"/>
|
||||||
|
</global>
|
||||||
|
|
||||||
|
<default>
|
||||||
|
<!-- Used to register JMX statistics in any available MBean server -->
|
||||||
|
<jmxStatistics enabled="false"/>
|
||||||
|
</default>
|
||||||
|
|
||||||
|
<!-- Default configuration is appropriate for entity/collection caching. -->
|
||||||
|
<namedCache name="entity">
|
||||||
|
<clustering mode="invalidation">
|
||||||
|
<stateRetrieval fetchInMemoryState="false" timeout="20000"/>
|
||||||
|
<sync replTimeout="20000"/>
|
||||||
|
</clustering>
|
||||||
|
<!-- Note: REPEATABLE_READ is only useful if the application evicts/clears entities
|
||||||
|
from the Hibernate Session and then expects to repeatably re-read them in
|
||||||
|
the same transaction. Otherwise, the Session's internal cache provides a
|
||||||
|
repeatable-read semantic. Before choosing this config, carefully read the docs
|
||||||
|
and make sure you really need REPEATABLE_READ.
|
||||||
|
-->
|
||||||
|
<locking isolationLevel="READ_COMMITTED" concurrencyLevel="1000" lockAcquisitionTimeout="15000"/>
|
||||||
|
<!-- Eviction configuration. WakeupInterval defines how often the eviction thread runs, in milliseconds.
|
||||||
|
0 means the eviction thread will never run. A separate executor is used for eviction in each cache. -->
|
||||||
|
<eviction wakeUpInterval="5000" maxEntries="10000" strategy="LRU"/>
|
||||||
|
<expiration maxIdle="100000"/>
|
||||||
|
<lazyDeserialization enabled="true"/>
|
||||||
|
</namedCache>
|
||||||
|
|
||||||
|
<!-- A config appropriate for query caching. Does not replicate queries. -->
|
||||||
|
<namedCache name="local-query">
|
||||||
|
<locking isolationLevel="READ_COMMITTED" concurrencyLevel="1000" lockAcquisitionTimeout="15000"/>
|
||||||
|
<!--Eviction configuration. WakeupInterval defines how often the eviction thread runs, in milliseconds. 0 means
|
||||||
|
the eviction thread will never run. A separate executor is used for eviction in each cache. -->
|
||||||
|
<eviction wakeUpInterval="5000" maxEntries="10000" strategy="LRU"/>
|
||||||
|
<expiration maxIdle="100000"/>
|
||||||
|
</namedCache>
|
||||||
|
|
||||||
|
<!-- A query cache that replicates queries. Replication is asynchronous. -->
|
||||||
|
<namedCache name="replicated-query">
|
||||||
|
<clustering mode="replication">
|
||||||
|
<stateRetrieval fetchInMemoryState="false"/>
|
||||||
|
<async/>
|
||||||
|
</clustering>
|
||||||
|
<locking isolationLevel="READ_COMMITTED" concurrencyLevel="1000" lockAcquisitionTimeout="15000"/>
|
||||||
|
<!--Eviction configuration. WakeupInterval defines how often the eviction thread runs, in milliseconds. 0 means
|
||||||
|
the eviction thread will never run. A separate executor is used for eviction in each cache. -->
|
||||||
|
<eviction wakeUpInterval="5000" maxEntries="10000" strategy="LRU"/>
|
||||||
|
<expiration maxIdle="100000"/>
|
||||||
|
</namedCache>
|
||||||
|
|
||||||
|
<!-- Optimized for timestamp caching. A clustered timestamp cache
|
||||||
|
is required if query caching is used, even if the query cache
|
||||||
|
itself is configured with CacheMode=LOCAL. -->
|
||||||
|
<namedCache name="timestamps">
|
||||||
|
<clustering mode="replication">
|
||||||
|
<stateRetrieval fetchInMemoryState="true" timeout="20000"/>
|
||||||
|
<async/>
|
||||||
|
</clustering>
|
||||||
|
<locking isolationLevel="READ_COMMITTED" concurrencyLevel="1000" lockAcquisitionTimeout="15000"/>
|
||||||
|
<lazyDeserialization enabled="true"/>
|
||||||
|
<!-- Don't ever evict modification timestamps -->
|
||||||
|
<eviction wakeUpInterval="0" strategy="NONE"/>
|
||||||
|
</namedCache>
|
||||||
|
|
||||||
|
</infinispan>
|
|
@ -0,0 +1,128 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2007, Red Hat, Inc. and/or it's affiliates or third-party contributors as
|
||||||
|
* indicated by the @author tags or express copyright attribution
|
||||||
|
* statements applied by the authors. All third-party contributions are
|
||||||
|
* distributed under license by Red Hat, Inc. and/or it's affiliates.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||||
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
* Lesser General Public License, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this distribution; if not, write to:
|
||||||
|
* Free Software Foundation, Inc.
|
||||||
|
* 51 Franklin Street, Fifth Floor
|
||||||
|
* Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
package org.hibernate.test.cache.infinispan;
|
||||||
|
|
||||||
|
import java.util.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.infinispan.InfinispanRegionFactory;
|
||||||
|
import org.hibernate.cfg.Configuration;
|
||||||
|
import org.hibernate.cfg.Environment;
|
||||||
|
import org.hibernate.test.cache.infinispan.util.CacheTestUtil;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base class for tests of EntityRegion and CollectionRegion implementations.
|
||||||
|
*
|
||||||
|
* @author Galder Zamarreño
|
||||||
|
* @since 3.5
|
||||||
|
*/
|
||||||
|
public abstract class AbstractEntityCollectionRegionTestCase extends AbstractRegionImplTestCase {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new EntityCollectionRegionTestCaseBase.
|
||||||
|
*
|
||||||
|
* @param name
|
||||||
|
*/
|
||||||
|
public AbstractEntityCollectionRegionTestCase(String name) {
|
||||||
|
super(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 testSupportedAccessTypes() throws Exception {
|
||||||
|
supportedAccessTypeTest();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void supportedAccessTypeTest() throws Exception {
|
||||||
|
Configuration cfg = CacheTestUtil.buildConfiguration("test", InfinispanRegionFactory.class, true, false);
|
||||||
|
String entityCfg = "entity";
|
||||||
|
cfg.setProperty(InfinispanRegionFactory.ENTITY_CACHE_RESOURCE_PROP, entityCfg);
|
||||||
|
InfinispanRegionFactory 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", InfinispanRegionFactory.class, true, false);
|
||||||
|
// cfg.setProperty(SharedCacheInstanceManager.CACHE_RESOURCE_PROP, CacheTestUtil.LOCAL_PESSIMISTIC_CACHE);
|
||||||
|
|
||||||
|
InfinispanRegionFactory 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", InfinispanRegionFactory.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", InfinispanRegionFactory.class, true, false);
|
||||||
|
// cfg.setProperty(SharedCacheInstanceManager.CACHE_RESOURCE_PROP, CacheTestUtil.LOCAL_PESSIMISTIC_CACHE);
|
||||||
|
|
||||||
|
InfinispanRegionFactory 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());
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,195 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2007, Red Hat, Inc. and/or it's affiliates or third-party contributors as
|
||||||
|
* indicated by the @author tags or express copyright attribution
|
||||||
|
* statements applied by the authors. All third-party contributions are
|
||||||
|
* distributed under license by Red Hat, Inc. and/or it's affiliates.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||||
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
* Lesser General Public License, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this distribution; if not, write to:
|
||||||
|
* Free Software Foundation, Inc.
|
||||||
|
* 51 Franklin Street, Fifth Floor
|
||||||
|
* Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
package org.hibernate.test.cache.infinispan;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.hibernate.cache.GeneralDataRegion;
|
||||||
|
import org.hibernate.cache.QueryResultsRegion;
|
||||||
|
import org.hibernate.cache.Region;
|
||||||
|
import org.hibernate.cache.infinispan.InfinispanRegionFactory;
|
||||||
|
import org.hibernate.cache.infinispan.util.CacheHelper;
|
||||||
|
import org.hibernate.cfg.Configuration;
|
||||||
|
import org.hibernate.test.cache.infinispan.util.CacheTestUtil;
|
||||||
|
import org.infinispan.Cache;
|
||||||
|
import org.infinispan.transaction.tm.BatchModeTransactionManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base class for tests of QueryResultsRegion and TimestampsRegion.
|
||||||
|
*
|
||||||
|
* @author Galder Zamarreño
|
||||||
|
* @since 3.5
|
||||||
|
*/
|
||||||
|
public abstract class AbstractGeneralDataRegionTestCase extends AbstractRegionImplTestCase {
|
||||||
|
protected static final String KEY = "Key";
|
||||||
|
|
||||||
|
protected static final String VALUE1 = "value1";
|
||||||
|
protected static final String VALUE2 = "value2";
|
||||||
|
|
||||||
|
public AbstractGeneralDataRegionTestCase(String name) {
|
||||||
|
super(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void putInRegion(Region region, Object key, Object value) {
|
||||||
|
((GeneralDataRegion) region).put(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void removeFromRegion(Region region, Object key) {
|
||||||
|
((GeneralDataRegion) region).evict(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test method for {@link QueryResultsRegion#evict(java.lang.Object)}.
|
||||||
|
*
|
||||||
|
* FIXME add testing of the "immediately without regard for transaction isolation" bit in the
|
||||||
|
* CollectionRegionAccessStrategy API.
|
||||||
|
*/
|
||||||
|
public void testEvict() throws Exception {
|
||||||
|
evictOrRemoveTest();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void evictOrRemoveTest() throws Exception {
|
||||||
|
Configuration cfg = createConfiguration();
|
||||||
|
InfinispanRegionFactory regionFactory = CacheTestUtil.startRegionFactory(cfg, getCacheTestSupport());
|
||||||
|
Cache localCache = getInfinispanCache(regionFactory);
|
||||||
|
boolean invalidation = CacheHelper.isClusteredInvalidation(localCache);
|
||||||
|
|
||||||
|
// Sleep a bit to avoid concurrent FLUSH problem
|
||||||
|
avoidConcurrentFlush();
|
||||||
|
|
||||||
|
GeneralDataRegion localRegion = (GeneralDataRegion) createRegion(regionFactory,
|
||||||
|
getStandardRegionName(REGION_PREFIX), cfg.getProperties(), null);
|
||||||
|
|
||||||
|
cfg = createConfiguration();
|
||||||
|
regionFactory = CacheTestUtil.startRegionFactory(cfg, getCacheTestSupport());
|
||||||
|
|
||||||
|
GeneralDataRegion remoteRegion = (GeneralDataRegion) createRegion(regionFactory,
|
||||||
|
getStandardRegionName(REGION_PREFIX), cfg.getProperties(), null);
|
||||||
|
|
||||||
|
assertNull("local is clean", localRegion.get(KEY));
|
||||||
|
assertNull("remote is clean", remoteRegion.get(KEY));
|
||||||
|
|
||||||
|
localRegion.put(KEY, VALUE1);
|
||||||
|
assertEquals(VALUE1, localRegion.get(KEY));
|
||||||
|
|
||||||
|
// allow async propagation
|
||||||
|
sleep(250);
|
||||||
|
Object expected = invalidation ? null : VALUE1;
|
||||||
|
assertEquals(expected, remoteRegion.get(KEY));
|
||||||
|
|
||||||
|
localRegion.evict(KEY);
|
||||||
|
|
||||||
|
// allow async propagation
|
||||||
|
sleep(250);
|
||||||
|
assertEquals(null, localRegion.get(KEY));
|
||||||
|
assertEquals(null, remoteRegion.get(KEY));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract String getStandardRegionName(String regionPrefix);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test method for {@link QueryResultsRegion#evictAll()}.
|
||||||
|
*
|
||||||
|
* FIXME add testing of the "immediately without regard for transaction isolation" bit in the
|
||||||
|
* CollectionRegionAccessStrategy API.
|
||||||
|
*/
|
||||||
|
public void testEvictAll() throws Exception {
|
||||||
|
evictOrRemoveAllTest("entity");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void evictOrRemoveAllTest(String configName) throws Exception {
|
||||||
|
Configuration cfg = createConfiguration();
|
||||||
|
InfinispanRegionFactory regionFactory = CacheTestUtil.startRegionFactory(cfg, getCacheTestSupport());
|
||||||
|
Cache localCache = getInfinispanCache(regionFactory);
|
||||||
|
// boolean invalidation = CacheHelper.isClusteredInvalidation(localCache);
|
||||||
|
|
||||||
|
// Sleep a bit to avoid concurrent FLUSH problem
|
||||||
|
avoidConcurrentFlush();
|
||||||
|
|
||||||
|
GeneralDataRegion localRegion = (GeneralDataRegion) createRegion(regionFactory,
|
||||||
|
getStandardRegionName(REGION_PREFIX), cfg.getProperties(), null);
|
||||||
|
|
||||||
|
cfg = createConfiguration();
|
||||||
|
regionFactory = CacheTestUtil.startRegionFactory(cfg, getCacheTestSupport());
|
||||||
|
Cache remoteCache = getInfinispanCache(regionFactory);
|
||||||
|
|
||||||
|
// Sleep a bit to avoid concurrent FLUSH problem
|
||||||
|
avoidConcurrentFlush();
|
||||||
|
|
||||||
|
GeneralDataRegion remoteRegion = (GeneralDataRegion) createRegion(regionFactory,
|
||||||
|
getStandardRegionName(REGION_PREFIX), cfg.getProperties(), null);
|
||||||
|
// String regionName = REGION_PREFIX;
|
||||||
|
|
||||||
|
Set children = CacheHelper.getKeySet(localCache);
|
||||||
|
assertEquals("No children in " + children, 0, children.size());
|
||||||
|
|
||||||
|
children = CacheHelper.getKeySet(remoteCache);
|
||||||
|
assertEquals("No children in " + children, 0, children.size());
|
||||||
|
|
||||||
|
assertNull("local is clean", localRegion.get(KEY));
|
||||||
|
assertNull("remote is clean", remoteRegion.get(KEY));
|
||||||
|
|
||||||
|
localRegion.put(KEY, VALUE1);
|
||||||
|
assertEquals(VALUE1, localRegion.get(KEY));
|
||||||
|
|
||||||
|
// Allow async propagation
|
||||||
|
sleep(250);
|
||||||
|
|
||||||
|
remoteRegion.put(KEY, VALUE1);
|
||||||
|
assertEquals(VALUE1, remoteRegion.get(KEY));
|
||||||
|
|
||||||
|
// Allow async propagation
|
||||||
|
sleep(250);
|
||||||
|
|
||||||
|
localRegion.evictAll();
|
||||||
|
|
||||||
|
// allow async propagation
|
||||||
|
sleep(250);
|
||||||
|
// This should re-establish the region root node in the optimistic case
|
||||||
|
assertNull(localRegion.get(KEY));
|
||||||
|
|
||||||
|
// Re-establishing the region root on the local node doesn't
|
||||||
|
// propagate it to other nodes. Do a get on the remote node to re-establish
|
||||||
|
// This only adds a node in the case of optimistic locking
|
||||||
|
assertEquals(null, remoteRegion.get(KEY));
|
||||||
|
|
||||||
|
assertEquals("local is clean", null, localRegion.get(KEY));
|
||||||
|
assertEquals("remote is clean", null, remoteRegion.get(KEY));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Configuration createConfiguration() {
|
||||||
|
Configuration cfg = CacheTestUtil.buildConfiguration("test", InfinispanRegionFactory.class, false, true);
|
||||||
|
return cfg;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void rollback() {
|
||||||
|
try {
|
||||||
|
BatchModeTransactionManager.getInstance().rollback();
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error(e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,97 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2007, Red Hat, Inc. and/or it's affiliates or third-party contributors as
|
||||||
|
* indicated by the @author tags or express copyright attribution
|
||||||
|
* statements applied by the authors. All third-party contributions are
|
||||||
|
* distributed under license by Red Hat, Inc. and/or it's affiliates.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||||
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
* Lesser General Public License, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this distribution; if not, write to:
|
||||||
|
* Free Software Foundation, Inc.
|
||||||
|
* 51 Franklin Street, Fifth Floor
|
||||||
|
* Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
package org.hibernate.test.cache.infinispan;
|
||||||
|
|
||||||
|
import org.hibernate.cache.RegionFactory;
|
||||||
|
import org.hibernate.junit.UnitTestCase;
|
||||||
|
import org.hibernate.test.cache.infinispan.util.CacheTestSupport;
|
||||||
|
import org.infinispan.Cache;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base class for all non-functional tests of Infinispan integration.
|
||||||
|
*
|
||||||
|
* @author Galder Zamarreño
|
||||||
|
* @since 3.5
|
||||||
|
*/
|
||||||
|
public abstract class AbstractNonFunctionalTestCase extends UnitTestCase {
|
||||||
|
|
||||||
|
public static final String REGION_PREFIX = "test";
|
||||||
|
|
||||||
|
private CacheTestSupport testSupport;
|
||||||
|
protected final Logger log = LoggerFactory.getLogger(getClass());
|
||||||
|
|
||||||
|
public AbstractNonFunctionalTestCase(String name) {
|
||||||
|
super(name);
|
||||||
|
testSupport = new CacheTestSupport(log);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void setUp() throws Exception {
|
||||||
|
super.setUp();
|
||||||
|
|
||||||
|
testSupport.setUp();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void tearDown() throws Exception {
|
||||||
|
super.tearDown();
|
||||||
|
|
||||||
|
testSupport.tearDown();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void registerCache(Cache cache) {
|
||||||
|
testSupport.registerCache(cache);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void unregisterCache(Cache cache) {
|
||||||
|
testSupport.unregisterCache(cache);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void registerFactory(RegionFactory factory) {
|
||||||
|
testSupport.registerFactory(factory);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void unregisterFactory(RegionFactory factory) {
|
||||||
|
testSupport.unregisterFactory(factory);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected CacheTestSupport getCacheTestSupport() {
|
||||||
|
return testSupport;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void sleep(long ms) {
|
||||||
|
try {
|
||||||
|
Thread.sleep(ms);
|
||||||
|
}
|
||||||
|
catch (InterruptedException e) {
|
||||||
|
log.warn("Interrupted during sleep", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void avoidConcurrentFlush() {
|
||||||
|
testSupport.avoidConcurrentFlush();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,59 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2007, Red Hat, Inc. and/or it's affiliates or third-party contributors as
|
||||||
|
* indicated by the @author tags or express copyright attribution
|
||||||
|
* statements applied by the authors. All third-party contributions are
|
||||||
|
* distributed under license by Red Hat, Inc. and/or it's affiliates.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||||
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
* Lesser General Public License, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this distribution; if not, write to:
|
||||||
|
* Free Software Foundation, Inc.
|
||||||
|
* 51 Franklin Street, Fifth Floor
|
||||||
|
* Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
package org.hibernate.test.cache.infinispan;
|
||||||
|
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
import org.hibernate.cache.CacheDataDescription;
|
||||||
|
import org.hibernate.cache.Region;
|
||||||
|
import org.hibernate.cache.impl.CacheDataDescriptionImpl;
|
||||||
|
import org.hibernate.cache.infinispan.InfinispanRegionFactory;
|
||||||
|
import org.hibernate.util.ComparableComparator;
|
||||||
|
import org.infinispan.Cache;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base class for tests of Region implementations.
|
||||||
|
*
|
||||||
|
* @author Galder Zamarreño
|
||||||
|
* @since 3.5
|
||||||
|
*/
|
||||||
|
public abstract class AbstractRegionImplTestCase extends AbstractNonFunctionalTestCase {
|
||||||
|
|
||||||
|
public AbstractRegionImplTestCase(String name) {
|
||||||
|
super(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract Cache getInfinispanCache(InfinispanRegionFactory regionFactory);
|
||||||
|
|
||||||
|
protected abstract Region createRegion(InfinispanRegionFactory regionFactory, String regionName, Properties properties, CacheDataDescription cdd);
|
||||||
|
|
||||||
|
protected abstract void putInRegion(Region region, Object key, Object value);
|
||||||
|
|
||||||
|
protected abstract void removeFromRegion(Region region, Object key);
|
||||||
|
|
||||||
|
protected CacheDataDescription getCacheDataDescription() {
|
||||||
|
return new CacheDataDescriptionImpl(true, true, ComparableComparator.INSTANCE);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,418 @@
|
||||||
|
/*
|
||||||
|
* JBoss, Home of Professional Open Source.
|
||||||
|
* Copyright 2009, Red Hat, Inc. and/or it's affiliates, and individual contributors
|
||||||
|
* as indicated by the @author tags. See the copyright.txt file in the
|
||||||
|
* distribution for a full listing of individual contributors.
|
||||||
|
*
|
||||||
|
* This is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU Lesser General Public License as
|
||||||
|
* published by the Free Software Foundation; either version 2.1 of
|
||||||
|
* the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This software is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this software; if not, write to the Free
|
||||||
|
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||||
|
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
|
||||||
|
*/
|
||||||
|
package org.hibernate.test.cache.infinispan;
|
||||||
|
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
import org.hibernate.cache.CacheException;
|
||||||
|
import org.hibernate.cache.infinispan.InfinispanRegionFactory;
|
||||||
|
import org.hibernate.cache.infinispan.collection.CollectionRegionImpl;
|
||||||
|
import org.hibernate.cache.infinispan.entity.EntityRegionImpl;
|
||||||
|
import org.hibernate.cache.infinispan.query.QueryResultsRegionImpl;
|
||||||
|
import org.hibernate.cache.infinispan.timestamp.TimestampsRegionImpl;
|
||||||
|
import org.infinispan.Cache;
|
||||||
|
import org.infinispan.config.Configuration;
|
||||||
|
import org.infinispan.config.Configuration.CacheMode;
|
||||||
|
import org.infinispan.eviction.EvictionStrategy;
|
||||||
|
import org.infinispan.manager.CacheManager;
|
||||||
|
import org.infinispan.manager.DefaultCacheManager;
|
||||||
|
|
||||||
|
import junit.framework.TestCase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* InfinispanRegionFactoryTestCase.
|
||||||
|
*
|
||||||
|
* @author Galder Zamarreño
|
||||||
|
* @since 3.5
|
||||||
|
*/
|
||||||
|
public class InfinispanRegionFactoryTestCase extends TestCase {
|
||||||
|
|
||||||
|
public void testConfigurationProcessing() {
|
||||||
|
final String person = "com.acme.Person";
|
||||||
|
final String addresses = "com.acme.Person.addresses";
|
||||||
|
Properties p = new Properties();
|
||||||
|
p.setProperty("hibernate.cache.infinispan.com.acme.Person.cfg", "person-cache");
|
||||||
|
p.setProperty("hibernate.cache.infinispan.com.acme.Person.eviction.strategy", "LRU");
|
||||||
|
p.setProperty("hibernate.cache.infinispan.com.acme.Person.eviction.wake_up_interval", "2000");
|
||||||
|
p.setProperty("hibernate.cache.infinispan.com.acme.Person.eviction.max_entries", "5000 ");
|
||||||
|
p.setProperty("hibernate.cache.infinispan.com.acme.Person.eviction.lifespan", "60000");
|
||||||
|
p.setProperty("hibernate.cache.infinispan.com.acme.Person.eviction.max_idle", "30000");
|
||||||
|
p.setProperty("hibernate.cache.infinispan.com.acme.Person.addresses.cfg", "person-addresses-cache");
|
||||||
|
p.setProperty("hibernate.cache.infinispan.com.acme.Person.addresses.eviction.lifespan", "120000");
|
||||||
|
p.setProperty("hibernate.cache.infinispan.com.acme.Person.addresses.eviction.max_idle", "60000");
|
||||||
|
p.setProperty("hibernate.cache.infinispan.query.cfg", "my-query-cache");
|
||||||
|
p.setProperty("hibernate.cache.infinispan.query.eviction.strategy", "FIFO");
|
||||||
|
p.setProperty("hibernate.cache.infinispan.query.eviction.wake_up_interval", "3000");
|
||||||
|
p.setProperty("hibernate.cache.infinispan.query.eviction.max_entries", "10000");
|
||||||
|
|
||||||
|
InfinispanRegionFactory factory = new InfinispanRegionFactory();
|
||||||
|
factory.start(null, p);
|
||||||
|
|
||||||
|
assertEquals("entity", factory.getTypeOverrides().get("entity").getCacheName());
|
||||||
|
assertEquals("entity", factory.getTypeOverrides().get("collection").getCacheName());
|
||||||
|
assertEquals("timestamps", factory.getTypeOverrides().get("timestamps").getCacheName());
|
||||||
|
|
||||||
|
assertEquals("person-cache", factory.getTypeOverrides().get(person).getCacheName());
|
||||||
|
assertEquals(EvictionStrategy.LRU, factory.getTypeOverrides().get(person).getEvictionStrategy());
|
||||||
|
assertEquals(2000, factory.getTypeOverrides().get(person).getEvictionWakeUpInterval());
|
||||||
|
assertEquals(5000, factory.getTypeOverrides().get(person).getEvictionMaxEntries());
|
||||||
|
assertEquals(60000, factory.getTypeOverrides().get(person).getExpirationLifespan());
|
||||||
|
assertEquals(30000, factory.getTypeOverrides().get(person).getExpirationMaxIdle());
|
||||||
|
|
||||||
|
assertEquals("person-addresses-cache", factory.getTypeOverrides().get(addresses).getCacheName());
|
||||||
|
assertEquals(120000, factory.getTypeOverrides().get(addresses).getExpirationLifespan());
|
||||||
|
assertEquals(60000, factory.getTypeOverrides().get(addresses).getExpirationMaxIdle());
|
||||||
|
|
||||||
|
assertEquals("my-query-cache", factory.getTypeOverrides().get("query").getCacheName());
|
||||||
|
assertEquals(EvictionStrategy.FIFO, factory.getTypeOverrides().get("query").getEvictionStrategy());
|
||||||
|
assertEquals(3000, factory.getTypeOverrides().get("query").getEvictionWakeUpInterval());
|
||||||
|
assertEquals(10000, factory.getTypeOverrides().get("query").getEvictionMaxEntries());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testBuildEntityCollectionRegionsPersonPlusEntityCollectionOverrides() {
|
||||||
|
final String person = "com.acme.Person";
|
||||||
|
final String address = "com.acme.Address";
|
||||||
|
final String car = "com.acme.Car";
|
||||||
|
final String addresses = "com.acme.Person.addresses";
|
||||||
|
final String parts = "com.acme.Car.parts";
|
||||||
|
Properties p = new Properties();
|
||||||
|
// First option, cache defined for entity and overrides for generic entity data type and entity itself.
|
||||||
|
p.setProperty("hibernate.cache.infinispan.com.acme.Person.cfg", "person-cache");
|
||||||
|
p.setProperty("hibernate.cache.infinispan.com.acme.Person.eviction.strategy", "LRU");
|
||||||
|
p.setProperty("hibernate.cache.infinispan.com.acme.Person.eviction.wake_up_interval", "2000");
|
||||||
|
p.setProperty("hibernate.cache.infinispan.com.acme.Person.eviction.max_entries", "5000 ");
|
||||||
|
p.setProperty("hibernate.cache.infinispan.com.acme.Person.eviction.lifespan", "60000");
|
||||||
|
p.setProperty("hibernate.cache.infinispan.com.acme.Person.eviction.max_idle", "30000");
|
||||||
|
p.setProperty("hibernate.cache.infinispan.entity.cfg", "myentity-cache");
|
||||||
|
p.setProperty("hibernate.cache.infinispan.entity.eviction.strategy", "FIFO");
|
||||||
|
p.setProperty("hibernate.cache.infinispan.entity.eviction.wake_up_interval", "3000");
|
||||||
|
p.setProperty("hibernate.cache.infinispan.entity.eviction.max_entries", "20000");
|
||||||
|
p.setProperty("hibernate.cache.infinispan.com.acme.Person.addresses.cfg", "addresses-cache");
|
||||||
|
p.setProperty("hibernate.cache.infinispan.com.acme.Person.addresses.eviction.strategy", "FIFO");
|
||||||
|
p.setProperty("hibernate.cache.infinispan.com.acme.Person.addresses.eviction.wake_up_interval", "2500");
|
||||||
|
p.setProperty("hibernate.cache.infinispan.com.acme.Person.addresses.eviction.max_entries", "5500 ");
|
||||||
|
p.setProperty("hibernate.cache.infinispan.com.acme.Person.addresses.eviction.lifespan", "65000");
|
||||||
|
p.setProperty("hibernate.cache.infinispan.com.acme.Person.addresses.eviction.max_idle", "35000");
|
||||||
|
p.setProperty("hibernate.cache.infinispan.collection.cfg", "mycollection-cache");
|
||||||
|
p.setProperty("hibernate.cache.infinispan.collection.eviction.strategy", "LRU");
|
||||||
|
p.setProperty("hibernate.cache.infinispan.collection.eviction.wake_up_interval", "3500");
|
||||||
|
p.setProperty("hibernate.cache.infinispan.collection.eviction.max_entries", "25000");
|
||||||
|
InfinispanRegionFactory factory = new InfinispanRegionFactory();
|
||||||
|
factory.start(null, p);
|
||||||
|
CacheManager manager = factory.getCacheManager();
|
||||||
|
manager.getGlobalConfiguration().setTransportClass(null);
|
||||||
|
// Configuration config = new Configuration();
|
||||||
|
// // Set to local to avoid creating a JGroups channel
|
||||||
|
// config.setCacheMode(CacheMode.LOCAL);
|
||||||
|
// manager.defineConfiguration("entity", config);
|
||||||
|
// manager.defineConfiguration("timestamps", config);
|
||||||
|
// manager.defineConfiguration("myentity-cache", config);
|
||||||
|
// manager.defineConfiguration("mycollection-cache", config);
|
||||||
|
try {
|
||||||
|
assertNotNull(factory.getTypeOverrides().get(person));
|
||||||
|
assertFalse(factory.getDefinedConfigurations().contains(person));
|
||||||
|
assertNotNull(factory.getTypeOverrides().get(addresses));
|
||||||
|
assertFalse(factory.getDefinedConfigurations().contains(addresses));
|
||||||
|
Cache cache = null;
|
||||||
|
|
||||||
|
EntityRegionImpl region = (EntityRegionImpl) factory.buildEntityRegion(person, p, null);
|
||||||
|
assertNotNull(factory.getTypeOverrides().get(person));
|
||||||
|
assertTrue(factory.getDefinedConfigurations().contains(person));
|
||||||
|
assertNull(factory.getTypeOverrides().get(address));
|
||||||
|
cache = region.getCache();
|
||||||
|
Configuration cacheCfg = cache.getConfiguration();
|
||||||
|
assertEquals(EvictionStrategy.LRU, cacheCfg.getEvictionStrategy());
|
||||||
|
assertEquals(2000, cacheCfg.getEvictionWakeUpInterval());
|
||||||
|
assertEquals(5000, cacheCfg.getEvictionMaxEntries());
|
||||||
|
assertEquals(60000, cacheCfg.getExpirationLifespan());
|
||||||
|
assertEquals(30000, cacheCfg.getExpirationMaxIdle());
|
||||||
|
|
||||||
|
region = (EntityRegionImpl) factory.buildEntityRegion(address, p, null);
|
||||||
|
assertNotNull(factory.getTypeOverrides().get(person));
|
||||||
|
assertTrue(factory.getDefinedConfigurations().contains(person));
|
||||||
|
assertNull(factory.getTypeOverrides().get(address));
|
||||||
|
cache = region.getCache();
|
||||||
|
cacheCfg = cache.getConfiguration();
|
||||||
|
assertEquals(EvictionStrategy.FIFO, cacheCfg.getEvictionStrategy());
|
||||||
|
assertEquals(3000, cacheCfg.getEvictionWakeUpInterval());
|
||||||
|
assertEquals(20000, cacheCfg.getEvictionMaxEntries());
|
||||||
|
|
||||||
|
region = (EntityRegionImpl) factory.buildEntityRegion(car, p, null);
|
||||||
|
assertNotNull(factory.getTypeOverrides().get(person));
|
||||||
|
assertTrue(factory.getDefinedConfigurations().contains(person));
|
||||||
|
assertNull(factory.getTypeOverrides().get(address));
|
||||||
|
cache = region.getCache();
|
||||||
|
cacheCfg = cache.getConfiguration();
|
||||||
|
assertEquals(EvictionStrategy.FIFO, cacheCfg.getEvictionStrategy());
|
||||||
|
assertEquals(3000, cacheCfg.getEvictionWakeUpInterval());
|
||||||
|
assertEquals(20000, cacheCfg.getEvictionMaxEntries());
|
||||||
|
|
||||||
|
CollectionRegionImpl collectionRegion = (CollectionRegionImpl) factory.buildCollectionRegion(addresses, p, null);
|
||||||
|
assertNotNull(factory.getTypeOverrides().get(addresses));
|
||||||
|
assertTrue(factory.getDefinedConfigurations().contains(person));
|
||||||
|
assertNull(factory.getTypeOverrides().get(parts));
|
||||||
|
cache = collectionRegion .getCache();
|
||||||
|
cacheCfg = cache.getConfiguration();
|
||||||
|
assertEquals(EvictionStrategy.FIFO, cacheCfg.getEvictionStrategy());
|
||||||
|
assertEquals(2500, cacheCfg.getEvictionWakeUpInterval());
|
||||||
|
assertEquals(5500, cacheCfg.getEvictionMaxEntries());
|
||||||
|
assertEquals(65000, cacheCfg.getExpirationLifespan());
|
||||||
|
assertEquals(35000, cacheCfg.getExpirationMaxIdle());
|
||||||
|
|
||||||
|
collectionRegion = (CollectionRegionImpl) factory.buildCollectionRegion(parts, p, null);
|
||||||
|
assertNotNull(factory.getTypeOverrides().get(addresses));
|
||||||
|
assertTrue(factory.getDefinedConfigurations().contains(addresses));
|
||||||
|
assertNull(factory.getTypeOverrides().get(parts));
|
||||||
|
cache = collectionRegion.getCache();
|
||||||
|
cacheCfg = cache.getConfiguration();
|
||||||
|
assertEquals(EvictionStrategy.LRU, cacheCfg.getEvictionStrategy());
|
||||||
|
assertEquals(3500, cacheCfg.getEvictionWakeUpInterval());
|
||||||
|
assertEquals(25000, cacheCfg.getEvictionMaxEntries());
|
||||||
|
|
||||||
|
collectionRegion = (CollectionRegionImpl) factory.buildCollectionRegion(parts, p, null);
|
||||||
|
assertNotNull(factory.getTypeOverrides().get(addresses));
|
||||||
|
assertTrue(factory.getDefinedConfigurations().contains(addresses));
|
||||||
|
assertNull(factory.getTypeOverrides().get(parts));
|
||||||
|
cache = collectionRegion.getCache();
|
||||||
|
cacheCfg = cache.getConfiguration();
|
||||||
|
assertEquals(EvictionStrategy.LRU, cacheCfg.getEvictionStrategy());
|
||||||
|
assertEquals(3500, cacheCfg.getEvictionWakeUpInterval());
|
||||||
|
assertEquals(25000, cacheCfg.getEvictionMaxEntries());
|
||||||
|
} finally {
|
||||||
|
factory.stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testBuildEntityCollectionRegionOverridesOnly() {
|
||||||
|
Cache cache = null;
|
||||||
|
Properties p = new Properties();
|
||||||
|
p.setProperty("hibernate.cache.infinispan.entity.eviction.strategy", "FIFO");
|
||||||
|
p.setProperty("hibernate.cache.infinispan.entity.eviction.wake_up_interval", "3000");
|
||||||
|
p.setProperty("hibernate.cache.infinispan.entity.eviction.max_entries", "30000");
|
||||||
|
p.setProperty("hibernate.cache.infinispan.collection.eviction.strategy", "LRU");
|
||||||
|
p.setProperty("hibernate.cache.infinispan.collection.eviction.wake_up_interval", "3500");
|
||||||
|
p.setProperty("hibernate.cache.infinispan.collection.eviction.max_entries", "35000");
|
||||||
|
InfinispanRegionFactory factory = new InfinispanRegionFactory();
|
||||||
|
factory.start(null, p);
|
||||||
|
CacheManager manager = factory.getCacheManager();
|
||||||
|
manager.getGlobalConfiguration().setTransportClass(null);
|
||||||
|
try {
|
||||||
|
EntityRegionImpl region = (EntityRegionImpl) factory.buildEntityRegion("com.acme.Address", p, null);
|
||||||
|
assertNull(factory.getTypeOverrides().get("com.acme.Address"));
|
||||||
|
cache = region.getCache();
|
||||||
|
Configuration cacheCfg = cache.getConfiguration();
|
||||||
|
assertEquals(EvictionStrategy.FIFO, cacheCfg.getEvictionStrategy());
|
||||||
|
assertEquals(3000, cacheCfg.getEvictionWakeUpInterval());
|
||||||
|
assertEquals(30000, cacheCfg.getEvictionMaxEntries());
|
||||||
|
assertEquals(100000, cacheCfg.getExpirationMaxIdle());
|
||||||
|
|
||||||
|
CollectionRegionImpl collectionRegion = (CollectionRegionImpl) factory.buildCollectionRegion("com.acme.Person.addresses", p, null);
|
||||||
|
assertNull(factory.getTypeOverrides().get("com.acme.Person.addresses"));
|
||||||
|
cache = collectionRegion.getCache();
|
||||||
|
cacheCfg = cache.getConfiguration();
|
||||||
|
assertEquals(EvictionStrategy.LRU, cacheCfg.getEvictionStrategy());
|
||||||
|
assertEquals(3500, cacheCfg.getEvictionWakeUpInterval());
|
||||||
|
assertEquals(35000, cacheCfg.getEvictionMaxEntries());
|
||||||
|
assertEquals(100000, cacheCfg.getExpirationMaxIdle());
|
||||||
|
} finally {
|
||||||
|
factory.stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testBuildEntityRegionPersonPlusEntityOverridesWithoutCfg() {
|
||||||
|
final String person = "com.acme.Person";
|
||||||
|
Properties p = new Properties();
|
||||||
|
// Third option, no cache defined for entity and overrides for generic entity data type and entity itself.
|
||||||
|
p.setProperty("hibernate.cache.infinispan.com.acme.Person.eviction.strategy", "LRU");
|
||||||
|
p.setProperty("hibernate.cache.infinispan.com.acme.Person.eviction.lifespan", "60000");
|
||||||
|
p.setProperty("hibernate.cache.infinispan.com.acme.Person.eviction.max_idle", "30000");
|
||||||
|
p.setProperty("hibernate.cache.infinispan.entity.cfg", "myentity-cache");
|
||||||
|
p.setProperty("hibernate.cache.infinispan.entity.eviction.strategy", "FIFO");
|
||||||
|
p.setProperty("hibernate.cache.infinispan.entity.eviction.wake_up_interval", "3000");
|
||||||
|
p.setProperty("hibernate.cache.infinispan.entity.eviction.max_entries", "10000");
|
||||||
|
InfinispanRegionFactory factory = new InfinispanRegionFactory();
|
||||||
|
factory.start(null, p);
|
||||||
|
CacheManager manager = factory.getCacheManager();
|
||||||
|
manager.getGlobalConfiguration().setTransportClass(null);
|
||||||
|
try {
|
||||||
|
assertNotNull(factory.getTypeOverrides().get(person));
|
||||||
|
assertFalse(factory.getDefinedConfigurations().contains(person));
|
||||||
|
EntityRegionImpl region = (EntityRegionImpl) factory.buildEntityRegion(person, p, null);
|
||||||
|
assertNotNull(factory.getTypeOverrides().get(person));
|
||||||
|
assertTrue(factory.getDefinedConfigurations().contains(person));
|
||||||
|
Cache cache = region.getCache();
|
||||||
|
Configuration cacheCfg = cache.getConfiguration();
|
||||||
|
assertEquals(EvictionStrategy.LRU, cacheCfg.getEvictionStrategy());
|
||||||
|
assertEquals(3000, cacheCfg.getEvictionWakeUpInterval());
|
||||||
|
assertEquals(10000, cacheCfg.getEvictionMaxEntries());
|
||||||
|
assertEquals(60000, cacheCfg.getExpirationLifespan());
|
||||||
|
assertEquals(30000, cacheCfg.getExpirationMaxIdle());
|
||||||
|
} finally {
|
||||||
|
factory.stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testTimestampValidation() {
|
||||||
|
Properties p = new Properties();
|
||||||
|
final DefaultCacheManager manager = new DefaultCacheManager();
|
||||||
|
InfinispanRegionFactory factory = new InfinispanRegionFactory() {
|
||||||
|
@Override
|
||||||
|
protected CacheManager createCacheManager(String configLoc) throws CacheException {
|
||||||
|
return manager;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Configuration config = new Configuration();
|
||||||
|
config.setCacheMode(CacheMode.INVALIDATION_SYNC);
|
||||||
|
manager.defineConfiguration("timestamps", config);
|
||||||
|
try {
|
||||||
|
factory.start(null, p);
|
||||||
|
fail("Should have failed saying that invalidation is not allowed for timestamp caches.");
|
||||||
|
} catch(CacheException ce) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testBuildDefaultTimestampsRegion() {
|
||||||
|
final String timestamps = "org.hibernate.cache.UpdateTimestampsCache";
|
||||||
|
Properties p = new Properties();
|
||||||
|
InfinispanRegionFactory factory = new InfinispanRegionFactory();
|
||||||
|
factory.start(null, p);
|
||||||
|
CacheManager manager = factory.getCacheManager();
|
||||||
|
manager.getGlobalConfiguration().setTransportClass(null);
|
||||||
|
try {
|
||||||
|
assertTrue(factory.getDefinedConfigurations().contains("timestamps"));
|
||||||
|
assertTrue(factory.getTypeOverrides().get("timestamps").getCacheName().equals("timestamps"));
|
||||||
|
Configuration config = new Configuration();
|
||||||
|
config.setFetchInMemoryState(false);
|
||||||
|
manager.defineConfiguration("timestamps", config);
|
||||||
|
TimestampsRegionImpl region = (TimestampsRegionImpl) factory.buildTimestampsRegion(timestamps, p);
|
||||||
|
Cache cache = region.getCache();
|
||||||
|
Configuration cacheCfg = cache.getConfiguration();
|
||||||
|
assertEquals(EvictionStrategy.NONE, cacheCfg.getEvictionStrategy());
|
||||||
|
assertEquals(CacheMode.REPL_ASYNC, cacheCfg.getCacheMode());
|
||||||
|
assertTrue(cacheCfg.isUseLazyDeserialization());
|
||||||
|
} finally {
|
||||||
|
factory.stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testBuildDiffCacheNameTimestampsRegion() {
|
||||||
|
final String timestamps = "org.hibernate.cache.UpdateTimestampsCache";
|
||||||
|
Properties p = new Properties();
|
||||||
|
p.setProperty("hibernate.cache.infinispan.timestamps.cfg", "unrecommended-timestamps");
|
||||||
|
InfinispanRegionFactory factory = new InfinispanRegionFactory();
|
||||||
|
factory.start(null, p);
|
||||||
|
CacheManager manager = factory.getCacheManager();
|
||||||
|
manager.getGlobalConfiguration().setTransportClass(null);
|
||||||
|
try {
|
||||||
|
assertFalse(factory.getDefinedConfigurations().contains("timestamp"));
|
||||||
|
assertTrue(factory.getDefinedConfigurations().contains("unrecommended-timestamps"));
|
||||||
|
assertTrue(factory.getTypeOverrides().get("timestamps").getCacheName().equals("unrecommended-timestamps"));
|
||||||
|
Configuration config = new Configuration();
|
||||||
|
config.setFetchInMemoryState(false);
|
||||||
|
config.setCacheMode(CacheMode.REPL_SYNC);
|
||||||
|
manager.defineConfiguration("unrecommended-timestamps", config);
|
||||||
|
TimestampsRegionImpl region = (TimestampsRegionImpl) factory.buildTimestampsRegion(timestamps, p);
|
||||||
|
Cache cache = region.getCache();
|
||||||
|
Configuration cacheCfg = cache.getConfiguration();
|
||||||
|
assertEquals(EvictionStrategy.NONE, cacheCfg.getEvictionStrategy());
|
||||||
|
assertEquals(CacheMode.REPL_SYNC, cacheCfg.getCacheMode());
|
||||||
|
assertFalse(cacheCfg.isUseLazyDeserialization());
|
||||||
|
} finally {
|
||||||
|
factory.stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testBuildTimestamRegionWithCacheNameOverride() {
|
||||||
|
final String timestamps = "org.hibernate.cache.UpdateTimestampsCache";
|
||||||
|
Properties p = new Properties();
|
||||||
|
InfinispanRegionFactory factory = new InfinispanRegionFactory();
|
||||||
|
p.setProperty("hibernate.cache.infinispan.timestamps.cfg", "mytimestamps-cache");
|
||||||
|
factory.start(null, p);
|
||||||
|
CacheManager manager = factory.getCacheManager();
|
||||||
|
manager.getGlobalConfiguration().setTransportClass(null);
|
||||||
|
try {
|
||||||
|
factory.buildTimestampsRegion(timestamps, p);
|
||||||
|
assertTrue(factory.getDefinedConfigurations().contains("mytimestamps-cache"));
|
||||||
|
} finally {
|
||||||
|
factory.stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testBuildTimestamRegionWithFifoEvictionOverride() {
|
||||||
|
final String timestamps = "org.hibernate.cache.UpdateTimestampsCache";
|
||||||
|
Properties p = new Properties();
|
||||||
|
InfinispanRegionFactory factory = new InfinispanRegionFactory();
|
||||||
|
p.setProperty("hibernate.cache.infinispan.timestamps.cfg", "mytimestamps-cache");
|
||||||
|
p.setProperty("hibernate.cache.infinispan.timestamps.eviction.strategy", "FIFO");
|
||||||
|
p.setProperty("hibernate.cache.infinispan.timestamps.eviction.wake_up_interval", "3000");
|
||||||
|
p.setProperty("hibernate.cache.infinispan.timestamps.eviction.max_entries", "10000");
|
||||||
|
try {
|
||||||
|
factory.start(null, p);
|
||||||
|
CacheManager manager = factory.getCacheManager();
|
||||||
|
manager.getGlobalConfiguration().setTransportClass(null);
|
||||||
|
factory.buildTimestampsRegion(timestamps, p);
|
||||||
|
assertTrue(factory.getDefinedConfigurations().contains("mytimestamps-cache"));
|
||||||
|
fail("Should fail cos no eviction configurations are allowed for timestamp caches");
|
||||||
|
} catch(CacheException ce) {
|
||||||
|
} finally {
|
||||||
|
factory.stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testBuildTimestamRegionWithNoneEvictionOverride() {
|
||||||
|
final String timestamps = "org.hibernate.cache.UpdateTimestampsCache";
|
||||||
|
Properties p = new Properties();
|
||||||
|
InfinispanRegionFactory factory = new InfinispanRegionFactory();
|
||||||
|
p.setProperty("hibernate.cache.infinispan.timestamps.cfg", "timestamps-none-eviction");
|
||||||
|
p.setProperty("hibernate.cache.infinispan.timestamps.eviction.strategy", "NONE");
|
||||||
|
p.setProperty("hibernate.cache.infinispan.timestamps.eviction.wake_up_interval", "3000");
|
||||||
|
p.setProperty("hibernate.cache.infinispan.timestamps.eviction.max_entries", "10000");
|
||||||
|
factory.start(null, p);
|
||||||
|
CacheManager manager = factory.getCacheManager();
|
||||||
|
manager.getGlobalConfiguration().setTransportClass(null);
|
||||||
|
try {
|
||||||
|
factory.buildTimestampsRegion(timestamps, p);
|
||||||
|
assertTrue(factory.getDefinedConfigurations().contains("timestamps-none-eviction"));
|
||||||
|
} finally {
|
||||||
|
factory.stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testBuildQueryRegion() {
|
||||||
|
final String query = "org.hibernate.cache.StandardQueryCache";
|
||||||
|
Properties p = new Properties();
|
||||||
|
InfinispanRegionFactory factory = new InfinispanRegionFactory();
|
||||||
|
factory.start(null, p);
|
||||||
|
CacheManager manager = factory.getCacheManager();
|
||||||
|
manager.getGlobalConfiguration().setTransportClass(null);
|
||||||
|
try {
|
||||||
|
assertTrue(factory.getDefinedConfigurations().contains("local-query"));
|
||||||
|
QueryResultsRegionImpl region = (QueryResultsRegionImpl) factory.buildQueryResultsRegion(query, p);
|
||||||
|
Cache cache = region.getCache();
|
||||||
|
Configuration cacheCfg = cache.getConfiguration();
|
||||||
|
assertEquals(CacheMode.LOCAL, cacheCfg.getCacheMode());
|
||||||
|
} finally {
|
||||||
|
factory.stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,541 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2007, Red Hat, Inc. and/or it's affiliates or third-party contributors as
|
||||||
|
* indicated by the @author tags or express copyright attribution
|
||||||
|
* statements applied by the authors. All third-party contributions are
|
||||||
|
* distributed under license by Red Hat, Inc. and/or it's affiliates.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||||
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
* Lesser General Public License, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this distribution; if not, write to:
|
||||||
|
* Free Software Foundation, Inc.
|
||||||
|
* 51 Franklin Street, Fifth Floor
|
||||||
|
* Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
package org.hibernate.test.cache.infinispan.collection;
|
||||||
|
|
||||||
|
import java.util.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.infinispan.InfinispanRegionFactory;
|
||||||
|
import org.hibernate.cache.infinispan.impl.BaseRegion;
|
||||||
|
import org.hibernate.cache.infinispan.util.CacheHelper;
|
||||||
|
import org.hibernate.cfg.Configuration;
|
||||||
|
import org.hibernate.test.cache.infinispan.AbstractNonFunctionalTestCase;
|
||||||
|
import org.hibernate.test.cache.infinispan.util.CacheTestUtil;
|
||||||
|
import org.hibernate.util.ComparableComparator;
|
||||||
|
import org.infinispan.Cache;
|
||||||
|
import org.infinispan.context.Flag;
|
||||||
|
import org.infinispan.transaction.tm.BatchModeTransactionManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base class for tests of CollectionRegionAccessStrategy impls.
|
||||||
|
*
|
||||||
|
* @author Galder Zamarreño
|
||||||
|
* @since 3.5
|
||||||
|
*/
|
||||||
|
public abstract class AbstractCollectionRegionAccessStrategyTestCase extends AbstractNonFunctionalTestCase {
|
||||||
|
|
||||||
|
public static final String REGION_NAME = "test/com.foo.test";
|
||||||
|
public static final String KEY_BASE = "KEY";
|
||||||
|
public static final String VALUE1 = "VALUE1";
|
||||||
|
public static final String VALUE2 = "VALUE2";
|
||||||
|
|
||||||
|
protected static int testCount;
|
||||||
|
|
||||||
|
protected static Configuration localCfg;
|
||||||
|
protected static InfinispanRegionFactory localRegionFactory;
|
||||||
|
protected Cache localCache;
|
||||||
|
protected static Configuration remoteCfg;
|
||||||
|
protected static InfinispanRegionFactory remoteRegionFactory;
|
||||||
|
protected Cache remoteCache;
|
||||||
|
|
||||||
|
protected CollectionRegion localCollectionRegion;
|
||||||
|
protected CollectionRegionAccessStrategy localAccessStrategy;
|
||||||
|
|
||||||
|
protected CollectionRegion remoteCollectionRegion;
|
||||||
|
protected CollectionRegionAccessStrategy remoteAccessStrategy;
|
||||||
|
|
||||||
|
protected boolean invalidation;
|
||||||
|
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();
|
||||||
|
|
||||||
|
// Sleep a bit to avoid concurrent FLUSH problem
|
||||||
|
avoidConcurrentFlush();
|
||||||
|
|
||||||
|
localCollectionRegion = localRegionFactory.buildCollectionRegion(REGION_NAME, localCfg.getProperties(),
|
||||||
|
getCacheDataDescription());
|
||||||
|
localCache = ((BaseRegion) localCollectionRegion).getCache();
|
||||||
|
localAccessStrategy = localCollectionRegion.buildAccessStrategy(getAccessType());
|
||||||
|
invalidation = CacheHelper.isClusteredInvalidation(localCache);
|
||||||
|
synchronous = CacheHelper.isSynchronous(localCache);
|
||||||
|
|
||||||
|
// Sleep a bit to avoid concurrent FLUSH problem
|
||||||
|
avoidConcurrentFlush();
|
||||||
|
|
||||||
|
remoteCollectionRegion = remoteRegionFactory.buildCollectionRegion(REGION_NAME, remoteCfg.getProperties(),
|
||||||
|
getCacheDataDescription());
|
||||||
|
remoteCache = ((BaseRegion) remoteCollectionRegion).getCache();
|
||||||
|
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.getAdvancedCache().clear(Flag.CACHE_MODE_LOCAL);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Problem purging local cache", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
remoteCache.getAdvancedCache().clear(Flag.CACHE_MODE_LOCAL);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Problem purging remote cache", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
node1Exception = null;
|
||||||
|
node2Exception = null;
|
||||||
|
|
||||||
|
node1Failure = null;
|
||||||
|
node2Failure = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static Configuration createConfiguration(String configName, String configResource) {
|
||||||
|
Configuration cfg = CacheTestUtil.buildConfiguration(REGION_PREFIX, InfinispanRegionFactory.class, true, false);
|
||||||
|
cfg.setProperty(InfinispanRegionFactory.ENTITY_CACHE_RESOURCE_PROP, configName);
|
||||||
|
return cfg;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected CacheDataDescription getCacheDataDescription() {
|
||||||
|
return new CacheDataDescriptionImpl(true, true, ComparableComparator.INSTANCE);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean isUsingInvalidation() {
|
||||||
|
return invalidation;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean isSynchronous() {
|
||||||
|
return synchronous;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 String KEY = KEY_BASE + testCount++;
|
||||||
|
|
||||||
|
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("node2 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()) {
|
||||||
|
// PFER does not generate any invalidation, so each node should
|
||||||
|
// succeed. We count on database locking and Hibernate removing
|
||||||
|
// the collection on any update to prevent the situation we have
|
||||||
|
// here where the caches have inconsistent data
|
||||||
|
expected1 = VALUE2;
|
||||||
|
expected2 = VALUE1;
|
||||||
|
} 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) {
|
||||||
|
|
||||||
|
final String KEY = KEY_BASE + testCount++;
|
||||||
|
|
||||||
|
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) {
|
||||||
|
|
||||||
|
final String KEY = KEY_BASE + testCount++;
|
||||||
|
|
||||||
|
// Fqn regionFqn = getRegionFqn(REGION_NAME, REGION_PREFIX);
|
||||||
|
//
|
||||||
|
// Node regionRoot = localCache.getRoot().getChild(regionFqn);
|
||||||
|
// assertFalse(regionRoot == null);
|
||||||
|
// assertEquals(0, getValidChildrenCount(regionRoot));
|
||||||
|
// assertTrue(regionRoot.isResident());
|
||||||
|
assertEquals(0, localCache.keySet().size());
|
||||||
|
|
||||||
|
// regionRoot = remoteCache.getRoot().getChild(regionFqn);
|
||||||
|
// assertFalse(regionRoot == null);
|
||||||
|
// assertEquals(0, getValidChildrenCount(regionRoot));
|
||||||
|
// assertTrue(regionRoot.isResident());
|
||||||
|
assertEquals(0, remoteCache.keySet().size());
|
||||||
|
|
||||||
|
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.evictAll();
|
||||||
|
else
|
||||||
|
localAccessStrategy.removeAll();
|
||||||
|
|
||||||
|
// This should re-establish the region root node
|
||||||
|
assertNull(localAccessStrategy.get(KEY, System.currentTimeMillis()));
|
||||||
|
|
||||||
|
// regionRoot = localCache.getRoot().getChild(regionFqn);
|
||||||
|
// assertFalse(regionRoot == null);
|
||||||
|
// assertEquals(0, getValidChildrenCount(regionRoot));
|
||||||
|
// assertTrue(regionRoot.isValid());
|
||||||
|
// assertTrue(regionRoot.isResident());
|
||||||
|
assertEquals(0, localCache.keySet().size());
|
||||||
|
|
||||||
|
// Re-establishing the region root on the local node doesn't
|
||||||
|
// propagate it to other nodes. Do a get on the remote node to re-establish
|
||||||
|
assertEquals(null, remoteAccessStrategy.get(KEY, System.currentTimeMillis()));
|
||||||
|
|
||||||
|
// regionRoot = remoteCache.getRoot().getChild(regionFqn);
|
||||||
|
// assertFalse(regionRoot == null);
|
||||||
|
// assertTrue(regionRoot.isValid());
|
||||||
|
// assertTrue(regionRoot.isResident());
|
||||||
|
//
|
||||||
|
// assertEquals(0, getValidChildrenCount(regionRoot));
|
||||||
|
// Not invalidation, so we didn't insert a child above
|
||||||
|
assertEquals(0, remoteCache.keySet().size());
|
||||||
|
|
||||||
|
// Test whether the get above messes up the optimistic version
|
||||||
|
remoteAccessStrategy.putFromLoad(KEY, VALUE1, System.currentTimeMillis(), new Integer(1));
|
||||||
|
assertEquals(VALUE1, remoteAccessStrategy.get(KEY, System.currentTimeMillis()));
|
||||||
|
|
||||||
|
// regionRoot = remoteCache.getRoot().getChild(regionFqn);
|
||||||
|
// assertFalse(regionRoot == null);
|
||||||
|
// assertTrue(regionRoot.isValid());
|
||||||
|
// assertTrue(regionRoot.isResident());
|
||||||
|
// // Region root should have 1 child -- the one we added above
|
||||||
|
// assertEquals(1, getValidChildrenCount(regionRoot));
|
||||||
|
// Revalidate the region root
|
||||||
|
assertEquals(1, remoteCache.keySet().size());
|
||||||
|
|
||||||
|
// Wait for async propagation of the putFromLoad
|
||||||
|
sleep(250);
|
||||||
|
|
||||||
|
assertEquals("local is correct", (isUsingInvalidation() ? null : VALUE1), localAccessStrategy.get(KEY, System
|
||||||
|
.currentTimeMillis()));
|
||||||
|
assertEquals("remote is correct", VALUE1, remoteAccessStrategy.get(KEY, System.currentTimeMillis()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void rollback() {
|
||||||
|
try {
|
||||||
|
BatchModeTransactionManager.getInstance().rollback();
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error(e.getMessage(), e);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class AccessStrategyTestSetup extends TestSetup {
|
||||||
|
|
||||||
|
private static final String PREFER_IPV4STACK = "java.net.preferIPv4Stack";
|
||||||
|
|
||||||
|
private final String configResource;
|
||||||
|
private final String configName;
|
||||||
|
private String preferIPv4Stack;
|
||||||
|
|
||||||
|
public AccessStrategyTestSetup(Test test, String configName) {
|
||||||
|
this(test, configName, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AccessStrategyTestSetup(Test test, String configName, String configResource) {
|
||||||
|
super(test);
|
||||||
|
this.configName = configName;
|
||||||
|
this.configResource = configResource;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void setUp() throws Exception {
|
||||||
|
super.setUp();
|
||||||
|
|
||||||
|
// Try to ensure we use IPv4; otherwise cluster formation is very slow
|
||||||
|
preferIPv4Stack = System.getProperty(PREFER_IPV4STACK);
|
||||||
|
System.setProperty(PREFER_IPV4STACK, "true");
|
||||||
|
|
||||||
|
localCfg = createConfiguration(configName, configResource);
|
||||||
|
localRegionFactory = CacheTestUtil.startRegionFactory(localCfg);
|
||||||
|
|
||||||
|
remoteCfg = createConfiguration(configName, configResource);
|
||||||
|
remoteRegionFactory = CacheTestUtil.startRegionFactory(remoteCfg);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void tearDown() throws Exception {
|
||||||
|
try {
|
||||||
|
super.tearDown();
|
||||||
|
} finally {
|
||||||
|
if (preferIPv4Stack == null)
|
||||||
|
System.clearProperty(PREFER_IPV4STACK);
|
||||||
|
else
|
||||||
|
System.setProperty(PREFER_IPV4STACK, preferIPv4Stack);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (localRegionFactory != null)
|
||||||
|
localRegionFactory.stop();
|
||||||
|
|
||||||
|
if (remoteRegionFactory != null)
|
||||||
|
remoteRegionFactory.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,44 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2007, Red Hat, Inc. and/or it's affiliates or third-party contributors as
|
||||||
|
* indicated by the @author tags or express copyright attribution
|
||||||
|
* statements applied by the authors. All third-party contributions are
|
||||||
|
* distributed under license by Red Hat, Inc. and/or it's affiliates.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||||
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
* Lesser General Public License, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this distribution; if not, write to:
|
||||||
|
* Free Software Foundation, Inc.
|
||||||
|
* 51 Franklin Street, Fifth Floor
|
||||||
|
* Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
package org.hibernate.test.cache.infinispan.collection;
|
||||||
|
|
||||||
|
import org.hibernate.cache.access.AccessType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base class for tests of TRANSACTIONAL access.
|
||||||
|
*
|
||||||
|
* @author <a href="brian.stansberry@jboss.com">Brian Stansberry</a>
|
||||||
|
*/
|
||||||
|
public abstract class AbstractReadOnlyAccessTestCase extends AbstractCollectionRegionAccessStrategyTestCase {
|
||||||
|
|
||||||
|
public AbstractReadOnlyAccessTestCase(String name) {
|
||||||
|
super(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected AccessType getAccessType() {
|
||||||
|
return AccessType.READ_ONLY;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,48 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2007, Red Hat, Inc. and/or it's affiliates or third-party contributors as
|
||||||
|
* indicated by the @author tags or express copyright attribution
|
||||||
|
* statements applied by the authors. All third-party contributions are
|
||||||
|
* distributed under license by Red Hat, Inc. and/or it's affiliates.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||||
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
* Lesser General Public License, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this distribution; if not, write to:
|
||||||
|
* Free Software Foundation, Inc.
|
||||||
|
* 51 Franklin Street, Fifth Floor
|
||||||
|
* Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
package org.hibernate.test.cache.infinispan.collection;
|
||||||
|
|
||||||
|
import org.hibernate.cache.access.AccessType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base class for tests of TRANSACTIONAL access.
|
||||||
|
*
|
||||||
|
* @author <a href="brian.stansberry@jboss.com">Brian Stansberry</a>
|
||||||
|
*/
|
||||||
|
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,51 @@
|
||||||
|
/*
|
||||||
|
* JBoss, Home of Professional Open Source.
|
||||||
|
* Copyright 2009, Red Hat, Inc. and/or it's affiliates, and individual contributors
|
||||||
|
* as indicated by the @author tags. See the copyright.txt file in the
|
||||||
|
* distribution for a full listing of individual contributors.
|
||||||
|
*
|
||||||
|
* This is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU Lesser General Public License as
|
||||||
|
* published by the Free Software Foundation; either version 2.1 of
|
||||||
|
* the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This software is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this software; if not, write to the Free
|
||||||
|
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||||
|
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
|
||||||
|
*/
|
||||||
|
package org.hibernate.test.cache.infinispan.collection;
|
||||||
|
|
||||||
|
import org.hibernate.test.cache.infinispan.util.CacheTestUtil;
|
||||||
|
|
||||||
|
import junit.framework.Test;
|
||||||
|
import junit.framework.TestSuite;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* InvalidatedTransactionalTestCase.
|
||||||
|
*
|
||||||
|
* @author Galder Zamarreño
|
||||||
|
* @since 3.5
|
||||||
|
*/
|
||||||
|
public class InvalidatedTransactionalTestCase extends AbstractTransactionalAccessTestCase {
|
||||||
|
|
||||||
|
public InvalidatedTransactionalTestCase(String name) {
|
||||||
|
super(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void testCacheConfiguration() {
|
||||||
|
assertTrue("Using Invalidation", isUsingInvalidation());
|
||||||
|
assertTrue("Synchronous mode", isSynchronous());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Test suite() throws Exception {
|
||||||
|
TestSuite suite = CacheTestUtil.createFailureExpectedSuite(InvalidatedTransactionalTestCase.class);
|
||||||
|
return getTestSetup(suite, "entity");
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,80 @@
|
||||||
|
/*
|
||||||
|
* JBoss, Home of Professional Open Source.
|
||||||
|
* Copyright 2009, Red Hat, Inc. and/or it's affiliates, and individual contributors
|
||||||
|
* as indicated by the @author tags. See the copyright.txt file in the
|
||||||
|
* distribution for a full listing of individual contributors.
|
||||||
|
*
|
||||||
|
* This is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU Lesser General Public License as
|
||||||
|
* published by the Free Software Foundation; either version 2.1 of
|
||||||
|
* the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This software is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this software; if not, write to the Free
|
||||||
|
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||||
|
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
|
||||||
|
*/
|
||||||
|
package org.hibernate.test.cache.infinispan.collection;
|
||||||
|
|
||||||
|
import org.hibernate.cache.access.AccessType;
|
||||||
|
import org.hibernate.cache.access.CollectionRegionAccessStrategy;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ReadOnlyExtraAPITestCase.
|
||||||
|
*
|
||||||
|
* @author Galder Zamarreño
|
||||||
|
* @since 3.5
|
||||||
|
*/
|
||||||
|
public class ReadOnlyExtraAPITestCase extends TransactionalExtraAPITestCase {
|
||||||
|
|
||||||
|
public ReadOnlyExtraAPITestCase(String name) {
|
||||||
|
super(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static CollectionRegionAccessStrategy localAccessStrategy;
|
||||||
|
|
||||||
|
@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,51 @@
|
||||||
|
/*
|
||||||
|
* JBoss, Home of Professional Open Source.
|
||||||
|
* Copyright 2009, Red Hat, Inc. and/or it's affiliates, and individual contributors
|
||||||
|
* as indicated by the @author tags. See the copyright.txt file in the
|
||||||
|
* distribution for a full listing of individual contributors.
|
||||||
|
*
|
||||||
|
* This is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU Lesser General Public License as
|
||||||
|
* published by the Free Software Foundation; either version 2.1 of
|
||||||
|
* the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This software is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this software; if not, write to the Free
|
||||||
|
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||||
|
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
|
||||||
|
*/
|
||||||
|
package org.hibernate.test.cache.infinispan.collection;
|
||||||
|
|
||||||
|
import org.hibernate.test.cache.infinispan.util.CacheTestUtil;
|
||||||
|
|
||||||
|
import junit.framework.Test;
|
||||||
|
import junit.framework.TestSuite;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests READ_ONLY access when invalidation is used.
|
||||||
|
*
|
||||||
|
* @author Galder Zamarreño
|
||||||
|
* @since 3.5
|
||||||
|
*/
|
||||||
|
public class ReadOnlyTestCase extends AbstractReadOnlyAccessTestCase {
|
||||||
|
|
||||||
|
public ReadOnlyTestCase(String name) {
|
||||||
|
super(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Test suite() throws Exception {
|
||||||
|
TestSuite suite = CacheTestUtil.createFailureExpectedSuite(ReadOnlyTestCase.class);
|
||||||
|
return getTestSetup(suite, "entity");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void testCacheConfiguration() {
|
||||||
|
assertTrue("Using Invalidation", isUsingInvalidation());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,125 @@
|
||||||
|
/*
|
||||||
|
* JBoss, Home of Professional Open Source.
|
||||||
|
* Copyright 2009, Red Hat, Inc. and/or it's affiliates, and individual contributors
|
||||||
|
* as indicated by the @author tags. See the copyright.txt file in the
|
||||||
|
* distribution for a full listing of individual contributors.
|
||||||
|
*
|
||||||
|
* This is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU Lesser General Public License as
|
||||||
|
* published by the Free Software Foundation; either version 2.1 of
|
||||||
|
* the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This software is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this software; if not, write to the Free
|
||||||
|
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||||
|
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
|
||||||
|
*/
|
||||||
|
package org.hibernate.test.cache.infinispan.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.infinispan.InfinispanRegionFactory;
|
||||||
|
import org.hibernate.cfg.Configuration;
|
||||||
|
import org.hibernate.test.cache.infinispan.AbstractNonFunctionalTestCase;
|
||||||
|
import org.hibernate.test.cache.infinispan.util.CacheTestUtil;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* TransactionalExtraAPITestCase.
|
||||||
|
*
|
||||||
|
* @author Galder Zamarreño
|
||||||
|
* @since 3.5
|
||||||
|
*/
|
||||||
|
public class TransactionalExtraAPITestCase extends AbstractNonFunctionalTestCase {
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
public TransactionalExtraAPITestCase(String name) {
|
||||||
|
super(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setUp() throws Exception {
|
||||||
|
super.setUp();
|
||||||
|
|
||||||
|
if (getCollectionAccessStrategy() == null) {
|
||||||
|
Configuration cfg = createConfiguration();
|
||||||
|
InfinispanRegionFactory rf = CacheTestUtil.startRegionFactory(cfg, getCacheTestSupport());
|
||||||
|
|
||||||
|
// Sleep a bit to avoid concurrent FLUSH problem
|
||||||
|
avoidConcurrentFlush();
|
||||||
|
|
||||||
|
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, InfinispanRegionFactory.class, true, false);
|
||||||
|
cfg.setProperty(InfinispanRegionFactory.ENTITY_CACHE_RESOURCE_PROP, getCacheConfigName());
|
||||||
|
return cfg;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String getCacheConfigName() {
|
||||||
|
return "entity";
|
||||||
|
}
|
||||||
|
|
||||||
|
protected AccessType getAccessType() {
|
||||||
|
return AccessType.TRANSACTIONAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected CollectionRegionAccessStrategy getCollectionAccessStrategy() {
|
||||||
|
return localAccessStrategy;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setCollectionAccessStrategy(CollectionRegionAccessStrategy strategy) {
|
||||||
|
localAccessStrategy = strategy;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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,743 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2007, Red Hat, Inc. and/or it's affiliates or third-party contributors as
|
||||||
|
* indicated by the @author tags or express copyright attribution
|
||||||
|
* statements applied by the authors. All third-party contributions are
|
||||||
|
* distributed under license by Red Hat, Inc. and/or it's affiliates.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||||
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
* Lesser General Public License, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this distribution; if not, write to:
|
||||||
|
* Free Software Foundation, Inc.
|
||||||
|
* 51 Franklin Street, Fifth Floor
|
||||||
|
* Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
package org.hibernate.test.cache.infinispan.entity;
|
||||||
|
|
||||||
|
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.infinispan.InfinispanRegionFactory;
|
||||||
|
import org.hibernate.cache.infinispan.impl.BaseRegion;
|
||||||
|
import org.hibernate.cache.infinispan.util.CacheHelper;
|
||||||
|
import org.hibernate.cfg.Configuration;
|
||||||
|
import org.hibernate.test.cache.infinispan.AbstractNonFunctionalTestCase;
|
||||||
|
import org.hibernate.test.cache.infinispan.util.CacheTestUtil;
|
||||||
|
import org.hibernate.util.ComparableComparator;
|
||||||
|
import org.infinispan.Cache;
|
||||||
|
import org.infinispan.context.Flag;
|
||||||
|
import org.infinispan.transaction.tm.BatchModeTransactionManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base class for tests of EntityRegionAccessStrategy impls.
|
||||||
|
*
|
||||||
|
* @author Galder Zamarreño
|
||||||
|
* @since 3.5
|
||||||
|
*/
|
||||||
|
public abstract class AbstractEntityRegionAccessStrategyTestCase extends AbstractNonFunctionalTestCase {
|
||||||
|
|
||||||
|
public static final String REGION_NAME = "test/com.foo.test";
|
||||||
|
public static final String KEY_BASE = "KEY";
|
||||||
|
public static final String VALUE1 = "VALUE1";
|
||||||
|
public static final String VALUE2 = "VALUE2";
|
||||||
|
|
||||||
|
protected static int testCount;
|
||||||
|
|
||||||
|
protected static Configuration localCfg;
|
||||||
|
protected static InfinispanRegionFactory localRegionFactory;
|
||||||
|
protected Cache localCache;
|
||||||
|
protected static Configuration remoteCfg;
|
||||||
|
protected static InfinispanRegionFactory remoteRegionFactory;
|
||||||
|
protected Cache remoteCache;
|
||||||
|
|
||||||
|
protected boolean invalidation;
|
||||||
|
protected 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();
|
||||||
|
|
||||||
|
// Sleep a bit to avoid concurrent FLUSH problem
|
||||||
|
avoidConcurrentFlush();
|
||||||
|
|
||||||
|
localEntityRegion = localRegionFactory.buildEntityRegion(REGION_NAME, localCfg
|
||||||
|
.getProperties(), getCacheDataDescription());
|
||||||
|
localAccessStrategy = localEntityRegion.buildAccessStrategy(getAccessType());
|
||||||
|
|
||||||
|
localCache = ((BaseRegion) localEntityRegion).getCache();
|
||||||
|
|
||||||
|
invalidation = CacheHelper.isClusteredInvalidation(localCache);
|
||||||
|
synchronous = CacheHelper.isSynchronous(localCache);
|
||||||
|
|
||||||
|
// Sleep a bit to avoid concurrent FLUSH problem
|
||||||
|
avoidConcurrentFlush();
|
||||||
|
|
||||||
|
remoteEntityRegion = remoteRegionFactory.buildEntityRegion(REGION_NAME, remoteCfg
|
||||||
|
.getProperties(), getCacheDataDescription());
|
||||||
|
remoteAccessStrategy = remoteEntityRegion.buildAccessStrategy(getAccessType());
|
||||||
|
|
||||||
|
remoteCache = ((BaseRegion) remoteEntityRegion).getCache();
|
||||||
|
|
||||||
|
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.getAdvancedCache().clear(Flag.CACHE_MODE_LOCAL);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Problem purging local cache", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
remoteCache.getAdvancedCache().clear(Flag.CACHE_MODE_LOCAL);
|
||||||
|
} 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, InfinispanRegionFactory.class, true, false);
|
||||||
|
cfg.setProperty(InfinispanRegionFactory.ENTITY_CACHE_RESOURCE_PROP, configName);
|
||||||
|
return cfg;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected CacheDataDescription getCacheDataDescription() {
|
||||||
|
return new CacheDataDescriptionImpl(true, true, ComparableComparator.INSTANCE);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean isUsingInvalidation() {
|
||||||
|
return invalidation;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean isSynchronous() {
|
||||||
|
return synchronous;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void assertThreadsRanCleanly() {
|
||||||
|
if (node1Failure != null)
|
||||||
|
throw node1Failure;
|
||||||
|
if (node2Failure != null)
|
||||||
|
throw node2Failure;
|
||||||
|
|
||||||
|
if (node1Exception != null) {
|
||||||
|
log.error("node1 saw an exception", node1Exception);
|
||||||
|
assertEquals("node1 saw no exceptions", null, node1Exception);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node2Exception != null) {
|
||||||
|
log.error("node2 saw an exception", node2Exception);
|
||||||
|
assertEquals("node2 saw no exceptions", null, node2Exception);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 String KEY = KEY_BASE + testCount++;
|
||||||
|
|
||||||
|
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));
|
||||||
|
|
||||||
|
assertThreadsRanCleanly();
|
||||||
|
|
||||||
|
long txTimestamp = System.currentTimeMillis();
|
||||||
|
assertEquals("Correct node1 value", VALUE2, localAccessStrategy.get(KEY, txTimestamp));
|
||||||
|
|
||||||
|
if (isUsingInvalidation()) {
|
||||||
|
// 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 String KEY = KEY_BASE + testCount++;
|
||||||
|
|
||||||
|
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 = !isBlockingReads() ? null : VALUE1;
|
||||||
|
Object expected = null;
|
||||||
|
|
||||||
|
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 (!isBlockingReads())
|
||||||
|
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));
|
||||||
|
// }
|
||||||
|
|
||||||
|
assertThreadsRanCleanly();
|
||||||
|
|
||||||
|
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 {
|
||||||
|
|
||||||
|
final String KEY = KEY_BASE + testCount++;
|
||||||
|
|
||||||
|
// Set up initial state
|
||||||
|
localAccessStrategy.get(KEY, System.currentTimeMillis());
|
||||||
|
localAccessStrategy.putFromLoad(KEY, VALUE1, System.currentTimeMillis(), new Integer(1));
|
||||||
|
remoteAccessStrategy.get(KEY, System.currentTimeMillis());
|
||||||
|
remoteAccessStrategy.putFromLoad(KEY, VALUE1, System.currentTimeMillis(), new Integer(1));
|
||||||
|
|
||||||
|
// Let the async put propagate
|
||||||
|
sleep(250);
|
||||||
|
|
||||||
|
final CountDownLatch readLatch = new CountDownLatch(1);
|
||||||
|
final CountDownLatch commitLatch = new CountDownLatch(1);
|
||||||
|
final CountDownLatch completionLatch = new CountDownLatch(2);
|
||||||
|
|
||||||
|
Thread updater = new Thread("testUpdate-updater") {
|
||||||
|
|
||||||
|
public void run() {
|
||||||
|
boolean readerUnlocked = false;
|
||||||
|
try {
|
||||||
|
long txTimestamp = System.currentTimeMillis();
|
||||||
|
BatchModeTransactionManager.getInstance().begin();
|
||||||
|
log.debug("Transaction began, get initial value");
|
||||||
|
assertEquals("Correct initial value", VALUE1, localAccessStrategy.get(KEY, txTimestamp));
|
||||||
|
log.debug("Now update value");
|
||||||
|
localAccessStrategy.update(KEY, VALUE2, new Integer(2), new Integer(1));
|
||||||
|
log.debug("Notify the read latch");
|
||||||
|
readLatch.countDown();
|
||||||
|
readerUnlocked = true;
|
||||||
|
log.debug("Await commit");
|
||||||
|
commitLatch.await();
|
||||||
|
BatchModeTransactionManager.getInstance().commit();
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("node1 caught exception", e);
|
||||||
|
node1Exception = e;
|
||||||
|
rollback();
|
||||||
|
} catch (AssertionFailedError e) {
|
||||||
|
node1Failure = e;
|
||||||
|
rollback();
|
||||||
|
} finally {
|
||||||
|
if (!readerUnlocked) readLatch.countDown();
|
||||||
|
log.debug("Completion latch countdown");
|
||||||
|
completionLatch.countDown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Thread reader = new Thread("testUpdate-reader") {
|
||||||
|
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
long txTimestamp = System.currentTimeMillis();
|
||||||
|
BatchModeTransactionManager.getInstance().begin();
|
||||||
|
log.debug("Transaction began, await read latch");
|
||||||
|
readLatch.await();
|
||||||
|
log.debug("Read latch acquired, verify local access strategy");
|
||||||
|
|
||||||
|
// 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 = !isBlockingReads() ? VALUE1 : VALUE2;
|
||||||
|
Object expected = VALUE1;
|
||||||
|
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();
|
||||||
|
log.debug("Completion latch countdown");
|
||||||
|
completionLatch.countDown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
updater.setDaemon(true);
|
||||||
|
reader.setDaemon(true);
|
||||||
|
updater.start();
|
||||||
|
reader.start();
|
||||||
|
|
||||||
|
// if (!isBlockingReads())
|
||||||
|
// Should complete promptly
|
||||||
|
assertTrue(completionLatch.await(2, 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));
|
||||||
|
// }
|
||||||
|
|
||||||
|
assertThreadsRanCleanly();
|
||||||
|
|
||||||
|
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) {
|
||||||
|
|
||||||
|
final String KEY = KEY_BASE + testCount++;
|
||||||
|
|
||||||
|
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) {
|
||||||
|
|
||||||
|
final String KEY = KEY_BASE + testCount++;
|
||||||
|
|
||||||
|
// Fqn regionFqn = getRegionFqn(REGION_NAME, REGION_PREFIX);
|
||||||
|
//
|
||||||
|
// Node regionRoot = localCache.getRoot().getChild(regionFqn);
|
||||||
|
// assertFalse(regionRoot == null);
|
||||||
|
assertEquals(0, localCache.keySet().size());
|
||||||
|
// assertTrue(regionRoot.isResident());
|
||||||
|
|
||||||
|
// regionRoot = remoteCache.getRoot().getChild(regionFqn);
|
||||||
|
// assertFalse(regionRoot == null);
|
||||||
|
assertEquals(0, remoteCache.keySet().size());
|
||||||
|
// assertTrue(regionRoot.isResident());
|
||||||
|
|
||||||
|
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()));
|
||||||
|
|
||||||
|
// Wait for async propagation
|
||||||
|
sleep(250);
|
||||||
|
|
||||||
|
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.evictAll();
|
||||||
|
else
|
||||||
|
localAccessStrategy.removeAll();
|
||||||
|
|
||||||
|
// This should re-establish the region root node in the optimistic case
|
||||||
|
assertNull(localAccessStrategy.get(KEY, System.currentTimeMillis()));
|
||||||
|
|
||||||
|
// regionRoot = localCache.getRoot().getChild(regionFqn);
|
||||||
|
// assertFalse(regionRoot == null);
|
||||||
|
// assertEquals(0, getValidChildrenCount(regionRoot));
|
||||||
|
// assertTrue(regionRoot.isValid());
|
||||||
|
// assertTrue(regionRoot.isResident());
|
||||||
|
assertEquals(0, localCache.keySet().size());
|
||||||
|
|
||||||
|
// Re-establishing the region root on the local node doesn't
|
||||||
|
// propagate it to other nodes. Do a get on the remote node to re-establish
|
||||||
|
assertEquals(null, remoteAccessStrategy.get(KEY, System.currentTimeMillis()));
|
||||||
|
|
||||||
|
// regionRoot = remoteCache.getRoot().getChild(regionFqn);
|
||||||
|
// assertFalse(regionRoot == null);
|
||||||
|
// assertTrue(regionRoot.isValid());
|
||||||
|
// assertTrue(regionRoot.isResident());
|
||||||
|
// // Not invalidation, so we didn't insert a child above
|
||||||
|
// assertEquals(0, getValidChildrenCount(regionRoot));
|
||||||
|
assertEquals(0, remoteCache.keySet().size());
|
||||||
|
|
||||||
|
// Test whether the get above messes up the optimistic version
|
||||||
|
remoteAccessStrategy.putFromLoad(KEY, VALUE1, System.currentTimeMillis(), new Integer(1));
|
||||||
|
assertEquals(VALUE1, remoteAccessStrategy.get(KEY, System.currentTimeMillis()));
|
||||||
|
|
||||||
|
// Revalidate the region root
|
||||||
|
// regionRoot = remoteCache.getRoot().getChild(regionFqn);
|
||||||
|
// assertFalse(regionRoot == null);
|
||||||
|
// assertTrue(regionRoot.isValid());
|
||||||
|
// assertTrue(regionRoot.isResident());
|
||||||
|
// // Region root should have 1 child -- the one we added above
|
||||||
|
// assertEquals(1, getValidChildrenCount(regionRoot));
|
||||||
|
assertEquals(1, remoteCache.keySet().size());
|
||||||
|
|
||||||
|
// Wait for async propagation
|
||||||
|
sleep(250);
|
||||||
|
|
||||||
|
assertEquals("local is correct", (isUsingInvalidation() ? null : VALUE1), localAccessStrategy
|
||||||
|
.get(KEY, System.currentTimeMillis()));
|
||||||
|
assertEquals("remote is correct", VALUE1, remoteAccessStrategy.get(KEY, System
|
||||||
|
.currentTimeMillis()));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void rollback() {
|
||||||
|
try {
|
||||||
|
BatchModeTransactionManager.getInstance().rollback();
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error(e.getMessage(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class AccessStrategyTestSetup extends TestSetup {
|
||||||
|
|
||||||
|
private static final String PREFER_IPV4STACK = "java.net.preferIPv4Stack";
|
||||||
|
private final String configName;
|
||||||
|
private String preferIPv4Stack;
|
||||||
|
|
||||||
|
public AccessStrategyTestSetup(Test test, String configName) {
|
||||||
|
super(test);
|
||||||
|
this.configName = configName;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void setUp() throws Exception {
|
||||||
|
try {
|
||||||
|
super.tearDown();
|
||||||
|
} finally {
|
||||||
|
if (preferIPv4Stack == null)
|
||||||
|
System.clearProperty(PREFER_IPV4STACK);
|
||||||
|
else
|
||||||
|
System.setProperty(PREFER_IPV4STACK, preferIPv4Stack);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to ensure we use IPv4; otherwise cluster formation is very slow
|
||||||
|
preferIPv4Stack = System.getProperty(PREFER_IPV4STACK);
|
||||||
|
System.setProperty(PREFER_IPV4STACK, "true");
|
||||||
|
|
||||||
|
localCfg = createConfiguration(configName);
|
||||||
|
localRegionFactory = CacheTestUtil.startRegionFactory(localCfg);
|
||||||
|
// localCache = localRegionFactory.getCacheManager().getCache("entity");
|
||||||
|
|
||||||
|
remoteCfg = createConfiguration(configName);
|
||||||
|
remoteRegionFactory = CacheTestUtil.startRegionFactory(remoteCfg);
|
||||||
|
// remoteCache = remoteRegionFactory.getCacheManager().getCache("entity");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void tearDown() throws Exception {
|
||||||
|
super.tearDown();
|
||||||
|
|
||||||
|
if (localRegionFactory != null)
|
||||||
|
localRegionFactory.stop();
|
||||||
|
|
||||||
|
if (remoteRegionFactory != null)
|
||||||
|
remoteRegionFactory.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,93 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2007, Red Hat, Inc. and/or it's affiliates or third-party contributors as
|
||||||
|
* indicated by the @author tags or express copyright attribution
|
||||||
|
* statements applied by the authors. All third-party contributions are
|
||||||
|
* distributed under license by Red Hat, Inc. and/or it's affiliates.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||||
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
* Lesser General Public License, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this distribution; if not, write to:
|
||||||
|
* Free Software Foundation, Inc.
|
||||||
|
* 51 Franklin Street, Fifth Floor
|
||||||
|
* Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
package org.hibernate.test.cache.infinispan.entity;
|
||||||
|
|
||||||
|
import org.hibernate.cache.access.AccessType;
|
||||||
|
import org.infinispan.transaction.tm.BatchModeTransactionManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base class for tests of TRANSACTIONAL access.
|
||||||
|
*
|
||||||
|
* @author Galder Zamarreño
|
||||||
|
* @since 3.5
|
||||||
|
*/
|
||||||
|
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 {
|
||||||
|
|
||||||
|
final String KEY = KEY_BASE + testCount++;
|
||||||
|
|
||||||
|
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 {
|
||||||
|
|
||||||
|
final String KEY = KEY_BASE + testCount++;
|
||||||
|
|
||||||
|
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,132 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2007, Red Hat, Inc. and/or it's affiliates or third-party contributors as
|
||||||
|
* indicated by the @author tags or express copyright attribution
|
||||||
|
* statements applied by the authors. All third-party contributions are
|
||||||
|
* distributed under license by Red Hat, Inc. and/or it's affiliates.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||||
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
* Lesser General Public License, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this distribution; if not, write to:
|
||||||
|
* Free Software Foundation, Inc.
|
||||||
|
* 51 Franklin Street, Fifth Floor
|
||||||
|
* Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
package org.hibernate.test.cache.infinispan.entity;
|
||||||
|
|
||||||
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import junit.framework.AssertionFailedError;
|
||||||
|
|
||||||
|
import org.hibernate.cache.access.AccessType;
|
||||||
|
import org.infinispan.transaction.tm.BatchModeTransactionManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base class for tests of TRANSACTIONAL access.
|
||||||
|
*
|
||||||
|
* @author Galder Zamarreño
|
||||||
|
* @since 3.5
|
||||||
|
*/
|
||||||
|
public abstract class AbstractTransactionalAccessTestCase extends AbstractEntityRegionAccessStrategyTestCase {
|
||||||
|
|
||||||
|
public AbstractTransactionalAccessTestCase(String name) {
|
||||||
|
super(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected AccessType getAccessType() {
|
||||||
|
return AccessType.TRANSACTIONAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testContestedPutFromLoad() throws Exception {
|
||||||
|
|
||||||
|
final String KEY = KEY_BASE + testCount++;
|
||||||
|
|
||||||
|
localAccessStrategy.get(KEY, System.currentTimeMillis());
|
||||||
|
localAccessStrategy.putFromLoad(KEY, VALUE1, System.currentTimeMillis(), new Integer(1));
|
||||||
|
|
||||||
|
final CountDownLatch pferLatch = new CountDownLatch(1);
|
||||||
|
final CountDownLatch pferCompletionLatch = new CountDownLatch(1);
|
||||||
|
final CountDownLatch commitLatch = new CountDownLatch(1);
|
||||||
|
final CountDownLatch completionLatch = new CountDownLatch(1);
|
||||||
|
|
||||||
|
Thread blocker = new Thread("Blocker") {
|
||||||
|
|
||||||
|
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("Putter") {
|
||||||
|
|
||||||
|
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));
|
||||||
|
|
||||||
|
assertThreadsRanCleanly();
|
||||||
|
|
||||||
|
long txTimestamp = System.currentTimeMillis();
|
||||||
|
assertEquals("Correct node1 value", VALUE2, localAccessStrategy.get(KEY, txTimestamp));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,101 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2007, Red Hat, Inc. and/or it's affiliates or third-party contributors as
|
||||||
|
* indicated by the @author tags or express copyright attribution
|
||||||
|
* statements applied by the authors. All third-party contributions are
|
||||||
|
* distributed under license by Red Hat, Inc. and/or it's affiliates.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||||
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
* Lesser General Public License, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this distribution; if not, write to:
|
||||||
|
* Free Software Foundation, Inc.
|
||||||
|
* 51 Franklin Street, Fifth Floor
|
||||||
|
* Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
package org.hibernate.test.cache.infinispan.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.infinispan.InfinispanRegionFactory;
|
||||||
|
import org.hibernate.test.cache.infinispan.AbstractEntityCollectionRegionTestCase;
|
||||||
|
import org.infinispan.Cache;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests of EntityRegionImpl.
|
||||||
|
*
|
||||||
|
* @author Galder Zamarreño
|
||||||
|
* @since 3.5
|
||||||
|
*/
|
||||||
|
public class EntityRegionImplTestCase extends AbstractEntityCollectionRegionTestCase {
|
||||||
|
|
||||||
|
public EntityRegionImplTestCase(String name) {
|
||||||
|
super(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void supportedAccessTypeTest(RegionFactory regionFactory, Properties properties) {
|
||||||
|
|
||||||
|
EntityRegion region = regionFactory.buildEntityRegion("test", properties, null);
|
||||||
|
|
||||||
|
assertNull("Got TRANSACTIONAL", region.buildAccessStrategy(AccessType.TRANSACTIONAL).lockRegion());
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
region.buildAccessStrategy(AccessType.READ_ONLY).lockRegion();
|
||||||
|
fail("Did not get READ_ONLY");
|
||||||
|
}
|
||||||
|
catch (UnsupportedOperationException good) {}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
region.buildAccessStrategy(AccessType.NONSTRICT_READ_WRITE);
|
||||||
|
fail("Incorrectly got NONSTRICT_READ_WRITE");
|
||||||
|
}
|
||||||
|
catch (CacheException good) {}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
region.buildAccessStrategy(AccessType.READ_WRITE);
|
||||||
|
fail("Incorrectly got READ_WRITE");
|
||||||
|
}
|
||||||
|
catch (CacheException good) {}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void putInRegion(Region region, Object key, Object value) {
|
||||||
|
((EntityRegion) region).buildAccessStrategy(AccessType.TRANSACTIONAL).insert(key, value, new Integer(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void removeFromRegion(Region region, Object key) {
|
||||||
|
((EntityRegion) region).buildAccessStrategy(AccessType.TRANSACTIONAL).remove(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Region createRegion(InfinispanRegionFactory regionFactory, String regionName,
|
||||||
|
Properties properties, CacheDataDescription cdd) {
|
||||||
|
return regionFactory.buildEntityRegion(regionName, properties, cdd);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Cache getInfinispanCache(InfinispanRegionFactory regionFactory) {
|
||||||
|
return regionFactory.getCacheManager().getCache("entity");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,52 @@
|
||||||
|
/*
|
||||||
|
* JBoss, Home of Professional Open Source.
|
||||||
|
* Copyright 2009, Red Hat, Inc. and/or it's affiliates, and individual contributors
|
||||||
|
* as indicated by the @author tags. See the copyright.txt file in the
|
||||||
|
* distribution for a full listing of individual contributors.
|
||||||
|
*
|
||||||
|
* This is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU Lesser General Public License as
|
||||||
|
* published by the Free Software Foundation; either version 2.1 of
|
||||||
|
* the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This software is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this software; if not, write to the Free
|
||||||
|
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||||
|
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
|
||||||
|
*/
|
||||||
|
package org.hibernate.test.cache.infinispan.entity;
|
||||||
|
|
||||||
|
import org.hibernate.test.cache.infinispan.util.CacheTestUtil;
|
||||||
|
|
||||||
|
import junit.framework.Test;
|
||||||
|
import junit.framework.TestSuite;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* InvalidatedTransactionalTestCase.
|
||||||
|
*
|
||||||
|
* @author Galder Zamarreño
|
||||||
|
* @since 3.5
|
||||||
|
*/
|
||||||
|
public class InvalidatedTransactionalTestCase extends AbstractTransactionalAccessTestCase {
|
||||||
|
|
||||||
|
public InvalidatedTransactionalTestCase(String name) {
|
||||||
|
super(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void testCacheConfiguration() {
|
||||||
|
assertTrue("Using Invalidation", isUsingInvalidation());
|
||||||
|
assertTrue("Synchronous mode", isSynchronous());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Test suite() throws Exception {
|
||||||
|
TestSuite suite = CacheTestUtil.createFailureExpectedSuite(InvalidatedTransactionalTestCase.class);
|
||||||
|
return getTestSetup(suite, "entity");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,95 @@
|
||||||
|
/*
|
||||||
|
* JBoss, Home of Professional Open Source.
|
||||||
|
* Copyright 2009, Red Hat, Inc. and/or it's affiliates, and individual contributors
|
||||||
|
* as indicated by the @author tags. See the copyright.txt file in the
|
||||||
|
* distribution for a full listing of individual contributors.
|
||||||
|
*
|
||||||
|
* This is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU Lesser General Public License as
|
||||||
|
* published by the Free Software Foundation; either version 2.1 of
|
||||||
|
* the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This software is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this software; if not, write to the Free
|
||||||
|
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||||
|
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
|
||||||
|
*/
|
||||||
|
package org.hibernate.test.cache.infinispan.entity;
|
||||||
|
|
||||||
|
import org.hibernate.cache.access.AccessType;
|
||||||
|
import org.hibernate.cache.access.EntityRegionAccessStrategy;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for the "extra API" in EntityRegionAccessStrategy;
|
||||||
|
* <p>
|
||||||
|
* By "extra API" we mean those methods that are superfluous to the
|
||||||
|
* function of the Infinispan integration, where the impl is a no-op or a static
|
||||||
|
* false return value, UnsupportedOperationException, etc.
|
||||||
|
*
|
||||||
|
* @author Galder Zamarreño
|
||||||
|
* @since 3.5
|
||||||
|
*/
|
||||||
|
public class ReadOnlyExtraAPITestCase extends TransactionalExtraAPITestCase {
|
||||||
|
private static EntityRegionAccessStrategy localAccessStrategy;
|
||||||
|
|
||||||
|
public ReadOnlyExtraAPITestCase(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) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
62
cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/entity/ReadOnlyTestCase.java
vendored
Normal file
62
cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/entity/ReadOnlyTestCase.java
vendored
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2007, Red Hat, Inc. and/or it's affiliates or third-party contributors as
|
||||||
|
* indicated by the @author tags or express copyright attribution
|
||||||
|
* statements applied by the authors. All third-party contributions are
|
||||||
|
* distributed under license by Red Hat, Inc. and/or it's affiliates.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||||
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
* Lesser General Public License, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this distribution; if not, write to:
|
||||||
|
* Free Software Foundation, Inc.
|
||||||
|
* 51 Franklin Street, Fifth Floor
|
||||||
|
* Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
package org.hibernate.test.cache.infinispan.entity;
|
||||||
|
|
||||||
|
import org.hibernate.test.cache.infinispan.util.CacheTestUtil;
|
||||||
|
|
||||||
|
import junit.framework.Test;
|
||||||
|
import junit.framework.TestSuite;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests READ_ONLY access when pessimistic locking and invalidation are used.
|
||||||
|
*
|
||||||
|
* @author Galder Zamarreño
|
||||||
|
* @since 3.5
|
||||||
|
*/
|
||||||
|
public class ReadOnlyTestCase extends AbstractReadOnlyAccessTestCase {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new PessimisticTransactionalAccessTestCase.
|
||||||
|
*
|
||||||
|
* @param name
|
||||||
|
*/
|
||||||
|
public ReadOnlyTestCase(String name) {
|
||||||
|
super(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Test suite() throws Exception {
|
||||||
|
TestSuite suite = CacheTestUtil.createFailureExpectedSuite(ReadOnlyTestCase.class);
|
||||||
|
return getTestSetup(suite, "entity");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Known failures
|
||||||
|
|
||||||
|
// Overrides
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void testCacheConfiguration() {
|
||||||
|
assertTrue("Using Invalidation", isUsingInvalidation());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,147 @@
|
||||||
|
/*
|
||||||
|
* JBoss, Home of Professional Open Source.
|
||||||
|
* Copyright 2009, Red Hat, Inc. and/or it's affiliates, and individual contributors
|
||||||
|
* as indicated by the @author tags. See the copyright.txt file in the
|
||||||
|
* distribution for a full listing of individual contributors.
|
||||||
|
*
|
||||||
|
* This is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU Lesser General Public License as
|
||||||
|
* published by the Free Software Foundation; either version 2.1 of
|
||||||
|
* the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This software is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this software; if not, write to the Free
|
||||||
|
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||||
|
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
|
||||||
|
*/
|
||||||
|
package org.hibernate.test.cache.infinispan.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.infinispan.InfinispanRegionFactory;
|
||||||
|
import org.hibernate.cfg.Configuration;
|
||||||
|
import org.hibernate.test.cache.infinispan.AbstractNonFunctionalTestCase;
|
||||||
|
import org.hibernate.test.cache.infinispan.util.CacheTestUtil;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for the "extra API" in EntityRegionAccessStrategy;.
|
||||||
|
* <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 Galder Zamarreño
|
||||||
|
* @since 3.5
|
||||||
|
*/
|
||||||
|
public class TransactionalExtraAPITestCase extends AbstractNonFunctionalTestCase {
|
||||||
|
|
||||||
|
public TransactionalExtraAPITestCase(String name) {
|
||||||
|
super(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
protected void setUp() throws Exception {
|
||||||
|
super.setUp();
|
||||||
|
|
||||||
|
if (getEntityAccessStrategy() == null) {
|
||||||
|
Configuration cfg = createConfiguration();
|
||||||
|
InfinispanRegionFactory rf = CacheTestUtil.startRegionFactory(cfg, getCacheTestSupport());
|
||||||
|
|
||||||
|
// Sleep a bit to avoid concurrent FLUSH problem
|
||||||
|
avoidConcurrentFlush();
|
||||||
|
|
||||||
|
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, InfinispanRegionFactory.class, true, false);
|
||||||
|
cfg.setProperty(InfinispanRegionFactory.ENTITY_CACHE_RESOURCE_PROP, getCacheConfigName());
|
||||||
|
return cfg;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String getCacheConfigName() {
|
||||||
|
return "entity";
|
||||||
|
}
|
||||||
|
|
||||||
|
protected AccessType getAccessType() {
|
||||||
|
return AccessType.TRANSACTIONAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected EntityRegionAccessStrategy getEntityAccessStrategy() {
|
||||||
|
return localAccessStrategy;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setEntityRegionAccessStrategy(EntityRegionAccessStrategy strategy) {
|
||||||
|
localAccessStrategy = strategy;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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,39 @@
|
||||||
|
package org.hibernate.test.cache.infinispan.functional;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.hibernate.junit.functional.FunctionalTestCase;
|
||||||
|
import org.hibernate.stat.SecondLevelCacheStatistics;
|
||||||
|
import org.hibernate.stat.Statistics;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Galder Zamarreño
|
||||||
|
* @since 3.5
|
||||||
|
*/
|
||||||
|
public abstract class AbstractFunctionalTestCase extends FunctionalTestCase {
|
||||||
|
private final String cacheConcurrencyStrategy;
|
||||||
|
|
||||||
|
public AbstractFunctionalTestCase(String string, String cacheConcurrencyStrategy) {
|
||||||
|
super(string);
|
||||||
|
this.cacheConcurrencyStrategy = cacheConcurrencyStrategy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String[] getMappings() {
|
||||||
|
return new String[] { "cache/infinispan/functional/Item.hbm.xml" };
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getCacheConcurrencyStrategy() {
|
||||||
|
return cacheConcurrencyStrategy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testEmptySecondLevelCacheEntry() throws Exception {
|
||||||
|
// getSessions().evictEntity(Item.class.getName());
|
||||||
|
getSessions().getCache().evictEntityRegion(Item.class.getName());
|
||||||
|
Statistics stats = getSessions().getStatistics();
|
||||||
|
stats.clear();
|
||||||
|
SecondLevelCacheStatistics statistics = stats.getSecondLevelCacheStatistics(Item.class.getName() + ".items");
|
||||||
|
Map cacheEntries = statistics.getEntries();
|
||||||
|
assertEquals(0, cacheEntries.size());
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
package org.hibernate.test.cache.infinispan.functional;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Galder Zamarreño
|
||||||
|
* @since 3.5
|
||||||
|
*/
|
||||||
|
public class BasicReadOnlyTestCase extends AbstractFunctionalTestCase {
|
||||||
|
|
||||||
|
public BasicReadOnlyTestCase(String string) {
|
||||||
|
super(string, "read-only");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,188 @@
|
||||||
|
package org.hibernate.test.cache.infinispan.functional;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
import org.hibernate.Session;
|
||||||
|
import org.hibernate.Transaction;
|
||||||
|
import org.hibernate.cache.entry.CacheEntry;
|
||||||
|
import org.hibernate.stat.SecondLevelCacheStatistics;
|
||||||
|
import org.hibernate.stat.Statistics;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Galder Zamarreño
|
||||||
|
* @since 3.5
|
||||||
|
*/
|
||||||
|
public class BasicTransactionalTestCase extends AbstractFunctionalTestCase {
|
||||||
|
|
||||||
|
public BasicTransactionalTestCase(String string) {
|
||||||
|
super(string, "transactional");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testEntityCache() {
|
||||||
|
Item item = new Item("chris", "Chris's Item");
|
||||||
|
|
||||||
|
Session s = openSession();
|
||||||
|
Statistics stats = s.getSessionFactory().getStatistics();
|
||||||
|
s.getTransaction().begin();
|
||||||
|
s.persist(item);
|
||||||
|
s.getTransaction().commit();
|
||||||
|
s.close();
|
||||||
|
|
||||||
|
s = openSession();
|
||||||
|
Item found = (Item) s.load(Item.class, item.getId());
|
||||||
|
System.out.println(stats);
|
||||||
|
assertEquals(item.getDescription(), found.getDescription());
|
||||||
|
assertEquals(0, stats.getSecondLevelCacheMissCount());
|
||||||
|
assertEquals(1, stats.getSecondLevelCacheHitCount());
|
||||||
|
s.delete(found);
|
||||||
|
s.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testCollectionCache() {
|
||||||
|
Item item = new Item("chris", "Chris's Item");
|
||||||
|
Item another = new Item("another", "Owned Item");
|
||||||
|
item.addItem(another);
|
||||||
|
|
||||||
|
Session s = openSession();
|
||||||
|
s.getTransaction().begin();
|
||||||
|
s.persist(item);
|
||||||
|
s.persist(another);
|
||||||
|
s.getTransaction().commit();
|
||||||
|
s.close();
|
||||||
|
|
||||||
|
s = openSession();
|
||||||
|
Statistics stats = s.getSessionFactory().getStatistics();
|
||||||
|
Item loaded = (Item) s.load(Item.class, item.getId());
|
||||||
|
assertEquals(1, loaded.getItems().size());
|
||||||
|
s.close();
|
||||||
|
|
||||||
|
s = openSession();
|
||||||
|
SecondLevelCacheStatistics cStats = stats.getSecondLevelCacheStatistics(Item.class.getName() + ".items");
|
||||||
|
Item loadedWithCachedCollection = (Item) s.load(Item.class, item.getId());
|
||||||
|
stats.logSummary();
|
||||||
|
assertEquals(item.getName(), loadedWithCachedCollection.getName());
|
||||||
|
assertEquals(item.getItems().size(), loadedWithCachedCollection.getItems().size());
|
||||||
|
assertEquals(1, cStats.getHitCount());
|
||||||
|
s.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void 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;
|
||||||
|
cachedVersionValue = (Long) ((CacheEntry) entry).getVersion();
|
||||||
|
assertEquals(initialVersion.longValue(), cachedVersionValue.longValue());
|
||||||
|
|
||||||
|
// cleanup
|
||||||
|
s = openSession();
|
||||||
|
txn = s.beginTransaction();
|
||||||
|
item = (VersionedItem) s.load(VersionedItem.class, item.getId());
|
||||||
|
s.delete(item);
|
||||||
|
txn.commit();
|
||||||
|
s.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
CacheEntry entry = (CacheEntry) slcs.getEntries().get(i.getId());
|
||||||
|
Serializable[] ser = entry.getDisassembledState();
|
||||||
|
assertTrue(ser[0].equals("widget"));
|
||||||
|
assertTrue(ser[1].equals("A bog standard item"));
|
||||||
|
|
||||||
|
// cleanup
|
||||||
|
s = openSession();
|
||||||
|
t = s.beginTransaction();
|
||||||
|
s.delete(i);
|
||||||
|
t.commit();
|
||||||
|
s.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testQueryCache() {
|
||||||
|
Item item = new Item("chris", "Chris's Item");
|
||||||
|
|
||||||
|
Session s = openSession();
|
||||||
|
s.getTransaction().begin();
|
||||||
|
s.persist(item);
|
||||||
|
s.getTransaction().commit();
|
||||||
|
s.close();
|
||||||
|
|
||||||
|
s = openSession();
|
||||||
|
s.createQuery("from Item").setCacheable(true).list();
|
||||||
|
s.close();
|
||||||
|
|
||||||
|
s = openSession();
|
||||||
|
Statistics stats = s.getSessionFactory().getStatistics();
|
||||||
|
s.createQuery("from Item").setCacheable(true).list();
|
||||||
|
assertEquals(1, stats.getQueryCacheHitCount());
|
||||||
|
s.createQuery("delete from Item").executeUpdate();
|
||||||
|
s.close();
|
||||||
|
}
|
||||||
|
}
|
91
cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/Contact.java
vendored
Executable file
91
cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/Contact.java
vendored
Executable file
|
@ -0,0 +1,91 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2008, Red Hat, Inc. and/or it's affiliates or third-party contributors as
|
||||||
|
* indicated by the @author tags or express copyright attribution
|
||||||
|
* statements applied by the authors. All third-party contributions are
|
||||||
|
* distributed under license by Red Hat, Inc. and/or it's affiliates.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||||
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
* Lesser General Public License, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this distribution; if not, write to:
|
||||||
|
* Free Software Foundation, Inc.
|
||||||
|
* 51 Franklin Street, Fifth Floor
|
||||||
|
* Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
package org.hibernate.test.cache.infinispan.functional;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Entity that has a many-to-one relationship to a Customer
|
||||||
|
*
|
||||||
|
* @author Galder Zamarreño
|
||||||
|
* @since 3.5
|
||||||
|
*/
|
||||||
|
public class Contact implements Serializable {
|
||||||
|
Integer id;
|
||||||
|
String name;
|
||||||
|
String tlf;
|
||||||
|
Customer customer;
|
||||||
|
|
||||||
|
public Integer getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Integer id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTlf() {
|
||||||
|
return tlf;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTlf(String tlf) {
|
||||||
|
this.tlf = tlf;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Customer getCustomer() {
|
||||||
|
return customer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCustomer(Customer customer) {
|
||||||
|
this.customer = customer;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o) {
|
||||||
|
if (o == this)
|
||||||
|
return true;
|
||||||
|
if (!(o instanceof Contact))
|
||||||
|
return false;
|
||||||
|
Contact c = (Contact) o;
|
||||||
|
return c.id.equals(id) && c.name.equals(name) && c.tlf.equals(tlf);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
int result = 17;
|
||||||
|
result = 31 * result + (id == null ? 0 : id.hashCode());
|
||||||
|
result = 31 * result + name.hashCode();
|
||||||
|
result = 31 * result + tlf.hashCode();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
67
cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/Customer.java
vendored
Executable file
67
cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/Customer.java
vendored
Executable file
|
@ -0,0 +1,67 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2008, Red Hat, Inc. and/or it's affiliates or third-party contributors as
|
||||||
|
* indicated by the @author tags or express copyright attribution
|
||||||
|
* statements applied by the authors. All third-party contributions are
|
||||||
|
* distributed under license by Red Hat, Inc. and/or it's affiliates.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||||
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
* Lesser General Public License, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this distribution; if not, write to:
|
||||||
|
* Free Software Foundation, Inc.
|
||||||
|
* 51 Franklin Street, Fifth Floor
|
||||||
|
* Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
package org.hibernate.test.cache.infinispan.functional;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Company customer
|
||||||
|
*
|
||||||
|
* @author Emmanuel Bernard
|
||||||
|
* @author Kabir Khan
|
||||||
|
*/
|
||||||
|
public class Customer implements Serializable {
|
||||||
|
Integer id;
|
||||||
|
String name;
|
||||||
|
|
||||||
|
private transient Set<Contact> contacts;
|
||||||
|
|
||||||
|
public Customer() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Integer id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String string) {
|
||||||
|
name = string;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<Contact> getContacts() {
|
||||||
|
return contacts;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setContacts(Set<Contact> contacts) {
|
||||||
|
this.contacts = contacts;
|
||||||
|
}
|
||||||
|
}
|
90
cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/Item.java
vendored
Executable file
90
cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/Item.java
vendored
Executable file
|
@ -0,0 +1,90 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2007, Red Hat, Inc. and/or it's affiliates or third-party contributors as
|
||||||
|
* indicated by the @author tags or express copyright attribution
|
||||||
|
* statements applied by the authors. All third-party contributions are
|
||||||
|
* distributed under license by Red Hat, Inc. and/or it's affiliates.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||||
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
* Lesser General Public License, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this distribution; if not, write to:
|
||||||
|
* Free Software Foundation, Inc.
|
||||||
|
* 51 Franklin Street, Fifth Floor
|
||||||
|
* Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
package org.hibernate.test.cache.infinispan.functional;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Gavin King
|
||||||
|
*/
|
||||||
|
public class Item {
|
||||||
|
private Long id;
|
||||||
|
private String name;
|
||||||
|
private String description;
|
||||||
|
private Item owner;
|
||||||
|
private Set<Item> items = new HashSet<Item>();
|
||||||
|
|
||||||
|
public Item() {}
|
||||||
|
|
||||||
|
public Item( String name, String description ) {
|
||||||
|
this.name = name;
|
||||||
|
this.description = 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Item getOwner() {
|
||||||
|
return owner;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOwner( Item owner ) {
|
||||||
|
this.owner = owner;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Set<Item> getItems() {
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setItems( Set<Item> items ) {
|
||||||
|
this.items = items;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addItem( Item item ) {
|
||||||
|
item.setOwner( this );
|
||||||
|
getItems().add( item );
|
||||||
|
}
|
||||||
|
}
|
39
cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/VersionedItem.java
vendored
Executable file
39
cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/functional/VersionedItem.java
vendored
Executable file
|
@ -0,0 +1,39 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2007, Red Hat, Inc. and/or it's affiliates or third-party contributors as
|
||||||
|
* indicated by the @author tags or express copyright attribution
|
||||||
|
* statements applied by the authors. All third-party contributions are
|
||||||
|
* distributed under license by Red Hat, Inc. and/or it's affiliates.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||||
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
* Lesser General Public License, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this distribution; if not, write to:
|
||||||
|
* Free Software Foundation, Inc.
|
||||||
|
* 51 Franklin Street, Fifth Floor
|
||||||
|
* Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
package org.hibernate.test.cache.infinispan.functional;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
public class VersionedItem extends Item {
|
||||||
|
private Long version;
|
||||||
|
|
||||||
|
public Long getVersion() {
|
||||||
|
return version;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setVersion(Long version) {
|
||||||
|
this.version = version;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,321 @@
|
||||||
|
/*
|
||||||
|
* JBoss, Home of Professional Open Source.
|
||||||
|
* Copyright 2009, Red Hat, Inc. and/or it's affiliates, and individual contributors
|
||||||
|
* as indicated by the @author tags. See the copyright.txt file in the
|
||||||
|
* distribution for a full listing of individual contributors.
|
||||||
|
*
|
||||||
|
* This is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU Lesser General Public License as
|
||||||
|
* published by the Free Software Foundation; either version 2.1 of
|
||||||
|
* the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This software is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this software; if not, write to the Free
|
||||||
|
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||||
|
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
|
||||||
|
*/
|
||||||
|
package org.hibernate.test.cache.infinispan.functional.bulk;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import javax.transaction.TransactionManager;
|
||||||
|
|
||||||
|
import org.hibernate.FlushMode;
|
||||||
|
import org.hibernate.cfg.Configuration;
|
||||||
|
import org.hibernate.cfg.Environment;
|
||||||
|
import org.hibernate.classic.Session;
|
||||||
|
import org.hibernate.junit.functional.FunctionalTestCase;
|
||||||
|
import org.hibernate.test.cache.infinispan.functional.Contact;
|
||||||
|
import org.hibernate.test.cache.infinispan.functional.Customer;
|
||||||
|
import org.hibernate.transaction.CMTTransactionFactory;
|
||||||
|
import org.hibernate.transaction.TransactionManagerLookup;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* BulkOperationsTestCase.
|
||||||
|
*
|
||||||
|
* @author Galder Zamarreño
|
||||||
|
* @since 3.5
|
||||||
|
*/
|
||||||
|
public class BulkOperationsTestCase extends FunctionalTestCase {
|
||||||
|
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(BulkOperationsTestCase.class);
|
||||||
|
|
||||||
|
private TransactionManager tm;
|
||||||
|
|
||||||
|
public BulkOperationsTestCase(String string) {
|
||||||
|
super(string);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String[] getMappings() {
|
||||||
|
return new String[] { "cache/infinispan/functional/Contact.hbm.xml", "cache/infinispan/functional/Customer.hbm.xml" };
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getCacheConcurrencyStrategy() {
|
||||||
|
return "transactional";
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Class getTransactionFactoryClass() {
|
||||||
|
return CMTTransactionFactory.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Class getConnectionProviderClass() {
|
||||||
|
// return org.hibernate.test.tm.ConnectionProviderImpl.class;
|
||||||
|
return org.hibernate.test.cache.infinispan.tm.XaConnectionProvider.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Class<? extends TransactionManagerLookup> getTransactionManagerLookupClass() {
|
||||||
|
return org.hibernate.test.cache.infinispan.tm.XaTransactionManagerLookup.class;
|
||||||
|
// return org.hibernate.test.tm.TransactionManagerLookupImpl.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void configure(Configuration cfg) {
|
||||||
|
super.configure(cfg);
|
||||||
|
|
||||||
|
cfg.setProperty(Environment.USE_SECOND_LEVEL_CACHE, "true");
|
||||||
|
cfg.setProperty(Environment.GENERATE_STATISTICS, "true");
|
||||||
|
cfg.setProperty(Environment.CONNECTION_PROVIDER, getConnectionProviderClass().getName());
|
||||||
|
cfg.setProperty(Environment.TRANSACTION_MANAGER_STRATEGY, getTransactionManagerLookupClass().getName());
|
||||||
|
|
||||||
|
Class transactionFactory = getTransactionFactoryClass();
|
||||||
|
cfg.setProperty( Environment.TRANSACTION_STRATEGY, transactionFactory.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testBulkOperations() throws Throwable {
|
||||||
|
System.out.println("*** testBulkOperations()");
|
||||||
|
boolean cleanedUp = false;
|
||||||
|
try {
|
||||||
|
tm = getTransactionManagerLookupClass().newInstance().getTransactionManager(null);
|
||||||
|
|
||||||
|
createContacts();
|
||||||
|
|
||||||
|
List<Integer> rhContacts = getContactsByCustomer("Red Hat");
|
||||||
|
assertNotNull("Red Hat contacts exist", rhContacts);
|
||||||
|
assertEquals("Created expected number of Red Hat contacts", 10, rhContacts.size());
|
||||||
|
|
||||||
|
assertEquals("Deleted all Red Hat contacts", 10, deleteContacts());
|
||||||
|
|
||||||
|
List<Integer> jbContacts = getContactsByCustomer("JBoss");
|
||||||
|
assertNotNull("JBoss contacts exist", jbContacts);
|
||||||
|
assertEquals("JBoss contacts remain", 10, jbContacts.size());
|
||||||
|
|
||||||
|
for (Integer id : rhContacts) {
|
||||||
|
assertNull("Red Hat contact " + id + " cannot be retrieved", getContact(id));
|
||||||
|
}
|
||||||
|
rhContacts = getContactsByCustomer("Red Hat");
|
||||||
|
if (rhContacts != null) {
|
||||||
|
assertEquals("No Red Hat contacts remain", 0, rhContacts.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
updateContacts("Kabir", "Updated");
|
||||||
|
for (Integer id : jbContacts) {
|
||||||
|
Contact contact = getContact(id);
|
||||||
|
assertNotNull("JBoss contact " + id + " exists", contact);
|
||||||
|
String expected = ("Kabir".equals(contact.getName())) ? "Updated" : "2222";
|
||||||
|
assertEquals("JBoss contact " + id + " has correct TLF", expected, contact.getTlf());
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Integer> updated = getContactsByTLF("Updated");
|
||||||
|
assertNotNull("Got updated contacts", updated);
|
||||||
|
assertEquals("Updated contacts", 5, updated.size());
|
||||||
|
} catch(Throwable t) {
|
||||||
|
cleanedUp = true;
|
||||||
|
log.debug("Exceptional cleanup");
|
||||||
|
cleanup(true);
|
||||||
|
throw t;
|
||||||
|
} finally {
|
||||||
|
// cleanup the db so we can run this test multiple times w/o restarting the cluster
|
||||||
|
if (!cleanedUp) {
|
||||||
|
log.debug("Non exceptional cleanup");
|
||||||
|
cleanup(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void createContacts() throws Exception {
|
||||||
|
log.debug("Create 10 contacts");
|
||||||
|
tm.begin();
|
||||||
|
try {
|
||||||
|
for (int i = 0; i < 10; i++)
|
||||||
|
createCustomer(i);
|
||||||
|
tm.commit();
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Unable to create customer", e);
|
||||||
|
tm.rollback();
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int deleteContacts() throws Exception {
|
||||||
|
String deleteHQL = "delete Contact where customer in ";
|
||||||
|
deleteHQL += " (select customer FROM Customer as customer ";
|
||||||
|
deleteHQL += " where customer.name = :cName)";
|
||||||
|
|
||||||
|
tm.begin();
|
||||||
|
try {
|
||||||
|
|
||||||
|
Session session = getSessions().getCurrentSession();
|
||||||
|
int rowsAffected = session.createQuery(deleteHQL).setFlushMode(FlushMode.AUTO)
|
||||||
|
.setParameter("cName", "Red Hat").executeUpdate();
|
||||||
|
tm.commit();
|
||||||
|
return rowsAffected;
|
||||||
|
} catch (Exception e) {
|
||||||
|
try {
|
||||||
|
tm.rollback();
|
||||||
|
} catch (Exception ee) {
|
||||||
|
// ignored
|
||||||
|
}
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Integer> getContactsByCustomer(String customerName) throws Exception {
|
||||||
|
String selectHQL = "select contact.id from Contact contact";
|
||||||
|
selectHQL += " where contact.customer.name = :cName";
|
||||||
|
|
||||||
|
log.debug("Get contacts for customer " + customerName);
|
||||||
|
tm.begin();
|
||||||
|
try {
|
||||||
|
|
||||||
|
Session session = getSessions().getCurrentSession();
|
||||||
|
List results = session.createQuery(selectHQL).setFlushMode(FlushMode.AUTO).setParameter("cName", customerName)
|
||||||
|
.list();
|
||||||
|
tm.commit();
|
||||||
|
return results;
|
||||||
|
} catch (Exception e) {
|
||||||
|
tm.rollback();
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Integer> getContactsByTLF(String tlf) throws Exception {
|
||||||
|
String selectHQL = "select contact.id from Contact contact";
|
||||||
|
selectHQL += " where contact.tlf = :cTLF";
|
||||||
|
|
||||||
|
tm.begin();
|
||||||
|
try {
|
||||||
|
|
||||||
|
Session session = getSessions().getCurrentSession();
|
||||||
|
List results = session.createQuery(selectHQL).setFlushMode(FlushMode.AUTO).setParameter("cTLF", tlf).list();
|
||||||
|
tm.commit();
|
||||||
|
return results;
|
||||||
|
} catch (Exception e) {
|
||||||
|
tm.rollback();
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int updateContacts(String name, String newTLF) throws Exception {
|
||||||
|
String updateHQL = "update Contact set tlf = :cNewTLF where name = :cName";
|
||||||
|
|
||||||
|
tm.begin();
|
||||||
|
try {
|
||||||
|
|
||||||
|
Session session = getSessions().getCurrentSession();
|
||||||
|
int rowsAffected = session.createQuery(updateHQL).setFlushMode(FlushMode.AUTO).setParameter("cNewTLF", newTLF)
|
||||||
|
.setParameter("cName", name).executeUpdate();
|
||||||
|
tm.commit();
|
||||||
|
return rowsAffected;
|
||||||
|
} catch (Exception e) {
|
||||||
|
tm.rollback();
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Contact getContact(Integer id) throws Exception {
|
||||||
|
tm.begin();
|
||||||
|
try {
|
||||||
|
|
||||||
|
Session session = getSessions().getCurrentSession();
|
||||||
|
Contact contact = (Contact) session.get(Contact.class, id);
|
||||||
|
tm.commit();
|
||||||
|
return contact;
|
||||||
|
} catch (Exception e) {
|
||||||
|
tm.rollback();
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// public void cleanup() throws Exception {
|
||||||
|
// String deleteContactHQL = "delete from Contact";
|
||||||
|
// String deleteCustomerHQL = "delete from Customer";
|
||||||
|
// tm.begin();
|
||||||
|
// try {
|
||||||
|
// Session session = getSessions().getCurrentSession();
|
||||||
|
// session.createQuery(deleteContactHQL).setFlushMode(FlushMode.AUTO).executeUpdate();
|
||||||
|
// session.createQuery(deleteCustomerHQL).setFlushMode(FlushMode.AUTO).executeUpdate();
|
||||||
|
// tm.commit();
|
||||||
|
// } catch (Exception e) {
|
||||||
|
// try {
|
||||||
|
// tm.rollback();
|
||||||
|
// } catch (Exception ee) {
|
||||||
|
// // ignored
|
||||||
|
// }
|
||||||
|
// throw e;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
public void cleanup(boolean ignore) throws Exception {
|
||||||
|
String deleteContactHQL = "delete from Contact";
|
||||||
|
String deleteCustomerHQL = "delete from Customer";
|
||||||
|
tm.begin();
|
||||||
|
try {
|
||||||
|
Session session = getSessions().getCurrentSession();
|
||||||
|
session.createQuery(deleteContactHQL).setFlushMode(FlushMode.AUTO).executeUpdate();
|
||||||
|
session.createQuery(deleteCustomerHQL).setFlushMode(FlushMode.AUTO).executeUpdate();
|
||||||
|
tm.commit();
|
||||||
|
} catch (Exception e) {
|
||||||
|
if (!ignore) {
|
||||||
|
try {
|
||||||
|
tm.rollback();
|
||||||
|
} catch (Exception ee) {
|
||||||
|
// ignored
|
||||||
|
}
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Customer createCustomer(int id) throws Exception {
|
||||||
|
System.out.println("CREATE CUSTOMER " + id);
|
||||||
|
try {
|
||||||
|
Customer customer = new Customer();
|
||||||
|
customer.setName((id % 2 == 0) ? "JBoss" : "Red Hat");
|
||||||
|
Set<Contact> contacts = new HashSet<Contact>();
|
||||||
|
|
||||||
|
Contact kabir = new Contact();
|
||||||
|
kabir.setCustomer(customer);
|
||||||
|
kabir.setName("Kabir");
|
||||||
|
kabir.setTlf("1111");
|
||||||
|
contacts.add(kabir);
|
||||||
|
|
||||||
|
Contact bill = new Contact();
|
||||||
|
bill.setCustomer(customer);
|
||||||
|
bill.setName("Bill");
|
||||||
|
bill.setTlf("2222");
|
||||||
|
contacts.add(bill);
|
||||||
|
|
||||||
|
customer.setContacts(contacts);
|
||||||
|
|
||||||
|
Session s = openSession();
|
||||||
|
s.getTransaction().begin();
|
||||||
|
s.persist(customer);
|
||||||
|
s.getTransaction().commit();
|
||||||
|
s.close();
|
||||||
|
|
||||||
|
return customer;
|
||||||
|
} finally {
|
||||||
|
System.out.println("CREATE CUSTOMER " + id + " - END");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,122 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2007, Red Hat, Inc. and/or it's affiliates or third-party contributors as
|
||||||
|
* indicated by the @author tags or express copyright attribution
|
||||||
|
* statements applied by the authors. All third-party contributions are
|
||||||
|
* distributed under license by Red Hat, Inc. and/or it's affiliates.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||||
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
* Lesser General Public License, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this distribution; if not, write to:
|
||||||
|
* Free Software Foundation, Inc.
|
||||||
|
* 51 Franklin Street, Fifth Floor
|
||||||
|
* Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
package org.hibernate.test.cache.infinispan.functional.classloader;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Comment
|
||||||
|
*
|
||||||
|
* @author Brian Stansberry
|
||||||
|
*/
|
||||||
|
public class Account implements Serializable {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
private Integer id;
|
||||||
|
private AccountHolder accountHolder;
|
||||||
|
private Integer balance;
|
||||||
|
private String branch;
|
||||||
|
|
||||||
|
public Integer getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Integer id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AccountHolder getAccountHolder() {
|
||||||
|
return accountHolder;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAccountHolder(AccountHolder accountHolder) {
|
||||||
|
this.accountHolder = accountHolder;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getBalance() {
|
||||||
|
return balance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBalance(Integer balance) {
|
||||||
|
this.balance = balance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getBranch() {
|
||||||
|
return branch;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBranch(String branch) {
|
||||||
|
this.branch = branch;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (obj == this)
|
||||||
|
return true;
|
||||||
|
if (!(obj instanceof Account))
|
||||||
|
return false;
|
||||||
|
Account acct = (Account) obj;
|
||||||
|
if (!safeEquals(id, acct.id))
|
||||||
|
return false;
|
||||||
|
if (!safeEquals(branch, acct.branch))
|
||||||
|
return false;
|
||||||
|
if (!safeEquals(balance, acct.balance))
|
||||||
|
return false;
|
||||||
|
if (!safeEquals(accountHolder, acct.accountHolder))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int hashCode() {
|
||||||
|
int result = 17;
|
||||||
|
result = result * 31 + safeHashCode(id);
|
||||||
|
result = result * 31 + safeHashCode(branch);
|
||||||
|
result = result * 31 + safeHashCode(balance);
|
||||||
|
result = result * 31 + safeHashCode(accountHolder);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
StringBuffer sb = new StringBuffer(getClass().getName());
|
||||||
|
sb.append("[id=");
|
||||||
|
sb.append(id);
|
||||||
|
sb.append(",branch=");
|
||||||
|
sb.append(branch);
|
||||||
|
sb.append(",balance=");
|
||||||
|
sb.append(balance);
|
||||||
|
sb.append(",accountHolder=");
|
||||||
|
sb.append(accountHolder);
|
||||||
|
sb.append("]");
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int safeHashCode(Object obj) {
|
||||||
|
return obj == null ? 0 : obj.hashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean safeEquals(Object a, Object b) {
|
||||||
|
return (a == b || (a != null && a.equals(b)));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,96 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2007, Red Hat, Inc. and/or it's affiliates or third-party contributors as
|
||||||
|
* indicated by the @author tags or express copyright attribution
|
||||||
|
* statements applied by the authors. All third-party contributions are
|
||||||
|
* distributed under license by Red Hat, Inc. and/or it's affiliates.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||||
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
* Lesser General Public License, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this distribution; if not, write to:
|
||||||
|
* Free Software Foundation, Inc.
|
||||||
|
* 51 Franklin Street, Fifth Floor
|
||||||
|
* Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
package org.hibernate.test.cache.infinispan.functional.classloader;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.ObjectInputStream;
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Comment
|
||||||
|
*
|
||||||
|
* @author Brian Stansberry
|
||||||
|
*/
|
||||||
|
public class AccountHolder implements Serializable
|
||||||
|
{
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
private String lastName;
|
||||||
|
private String ssn;
|
||||||
|
private transient boolean deserialized;
|
||||||
|
|
||||||
|
public AccountHolder( ) {
|
||||||
|
this("Stansberry", "123-456-7890");
|
||||||
|
}
|
||||||
|
|
||||||
|
public AccountHolder(String lastName, String ssn)
|
||||||
|
{
|
||||||
|
this.lastName = lastName;
|
||||||
|
this.ssn = ssn;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLastName( ) { return this.lastName; }
|
||||||
|
public void setLastName(String lastName) { this.lastName = lastName; }
|
||||||
|
|
||||||
|
public String getSsn( ) { return ssn; }
|
||||||
|
public void setSsn(String ssn) { this.ssn = ssn; }
|
||||||
|
|
||||||
|
public boolean equals(Object obj)
|
||||||
|
{
|
||||||
|
if (obj == this) return true;
|
||||||
|
if (!(obj instanceof AccountHolder)) return false;
|
||||||
|
AccountHolder pk = (AccountHolder)obj;
|
||||||
|
if (!lastName.equals(pk.lastName)) return false;
|
||||||
|
if (!ssn.equals(pk.ssn)) return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int hashCode( )
|
||||||
|
{
|
||||||
|
int result = 17;
|
||||||
|
result = result * 31 + lastName.hashCode();
|
||||||
|
result = result * 31 + ssn.hashCode();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
StringBuffer sb = new StringBuffer(getClass().getName());
|
||||||
|
sb.append("[lastName=");
|
||||||
|
sb.append(lastName);
|
||||||
|
sb.append(",ssn=");
|
||||||
|
sb.append(ssn);
|
||||||
|
sb.append(",deserialized=");
|
||||||
|
sb.append(deserialized);
|
||||||
|
sb.append("]");
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException
|
||||||
|
{
|
||||||
|
ois.defaultReadObject();
|
||||||
|
deserialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,105 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2008, Red Hat, Inc. and/or it's affiliates or third-party contributors as
|
||||||
|
* indicated by the @author tags or express copyright attribution
|
||||||
|
* statements applied by the authors. All third-party contributions are
|
||||||
|
* distributed under license by Red Hat, Inc. and/or it's affiliates.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||||
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
* Lesser General Public License, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this distribution; if not, write to:
|
||||||
|
* Free Software Foundation, Inc.
|
||||||
|
* 51 Franklin Street, Fifth Floor
|
||||||
|
* Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
package org.hibernate.test.cache.infinispan.functional.classloader;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.infinispan.notifications.Listener;
|
||||||
|
import org.infinispan.notifications.cachelistener.annotation.CacheEntryCreated;
|
||||||
|
import org.infinispan.notifications.cachelistener.annotation.CacheEntryModified;
|
||||||
|
import org.infinispan.notifications.cachelistener.annotation.CacheEntryVisited;
|
||||||
|
import org.infinispan.notifications.cachelistener.event.CacheEntryCreatedEvent;
|
||||||
|
import org.infinispan.notifications.cachelistener.event.CacheEntryModifiedEvent;
|
||||||
|
import org.infinispan.notifications.cachelistener.event.CacheEntryVisitedEvent;
|
||||||
|
|
||||||
|
@Listener
|
||||||
|
public class CacheAccessListener {
|
||||||
|
// HashSet<Fqn<String>> modified = new HashSet<Fqn<String>>();
|
||||||
|
// HashSet<Fqn<String>> accessed = new HashSet<Fqn<String>>();
|
||||||
|
HashSet modified = new HashSet();
|
||||||
|
HashSet accessed = new HashSet();
|
||||||
|
|
||||||
|
public void clear() {
|
||||||
|
modified.clear();
|
||||||
|
accessed.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
@CacheEntryModified
|
||||||
|
public void nodeModified(CacheEntryModifiedEvent event) {
|
||||||
|
if (!event.isPre()) {
|
||||||
|
Object key = event.getKey();
|
||||||
|
System.out.println("MyListener - Modified node " + key);
|
||||||
|
modified.add(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@CacheEntryCreated
|
||||||
|
public void nodeCreated(CacheEntryCreatedEvent event) {
|
||||||
|
if (!event.isPre()) {
|
||||||
|
Object key = event.getKey();
|
||||||
|
System.out.println("MyListener - Created node " + key);
|
||||||
|
modified.add(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@CacheEntryVisited
|
||||||
|
public void nodeVisited(CacheEntryVisitedEvent event) {
|
||||||
|
if (!event.isPre()) {
|
||||||
|
Object key = event.getKey();
|
||||||
|
System.out.println("MyListener - Visited node " + key);
|
||||||
|
accessed.add(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean getSawRegionModification(Object key) {
|
||||||
|
return getSawRegion(key, modified);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean getSawRegionAccess(Object key) {
|
||||||
|
return getSawRegion(key, accessed);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean getSawRegion(Object key, Set sawEvents) {
|
||||||
|
if (sawEvents.contains(key)) {
|
||||||
|
sawEvents.remove(key);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
// boolean saw = false;
|
||||||
|
// for (Object key : sawEvents) {
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
// Fqn<String> fqn = Fqn.fromString(regionName);
|
||||||
|
// for (Iterator<Fqn<String>> it = sawEvent.iterator(); it.hasNext();) {
|
||||||
|
// Fqn<String> modified = (Fqn<String>) it.next();
|
||||||
|
// if (modified.isChildOf(fqn)) {
|
||||||
|
// it.remove();
|
||||||
|
// saw = true;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// return saw;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,295 @@
|
||||||
|
/*
|
||||||
|
* JBoss, Home of Professional Open Source.
|
||||||
|
* Copyright 2006, Red Hat, Inc. and/or it's affiliates, and individual contributors
|
||||||
|
* as indicated by the @author tags. See the copyright.txt file in the
|
||||||
|
* distribution for a full listing of individual contributors.
|
||||||
|
*
|
||||||
|
* This is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU Lesser General Public License as
|
||||||
|
* published by the Free Software Foundation; either version 2.1 of
|
||||||
|
* the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This software is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this software; if not, write to the Free
|
||||||
|
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||||
|
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
|
||||||
|
*/
|
||||||
|
package org.hibernate.test.cache.infinispan.functional.classloader;
|
||||||
|
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import javax.transaction.TransactionManager;
|
||||||
|
|
||||||
|
import org.hibernate.Query;
|
||||||
|
import org.hibernate.Session;
|
||||||
|
import org.hibernate.SessionFactory;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Comment
|
||||||
|
*
|
||||||
|
* @author Brian Stansberry
|
||||||
|
*/
|
||||||
|
public class ClassLoaderTestDAO {
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(ClassLoaderTestDAO.class);
|
||||||
|
|
||||||
|
private SessionFactory sessionFactory;
|
||||||
|
private TransactionManager tm;
|
||||||
|
|
||||||
|
private Class acctClass;
|
||||||
|
private Class holderClass;
|
||||||
|
private Method setId;
|
||||||
|
private Method setBalance;
|
||||||
|
private Method setBranch;
|
||||||
|
private Method setHolder;
|
||||||
|
private Object smith;
|
||||||
|
private Object jones;
|
||||||
|
private Object barney;
|
||||||
|
private Method setName;
|
||||||
|
private Method setSsn;
|
||||||
|
|
||||||
|
public ClassLoaderTestDAO(SessionFactory factory, TransactionManager tm) throws Exception {
|
||||||
|
this.sessionFactory = factory;
|
||||||
|
this.tm = tm;
|
||||||
|
|
||||||
|
acctClass = Thread.currentThread().getContextClassLoader().loadClass(
|
||||||
|
getClass().getPackage().getName() + ".Account");
|
||||||
|
holderClass = Thread.currentThread().getContextClassLoader().loadClass(
|
||||||
|
getClass().getPackage().getName() + ".AccountHolder");
|
||||||
|
setId = acctClass.getMethod("setId", Integer.class);
|
||||||
|
setBalance = acctClass.getMethod("setBalance", Integer.class);
|
||||||
|
setBranch = acctClass.getMethod("setBranch", String.class);
|
||||||
|
setHolder = acctClass.getMethod("setAccountHolder", holderClass);
|
||||||
|
|
||||||
|
setName = holderClass.getMethod("setLastName", String.class);
|
||||||
|
setSsn = holderClass.getMethod("setSsn", String.class);
|
||||||
|
|
||||||
|
smith = holderClass.newInstance();
|
||||||
|
setName.invoke(smith, "Smith");
|
||||||
|
setSsn.invoke(smith, "1000");
|
||||||
|
|
||||||
|
jones = holderClass.newInstance();
|
||||||
|
setName.invoke(jones, "Jones");
|
||||||
|
setSsn.invoke(jones, "2000");
|
||||||
|
|
||||||
|
barney = holderClass.newInstance();
|
||||||
|
setName.invoke(barney, "Barney");
|
||||||
|
setSsn.invoke(barney, "3000");
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object getSmith() {
|
||||||
|
return smith;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object getJones() {
|
||||||
|
return jones;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object getBarney() {
|
||||||
|
return barney;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateAccountBranch(Integer id, String branch) throws Exception {
|
||||||
|
log.debug("Updating account " + id + " to branch " + branch);
|
||||||
|
tm.begin();
|
||||||
|
try {
|
||||||
|
Session session = sessionFactory.getCurrentSession();
|
||||||
|
Object account = session.get(acctClass, id);
|
||||||
|
log.debug("Set branch " + branch);
|
||||||
|
setBranch.invoke(account, branch);
|
||||||
|
session.update(account);
|
||||||
|
tm.commit();
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("rolling back", e);
|
||||||
|
tm.rollback();
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
log.debug("Updated account " + id + " to branch " + branch);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getCountForBranch(String branch, boolean useRegion) throws Exception {
|
||||||
|
tm.begin();
|
||||||
|
try {
|
||||||
|
Query query = sessionFactory.getCurrentSession().createQuery(
|
||||||
|
"select account from Account as account where account.branch = :branch");
|
||||||
|
query.setString("branch", branch);
|
||||||
|
if (useRegion) {
|
||||||
|
query.setCacheRegion("AccountRegion");
|
||||||
|
}
|
||||||
|
query.setCacheable(true);
|
||||||
|
int result = query.list().size();
|
||||||
|
tm.commit();
|
||||||
|
return result;
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("rolling back", e);
|
||||||
|
tm.rollback();
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void createAccount(Object holder, Integer id, Integer openingBalance, String branch) throws Exception {
|
||||||
|
log.debug("Creating account " + id);
|
||||||
|
tm.begin();
|
||||||
|
try {
|
||||||
|
Object account = acctClass.newInstance();
|
||||||
|
setId.invoke(account, id);
|
||||||
|
setHolder.invoke(account, holder);
|
||||||
|
setBalance.invoke(account, openingBalance);
|
||||||
|
log.debug("Set branch " + branch);
|
||||||
|
setBranch.invoke(account, branch);
|
||||||
|
sessionFactory.getCurrentSession().persist(account);
|
||||||
|
tm.commit();
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("rolling back", e);
|
||||||
|
tm.rollback();
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
|
||||||
|
log.debug("Created account " + id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Account getAccount(Integer id) throws Exception {
|
||||||
|
log.debug("Getting account " + id);
|
||||||
|
tm.begin();
|
||||||
|
try {
|
||||||
|
Session session = sessionFactory.getCurrentSession();
|
||||||
|
Account acct = (Account) session.get(acctClass, id);
|
||||||
|
tm.commit();
|
||||||
|
return acct;
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("rolling back", e);
|
||||||
|
tm.rollback();
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Account getAccountWithRefresh(Integer id) throws Exception {
|
||||||
|
log.debug("Getting account " + id + " with refresh");
|
||||||
|
tm.begin();
|
||||||
|
try {
|
||||||
|
Session session = sessionFactory.getCurrentSession();
|
||||||
|
Account acct = (Account) session.get(acctClass, id);
|
||||||
|
session.refresh(acct);
|
||||||
|
acct = (Account) session.get(acctClass, id);
|
||||||
|
tm.commit();
|
||||||
|
return acct;
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("rolling back", e);
|
||||||
|
tm.rollback();
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateAccountBalance(Integer id, Integer newBalance) throws Exception {
|
||||||
|
log.debug("Updating account " + id + " to balance " + newBalance);
|
||||||
|
tm.begin();
|
||||||
|
try {
|
||||||
|
Session session = sessionFactory.getCurrentSession();
|
||||||
|
Object account = session.get(acctClass, id);
|
||||||
|
setBalance.invoke(account, newBalance);
|
||||||
|
session.update(account);
|
||||||
|
tm.commit();
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("rolling back", e);
|
||||||
|
tm.rollback();
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
log.debug("Updated account " + id + " to balance " + newBalance);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getBranch(Object holder, boolean useRegion) throws Exception {
|
||||||
|
tm.begin();
|
||||||
|
try {
|
||||||
|
Query query = sessionFactory.getCurrentSession().createQuery(
|
||||||
|
"select account.branch from Account as account where account.accountHolder = ?");
|
||||||
|
query.setParameter(0, holder);
|
||||||
|
if (useRegion) {
|
||||||
|
query.setCacheRegion("AccountRegion");
|
||||||
|
}
|
||||||
|
query.setCacheable(true);
|
||||||
|
String result = (String) query.list().get(0);
|
||||||
|
tm.commit();
|
||||||
|
return result;
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("rolling back", e);
|
||||||
|
tm.rollback();
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getTotalBalance(Object holder, boolean useRegion) throws Exception {
|
||||||
|
List results = null;
|
||||||
|
tm.begin();
|
||||||
|
try {
|
||||||
|
Query query = sessionFactory.getCurrentSession().createQuery(
|
||||||
|
"select account.balance from Account as account where account.accountHolder = ?");
|
||||||
|
query.setParameter(0, holder);
|
||||||
|
if (useRegion) {
|
||||||
|
query.setCacheRegion("AccountRegion");
|
||||||
|
}
|
||||||
|
query.setCacheable(true);
|
||||||
|
results = query.list();
|
||||||
|
tm.commit();
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("rolling back", e);
|
||||||
|
tm.rollback();
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
|
||||||
|
int total = 0;
|
||||||
|
if (results != null) {
|
||||||
|
for (Iterator it = results.iterator(); it.hasNext();) {
|
||||||
|
total += ((Integer) it.next()).intValue();
|
||||||
|
System.out.println("Total = " + total);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return total;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void cleanup() throws Exception {
|
||||||
|
internalCleanup();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void internalCleanup() throws Exception {
|
||||||
|
if (sessionFactory != null) {
|
||||||
|
tm.begin();
|
||||||
|
try {
|
||||||
|
|
||||||
|
Session session = sessionFactory.getCurrentSession();
|
||||||
|
Query query = session.createQuery("select account from Account as account");
|
||||||
|
List accts = query.list();
|
||||||
|
if (accts != null) {
|
||||||
|
for (Iterator it = accts.iterator(); it.hasNext();) {
|
||||||
|
try {
|
||||||
|
Object acct = it.next();
|
||||||
|
log.info("Removing " + acct);
|
||||||
|
session.delete(acct);
|
||||||
|
} catch (Exception ignored) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tm.commit();
|
||||||
|
} catch (Exception e) {
|
||||||
|
tm.rollback();
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void remove() {
|
||||||
|
try {
|
||||||
|
internalCleanup();
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Caught exception in remove", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,90 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2007, Red Hat, Inc. and/or it's affiliates. 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.infinispan.functional.classloader;
|
||||||
|
|
||||||
|
import org.hibernate.test.cache.infinispan.functional.cluster.ClusterAwareRegionFactory;
|
||||||
|
import org.hibernate.test.cache.infinispan.functional.cluster.DualNodeJtaTransactionManagerImpl;
|
||||||
|
|
||||||
|
import junit.framework.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A TestSetup that uses SelectedClassnameClassLoader to ensure that certain classes are not visible
|
||||||
|
* to JBoss Cache or JGroups' classloader.
|
||||||
|
*
|
||||||
|
* @author <a href="brian.stansberry@jboss.com">Brian Stansberry</a>
|
||||||
|
*/
|
||||||
|
public class IsolatedCacheTestSetup extends SelectedClassnameClassLoaderTestSetup {
|
||||||
|
|
||||||
|
private String[] isolatedClasses;
|
||||||
|
private String cacheConfig;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new IsolatedCacheTestSetup.
|
||||||
|
*/
|
||||||
|
public IsolatedCacheTestSetup(Test test, String[] isolatedClasses, String cacheConfig) {
|
||||||
|
super(test, null, null, isolatedClasses);
|
||||||
|
this.isolatedClasses = isolatedClasses;
|
||||||
|
this.cacheConfig = cacheConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void setUp() throws Exception {
|
||||||
|
super.setUp();
|
||||||
|
|
||||||
|
// // At this point the TCCL cannot see the isolatedClasses
|
||||||
|
// // We want the caches to use this CL as their default classloader
|
||||||
|
|
||||||
|
ClassLoader tccl = Thread.currentThread().getContextClassLoader();
|
||||||
|
|
||||||
|
// org.jgroups.ChannelFactory cf = new org.jgroups.JChannelFactory();
|
||||||
|
// cf.setMultiplexerConfig(DEF_JGROUPS_RESOURCE);
|
||||||
|
//
|
||||||
|
// // Use a CacheManager that will inject the desired defaultClassLoader into our caches
|
||||||
|
// CustomClassLoaderCacheManager cm = new CustomClassLoaderCacheManager(DEF_CACHE_FACTORY_RESOURCE, cf, tccl);
|
||||||
|
// cm.start();
|
||||||
|
// TestCacheInstanceManager.addTestCacheManager(DualNodeTestUtil.LOCAL, cm);
|
||||||
|
//
|
||||||
|
// cm.getCache(cacheConfig, true);
|
||||||
|
//
|
||||||
|
// // Repeat for the "remote" cache
|
||||||
|
//
|
||||||
|
// cf = new org.jgroups.JChannelFactory();
|
||||||
|
// cf.setMultiplexerConfig(DEF_JGROUPS_RESOURCE);
|
||||||
|
//
|
||||||
|
// cm = new CustomClassLoaderCacheManager(DEF_CACHE_FACTORY_RESOURCE, cf, tccl);
|
||||||
|
// cm.start();
|
||||||
|
// TestCacheInstanceManager.addTestCacheManager(DualNodeTestUtil.REMOTE, cm);
|
||||||
|
//
|
||||||
|
// cm.getCache(cacheConfig, true);
|
||||||
|
|
||||||
|
// Now make the isolatedClasses visible to the test driver itself
|
||||||
|
SelectedClassnameClassLoader visible = new SelectedClassnameClassLoader(isolatedClasses, null, null, tccl);
|
||||||
|
Thread.currentThread().setContextClassLoader(visible);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void tearDown() throws Exception {
|
||||||
|
try {
|
||||||
|
super.tearDown();
|
||||||
|
} finally {
|
||||||
|
ClusterAwareRegionFactory.clearCacheManagers();
|
||||||
|
DualNodeJtaTransactionManagerImpl.cleanupTransactions();
|
||||||
|
DualNodeJtaTransactionManagerImpl.cleanupTransactionManagers();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,331 @@
|
||||||
|
/*
|
||||||
|
* JBoss, Home of Professional Open Source.
|
||||||
|
* Copyright 2009, Red Hat, Inc. and/or it's affiliates, and individual contributors
|
||||||
|
* as indicated by the @author tags. See the copyright.txt file in the
|
||||||
|
* distribution for a full listing of individual contributors.
|
||||||
|
*
|
||||||
|
* This is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU Lesser General Public License as
|
||||||
|
* published by the Free Software Foundation; either version 2.1 of
|
||||||
|
* the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This software is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this software; if not, write to the Free
|
||||||
|
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||||
|
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
|
||||||
|
*/
|
||||||
|
package org.hibernate.test.cache.infinispan.functional.classloader;
|
||||||
|
|
||||||
|
import javax.transaction.TransactionManager;
|
||||||
|
|
||||||
|
import junit.framework.Test;
|
||||||
|
import junit.framework.TestSuite;
|
||||||
|
|
||||||
|
import org.hibernate.SessionFactory;
|
||||||
|
import org.hibernate.cache.StandardQueryCache;
|
||||||
|
import org.hibernate.test.cache.infinispan.functional.cluster.AbstractDualNodeTestCase;
|
||||||
|
import org.hibernate.test.cache.infinispan.functional.cluster.ClusterAwareRegionFactory;
|
||||||
|
import org.hibernate.test.cache.infinispan.functional.cluster.DualNodeJtaTransactionManagerImpl;
|
||||||
|
import org.infinispan.Cache;
|
||||||
|
import org.infinispan.manager.CacheManager;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests entity and query caching when class of objects being cached are not visible to Infinispan's
|
||||||
|
* classloader. Also serves as a general integration test.
|
||||||
|
* <p/>
|
||||||
|
* This test stores an object (AccountHolder) that isn't visible to the Infinispan classloader in
|
||||||
|
* the cache in two places:
|
||||||
|
*
|
||||||
|
* 1) As part of the value tuple in an Account entity 2) As part of the FQN in a query cache entry
|
||||||
|
* (see query in ClassLoaderTestDAO.getBranch())
|
||||||
|
*
|
||||||
|
* @author Galder Zamarreño
|
||||||
|
* @since 3.5
|
||||||
|
*/
|
||||||
|
public class IsolatedClassLoaderTest extends AbstractDualNodeTestCase {
|
||||||
|
|
||||||
|
public static final String OUR_PACKAGE = IsolatedClassLoaderTest.class.getPackage().getName();
|
||||||
|
|
||||||
|
private static final String CACHE_CONFIG = "replicated-query";
|
||||||
|
|
||||||
|
protected static final long SLEEP_TIME = 300L;
|
||||||
|
|
||||||
|
protected final Logger log = LoggerFactory.getLogger(getClass());
|
||||||
|
|
||||||
|
static int test = 0;
|
||||||
|
|
||||||
|
private Cache localQueryCache ;
|
||||||
|
private CacheAccessListener localQueryListener;
|
||||||
|
|
||||||
|
private Cache remoteQueryCache;
|
||||||
|
private CacheAccessListener remoteQueryListener;
|
||||||
|
|
||||||
|
public IsolatedClassLoaderTest(String string) {
|
||||||
|
super(string);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Test suite() throws Exception {
|
||||||
|
TestSuite suite = new TestSuite(IsolatedClassLoaderTest.class);
|
||||||
|
String[] acctClasses = { OUR_PACKAGE + ".Account", OUR_PACKAGE + ".AccountHolder" };
|
||||||
|
return new IsolatedCacheTestSetup(suite, acctClasses, CACHE_CONFIG);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String[] getMappings() {
|
||||||
|
return new String[] { "cache/infinispan/functional/classloader/Account.hbm.xml" };
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void cleanupTransactionManagement() {
|
||||||
|
// Don't clean up the managers, just the transactions
|
||||||
|
// Managers are still needed by the long-lived caches
|
||||||
|
DualNodeJtaTransactionManagerImpl.cleanupTransactions();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void cleanupTest() throws Exception {
|
||||||
|
try {
|
||||||
|
if (localQueryCache != null && localQueryListener != null)
|
||||||
|
localQueryCache.removeListener(localQueryListener);
|
||||||
|
if (remoteQueryCache != null && remoteQueryListener != null)
|
||||||
|
remoteQueryCache.removeListener(remoteQueryListener);
|
||||||
|
} finally {
|
||||||
|
super.cleanupTest();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simply confirms that the test fixture's classloader isolation setup is functioning as
|
||||||
|
* expected.
|
||||||
|
*
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public void testIsolatedSetup() throws Exception {
|
||||||
|
// Bind a listener to the "local" cache
|
||||||
|
// Our region factory makes its CacheManager available to us
|
||||||
|
CacheManager localManager = ClusterAwareRegionFactory.getCacheManager(AbstractDualNodeTestCase.LOCAL);
|
||||||
|
Cache localAccountCache = localManager.getCache(Account.class.getName());
|
||||||
|
Cache localAccountHolderCache = localManager.getCache(AccountHolder.class.getName());
|
||||||
|
|
||||||
|
// Bind a listener to the "remote" cache
|
||||||
|
CacheManager remoteManager = ClusterAwareRegionFactory.getCacheManager(AbstractDualNodeTestCase.REMOTE);
|
||||||
|
Cache remoteAccountCache = remoteManager.getCache(Account.class.getName());
|
||||||
|
Cache remoteAccountHolderCache = remoteManager.getCache(AccountHolder.class.getName());
|
||||||
|
|
||||||
|
ClassLoader cl = Thread.currentThread().getContextClassLoader();
|
||||||
|
log.info("TCCL is " + cl);
|
||||||
|
Thread.currentThread().setContextClassLoader(cl.getParent());
|
||||||
|
|
||||||
|
// org.jboss.cache.Fqn fqn = org.jboss.cache.Fqn.fromString("/isolated1");
|
||||||
|
// org.jboss.cache.Region r = localCache.getRegion(fqn, true);
|
||||||
|
// r.registerContextClassLoader(cl.getParent());
|
||||||
|
// r.activate();
|
||||||
|
//
|
||||||
|
// r = remoteCache.getRegion(fqn, true);
|
||||||
|
// r.registerContextClassLoader(cl.getParent());
|
||||||
|
// r.activate();
|
||||||
|
// Thread.currentThread().setContextClassLoader(cl);
|
||||||
|
Account acct = new Account();
|
||||||
|
acct.setAccountHolder(new AccountHolder());
|
||||||
|
|
||||||
|
try {
|
||||||
|
localAccountCache.put("isolated1", acct);
|
||||||
|
fail("Should not have succeeded in putting acct -- classloader not isolated");
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.info("Caught exception as desired", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
// localCache.getRegion(fqn,
|
||||||
|
// false).registerContextClassLoader(Thread.currentThread().getContextClassLoader());
|
||||||
|
// remoteCache.getRegion(fqn,
|
||||||
|
// false).registerContextClassLoader(Thread.currentThread().getContextClassLoader());
|
||||||
|
|
||||||
|
Thread.currentThread().setContextClassLoader(cl);
|
||||||
|
localAccountCache.put("isolated1", acct);
|
||||||
|
assertEquals(acct.getClass().getName(), remoteAccountCache.get("isolated1").getClass().getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testClassLoaderHandlingNamedQueryRegion() throws Exception {
|
||||||
|
queryTest(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testClassLoaderHandlingStandardQueryCache() throws Exception {
|
||||||
|
queryTest(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void queryTest(boolean useNamedRegion) throws Exception {
|
||||||
|
// Bind a listener to the "local" cache
|
||||||
|
// Our region factory makes its CacheManager available to us
|
||||||
|
CacheManager localManager = ClusterAwareRegionFactory.getCacheManager(AbstractDualNodeTestCase.LOCAL);
|
||||||
|
localQueryCache = localManager.getCache("local-query");
|
||||||
|
localQueryListener = new CacheAccessListener();
|
||||||
|
localQueryCache.addListener(localQueryListener);
|
||||||
|
|
||||||
|
TransactionManager localTM = DualNodeJtaTransactionManagerImpl.getInstance(AbstractDualNodeTestCase.LOCAL);
|
||||||
|
|
||||||
|
// Bind a listener to the "remote" cache
|
||||||
|
CacheManager remoteManager = ClusterAwareRegionFactory.getCacheManager(AbstractDualNodeTestCase.REMOTE);
|
||||||
|
remoteQueryCache = remoteManager.getCache("local-query");
|
||||||
|
remoteQueryListener = new CacheAccessListener();
|
||||||
|
remoteQueryCache.addListener(remoteQueryListener);
|
||||||
|
|
||||||
|
TransactionManager remoteTM = DualNodeJtaTransactionManagerImpl.getInstance(AbstractDualNodeTestCase.REMOTE);
|
||||||
|
|
||||||
|
SessionFactory localFactory = getEnvironment().getSessionFactory();
|
||||||
|
SessionFactory remoteFactory = getSecondNodeEnvironment().getSessionFactory();
|
||||||
|
|
||||||
|
ClassLoaderTestDAO dao0 = new ClassLoaderTestDAO(localFactory, localTM);
|
||||||
|
ClassLoaderTestDAO dao1 = new ClassLoaderTestDAO(remoteFactory, remoteTM);
|
||||||
|
|
||||||
|
// // Determine whether our query region is already there (in which case it
|
||||||
|
// // will receive remote messages immediately) or is yet to be created on
|
||||||
|
// // first use (in which case it will initially discard remote messages)
|
||||||
|
// String regionName = createRegionName(useNamedRegion ? "AccountRegion" : StandardQueryCache.class.getName());
|
||||||
|
// Region queryRegion = remoteCache.getRegion(Fqn.fromString(regionName), false);
|
||||||
|
// boolean queryRegionExists = queryRegion != null && queryRegion.isActive();
|
||||||
|
|
||||||
|
// Initial ops on node 0
|
||||||
|
setupEntities(dao0);
|
||||||
|
|
||||||
|
// Query on post code count
|
||||||
|
assertEquals("63088 has correct # of accounts", 6, dao0.getCountForBranch("63088", useNamedRegion));
|
||||||
|
|
||||||
|
assertTrue("Query cache used ", localQueryListener.getSawRegionModification("???"));
|
||||||
|
// Clear the access state
|
||||||
|
localQueryListener.getSawRegionAccess("???");
|
||||||
|
|
||||||
|
log.info("First query on node0 done");
|
||||||
|
|
||||||
|
// Sleep a bit to allow async repl to happen
|
||||||
|
sleep(SLEEP_TIME);
|
||||||
|
|
||||||
|
// // If region isn't activated yet, should not have been modified
|
||||||
|
// if (!queryRegionExists) {
|
||||||
|
assertFalse("Query cache remotely modified", remoteQueryListener.getSawRegionModification("???"));
|
||||||
|
// Clear the access state
|
||||||
|
remoteQueryListener.getSawRegionAccess("???");
|
||||||
|
// } else {
|
||||||
|
assertTrue("Query cache remotely modified ", remoteQueryListener.getSawRegionModification("???"));
|
||||||
|
// Clear the access state
|
||||||
|
remoteQueryListener.getSawRegionAccess("???");
|
||||||
|
// }
|
||||||
|
|
||||||
|
// Do query again from node 1
|
||||||
|
assertEquals("63088 has correct # of accounts", 6, dao1.getCountForBranch("63088", useNamedRegion));
|
||||||
|
|
||||||
|
// if (!queryRegionExists) {
|
||||||
|
// // Query should have activated the region and then been inserted
|
||||||
|
assertTrue("Query cache modified ", remoteQueryListener.getSawRegionModification("???"));
|
||||||
|
// Clear the access state
|
||||||
|
remoteQueryListener.getSawRegionAccess("???");
|
||||||
|
// }
|
||||||
|
|
||||||
|
log.info("First query on node 1 done");
|
||||||
|
|
||||||
|
// We now have the query cache region activated on both nodes.
|
||||||
|
|
||||||
|
// Sleep a bit to allow async repl to happen
|
||||||
|
sleep(SLEEP_TIME);
|
||||||
|
|
||||||
|
// Do some more queries on node 0
|
||||||
|
|
||||||
|
assertEquals("Correct branch for Smith", "94536", dao0.getBranch(dao0.getSmith(), useNamedRegion));
|
||||||
|
|
||||||
|
assertEquals("Correct high balances for Jones", 40, dao0.getTotalBalance(dao0.getJones(), useNamedRegion));
|
||||||
|
|
||||||
|
assertTrue("Query cache used ", localQueryListener.getSawRegionModification("???"));
|
||||||
|
// Clear the access state
|
||||||
|
localQueryListener.getSawRegionAccess("???");
|
||||||
|
|
||||||
|
log.info("Second set of queries on node0 done");
|
||||||
|
|
||||||
|
// Sleep a bit to allow async repl to happen
|
||||||
|
sleep(SLEEP_TIME);
|
||||||
|
|
||||||
|
// Check if the previous queries replicated
|
||||||
|
assertTrue("Query cache remotely modified ", remoteQueryListener.getSawRegionModification("???"));
|
||||||
|
// Clear the access state
|
||||||
|
remoteQueryListener.getSawRegionAccess("???");
|
||||||
|
|
||||||
|
// Do queries again from node 1
|
||||||
|
assertEquals("Correct branch for Smith", "94536", dao1.getBranch(dao1.getSmith(), useNamedRegion));
|
||||||
|
|
||||||
|
assertEquals("Correct high balances for Jones", 40, dao1.getTotalBalance(dao1.getJones(), useNamedRegion));
|
||||||
|
|
||||||
|
// Should be no change; query was already there
|
||||||
|
assertFalse("Query cache modified ", remoteQueryListener.getSawRegionModification("???"));
|
||||||
|
assertTrue("Query cache accessed ", remoteQueryListener.getSawRegionAccess("???"));
|
||||||
|
|
||||||
|
log.info("Second set of queries on node1 done");
|
||||||
|
|
||||||
|
// allow async to propagate
|
||||||
|
sleep(SLEEP_TIME);
|
||||||
|
|
||||||
|
// Modify underlying data on node 1
|
||||||
|
modifyEntities(dao1);
|
||||||
|
|
||||||
|
// allow async timestamp change to propagate
|
||||||
|
sleep(SLEEP_TIME);
|
||||||
|
|
||||||
|
// Confirm query results are correct on node 0
|
||||||
|
|
||||||
|
assertEquals("63088 has correct # of accounts", 7, dao0.getCountForBranch("63088", useNamedRegion));
|
||||||
|
|
||||||
|
assertEquals("Correct branch for Smith", "63088", dao0.getBranch(dao0.getSmith(), useNamedRegion));
|
||||||
|
|
||||||
|
assertEquals("Correct high balances for Jones", 50, dao0.getTotalBalance(dao0.getJones(), useNamedRegion));
|
||||||
|
|
||||||
|
log.info("Third set of queries on node0 done");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setupEntities(ClassLoaderTestDAO dao) throws Exception {
|
||||||
|
dao.cleanup();
|
||||||
|
|
||||||
|
dao.createAccount(dao.getSmith(), new Integer(1001), new Integer(5), "94536");
|
||||||
|
dao.createAccount(dao.getSmith(), new Integer(1002), new Integer(15), "94536");
|
||||||
|
dao.createAccount(dao.getSmith(), new Integer(1003), new Integer(20), "94536");
|
||||||
|
|
||||||
|
dao.createAccount(dao.getJones(), new Integer(2001), new Integer(5), "63088");
|
||||||
|
dao.createAccount(dao.getJones(), new Integer(2002), new Integer(15), "63088");
|
||||||
|
dao.createAccount(dao.getJones(), new Integer(2003), new Integer(20), "63088");
|
||||||
|
|
||||||
|
dao.createAccount(dao.getBarney(), new Integer(3001), new Integer(5), "63088");
|
||||||
|
dao.createAccount(dao.getBarney(), new Integer(3002), new Integer(15), "63088");
|
||||||
|
dao.createAccount(dao.getBarney(), new Integer(3003), new Integer(20), "63088");
|
||||||
|
|
||||||
|
log.info("Standard entities created");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void resetRegionUsageState(CacheAccessListener localListener, CacheAccessListener remoteListener) {
|
||||||
|
String stdName = StandardQueryCache.class.getName();
|
||||||
|
String acctName = Account.class.getName();
|
||||||
|
|
||||||
|
localListener.getSawRegionModification(stdName);
|
||||||
|
localListener.getSawRegionModification(acctName);
|
||||||
|
|
||||||
|
localListener.getSawRegionAccess(stdName);
|
||||||
|
localListener.getSawRegionAccess(acctName);
|
||||||
|
|
||||||
|
remoteListener.getSawRegionModification(stdName);
|
||||||
|
remoteListener.getSawRegionModification(acctName);
|
||||||
|
|
||||||
|
remoteListener.getSawRegionAccess(stdName);
|
||||||
|
remoteListener.getSawRegionAccess(acctName);
|
||||||
|
|
||||||
|
log.info("Region usage state cleared");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void modifyEntities(ClassLoaderTestDAO dao) throws Exception {
|
||||||
|
dao.updateAccountBranch(1001, "63088");
|
||||||
|
dao.updateAccountBalance(2001, 15);
|
||||||
|
|
||||||
|
log.info("Entities modified");
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,288 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2007, Red Hat, Inc. and/or it's affiliates or third-party contributors as
|
||||||
|
* indicated by the @author tags or express copyright attribution
|
||||||
|
* statements applied by the authors. All third-party contributions are
|
||||||
|
* distributed under license by Red Hat, Inc. and/or it's affiliates.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||||
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
* Lesser General Public License, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this distribution; if not, write to:
|
||||||
|
* Free Software Foundation, Inc.
|
||||||
|
* 51 Franklin Street, Fifth Floor
|
||||||
|
* Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
package org.hibernate.test.cache.infinispan.functional.classloader;
|
||||||
|
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A ClassLoader that loads classes whose classname begins with one of a
|
||||||
|
* given set of strings, without attempting first to delegate to its
|
||||||
|
* parent loader.
|
||||||
|
* <p>
|
||||||
|
* This class is intended to allow emulation of 2 different types of common J2EE
|
||||||
|
* classloading situations.
|
||||||
|
* <ul>
|
||||||
|
* <li>Servlet-style child-first classloading, where this class is the
|
||||||
|
* child loader.</li>
|
||||||
|
* <li>Parent-first classloading where the parent does not have access to
|
||||||
|
* certain classes</li>
|
||||||
|
* </ul>
|
||||||
|
* </p>
|
||||||
|
* <p>
|
||||||
|
* This class can also be configured to raise a ClassNotFoundException if
|
||||||
|
* asked to load certain classes, thus allowing classes on the classpath
|
||||||
|
* to be hidden from a test environment.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author Brian Stansberry
|
||||||
|
*/
|
||||||
|
public class SelectedClassnameClassLoader extends ClassLoader
|
||||||
|
{
|
||||||
|
private Logger log = LoggerFactory.getLogger(SelectedClassnameClassLoader.class);
|
||||||
|
|
||||||
|
private String[] includedClasses = null;
|
||||||
|
private String[] excludedClasses = null;
|
||||||
|
private String[] notFoundClasses = null;
|
||||||
|
|
||||||
|
private Map<String, Class> classes = new java.util.HashMap<String, Class>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new classloader that loads the given classes.
|
||||||
|
*
|
||||||
|
* @param includedClasses array of class or package names that should be
|
||||||
|
* directly loaded by this loader. Classes
|
||||||
|
* whose name starts with any of the strings
|
||||||
|
* in this array will be loaded by this class,
|
||||||
|
* unless their name appears in
|
||||||
|
* <code>excludedClasses</code>.
|
||||||
|
* Can be <code>null</code>
|
||||||
|
* @param excludedClasses array of class or package names that should NOT
|
||||||
|
* be directly loaded by this loader. Loading of
|
||||||
|
* classes whose name starts with any of the
|
||||||
|
* strings in this array will be delegated to
|
||||||
|
* <code>parent</code>, even if the classes
|
||||||
|
* package or classname appears in
|
||||||
|
* <code>includedClasses</code>. Typically this
|
||||||
|
* parameter is used to exclude loading one or
|
||||||
|
* more classes in a package whose other classes
|
||||||
|
* are loaded by this object.
|
||||||
|
* @param parent ClassLoader to which loading of classes should
|
||||||
|
* be delegated if necessary
|
||||||
|
*/
|
||||||
|
public SelectedClassnameClassLoader(String[] includedClasses,
|
||||||
|
String[] excludedClasses,
|
||||||
|
ClassLoader parent)
|
||||||
|
{
|
||||||
|
this(includedClasses, excludedClasses, null, parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new classloader that loads the given classes.
|
||||||
|
*
|
||||||
|
* @param includedClasses array of class or package names that should be
|
||||||
|
* directly loaded by this loader. Classes
|
||||||
|
* whose name starts with any of the strings
|
||||||
|
* in this array will be loaded by this class,
|
||||||
|
* unless their name appears in
|
||||||
|
* <code>excludedClasses</code>.
|
||||||
|
* Can be <code>null</code>
|
||||||
|
* @param excludedClasses array of class or package names that should NOT
|
||||||
|
* be directly loaded by this loader. Loading of
|
||||||
|
* classes whose name starts with any of the
|
||||||
|
* strings in this array will be delegated to
|
||||||
|
* <code>parent</code>, even if the classes
|
||||||
|
* package or classname appears in
|
||||||
|
* <code>includedClasses</code>. Typically this
|
||||||
|
* parameter is used to exclude loading one or
|
||||||
|
* more classes in a package whose other classes
|
||||||
|
* are loaded by this object.
|
||||||
|
* @param notFoundClasses array of class or package names for which this
|
||||||
|
* should raise a ClassNotFoundException
|
||||||
|
* @param parent ClassLoader to which loading of classes should
|
||||||
|
* be delegated if necessary
|
||||||
|
*/
|
||||||
|
public SelectedClassnameClassLoader(String[] includedClasses,
|
||||||
|
String[] excludedClasses,
|
||||||
|
String[] notFoundClasses,
|
||||||
|
ClassLoader parent)
|
||||||
|
{
|
||||||
|
super(parent);
|
||||||
|
this.includedClasses = includedClasses;
|
||||||
|
this.excludedClasses = excludedClasses;
|
||||||
|
this.notFoundClasses = notFoundClasses;
|
||||||
|
|
||||||
|
log.debug("created " + this);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected synchronized Class<?> loadClass(String name, boolean resolve)
|
||||||
|
throws ClassNotFoundException
|
||||||
|
{
|
||||||
|
log.trace("loadClass(" + name + "," + resolve + ")");
|
||||||
|
if (isIncluded(name) && (isExcluded(name) == false))
|
||||||
|
{
|
||||||
|
Class c = findClass(name);
|
||||||
|
|
||||||
|
if (resolve)
|
||||||
|
{
|
||||||
|
resolveClass(c);
|
||||||
|
}
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
else if (isNotFound(name))
|
||||||
|
{
|
||||||
|
throw new ClassNotFoundException(name + " is discarded");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return super.loadClass(name, resolve);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Class<?> findClass(String name) throws ClassNotFoundException
|
||||||
|
{
|
||||||
|
log.trace("findClass(" + name + ")");
|
||||||
|
Class result = classes.get(name);
|
||||||
|
if (result != null)
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isIncluded(name) && (isExcluded(name) == false))
|
||||||
|
{
|
||||||
|
result = createClass(name);
|
||||||
|
}
|
||||||
|
else if (isNotFound(name))
|
||||||
|
{
|
||||||
|
throw new ClassNotFoundException(name + " is discarded");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
result = super.findClass(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
classes.put(name, result);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Class createClass(String name) throws ClassFormatError, ClassNotFoundException
|
||||||
|
{
|
||||||
|
log.info("createClass(" + name + ")");
|
||||||
|
try
|
||||||
|
{
|
||||||
|
InputStream is = getResourceAsStream(name.replace('.', '/').concat(".class"));
|
||||||
|
byte[] bytes = new byte[1024];
|
||||||
|
ByteArrayOutputStream baos = new ByteArrayOutputStream(1024);
|
||||||
|
int read;
|
||||||
|
while ((read = is.read(bytes)) > -1)
|
||||||
|
{
|
||||||
|
baos.write(bytes, 0, read);
|
||||||
|
}
|
||||||
|
bytes = baos.toByteArray();
|
||||||
|
return this.defineClass(name, bytes, 0, bytes.length);
|
||||||
|
}
|
||||||
|
catch (FileNotFoundException e)
|
||||||
|
{
|
||||||
|
throw new ClassNotFoundException("cannot find " + name, e);
|
||||||
|
}
|
||||||
|
catch (IOException e)
|
||||||
|
{
|
||||||
|
throw new ClassNotFoundException("cannot read " + name, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean isIncluded(String className)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (includedClasses != null)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < includedClasses.length; i++)
|
||||||
|
{
|
||||||
|
if (className.startsWith(includedClasses[i]))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean isExcluded(String className)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (excludedClasses != null)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < excludedClasses.length; i++)
|
||||||
|
{
|
||||||
|
if (className.startsWith(excludedClasses[i]))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean isNotFound(String className)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (notFoundClasses != null)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < notFoundClasses.length; i++)
|
||||||
|
{
|
||||||
|
if (className.startsWith(notFoundClasses[i]))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
String s = getClass().getName();
|
||||||
|
s += "[includedClasses=";
|
||||||
|
s += listClasses(includedClasses);
|
||||||
|
s += ";excludedClasses=";
|
||||||
|
s += listClasses(excludedClasses);
|
||||||
|
s += ";notFoundClasses=";
|
||||||
|
s += listClasses(notFoundClasses);
|
||||||
|
s += ";parent=";
|
||||||
|
s += getParent();
|
||||||
|
s += "]";
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String listClasses(String[] classes) {
|
||||||
|
if (classes == null) return null;
|
||||||
|
String s = "";
|
||||||
|
for (int i = 0; i < classes.length; i++) {
|
||||||
|
if (i > 0)
|
||||||
|
s += ",";
|
||||||
|
s += classes[i];
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,73 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2007, Red Hat, Inc. and/or it's affiliates. 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.infinispan.functional.classloader;
|
||||||
|
|
||||||
|
import junit.extensions.TestSetup;
|
||||||
|
import junit.framework.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A TestSetup that makes SelectedClassnameClassLoader the thread
|
||||||
|
* context classloader for the duration of the test.
|
||||||
|
*
|
||||||
|
* @author <a href="brian.stansberry@jboss.com">Brian Stansberry</a>
|
||||||
|
* @version $Revision: 1 $
|
||||||
|
*/
|
||||||
|
public class SelectedClassnameClassLoaderTestSetup extends TestSetup
|
||||||
|
{
|
||||||
|
private ClassLoader originalTCCL;
|
||||||
|
private String[] includedClasses;
|
||||||
|
private String[] excludedClasses;
|
||||||
|
private String[] notFoundClasses;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new SelectedClassnameClassLoaderTestSetup.
|
||||||
|
*
|
||||||
|
* @param test
|
||||||
|
*/
|
||||||
|
public SelectedClassnameClassLoaderTestSetup(Test test,
|
||||||
|
String[] includedClasses,
|
||||||
|
String[] excludedClasses,
|
||||||
|
String[] notFoundClasses)
|
||||||
|
{
|
||||||
|
super(test);
|
||||||
|
this.includedClasses = includedClasses;
|
||||||
|
this.excludedClasses = excludedClasses;
|
||||||
|
this.notFoundClasses = notFoundClasses;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void setUp() throws Exception
|
||||||
|
{
|
||||||
|
super.setUp();
|
||||||
|
|
||||||
|
originalTCCL = Thread.currentThread().getContextClassLoader();
|
||||||
|
ClassLoader parent = originalTCCL == null ? getClass().getClassLoader() : originalTCCL;
|
||||||
|
ClassLoader selectedTCCL = new SelectedClassnameClassLoader(includedClasses, excludedClasses, notFoundClasses, parent);
|
||||||
|
Thread.currentThread().setContextClassLoader(selectedTCCL);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void tearDown() throws Exception
|
||||||
|
{
|
||||||
|
Thread.currentThread().setContextClassLoader(originalTCCL);
|
||||||
|
super.tearDown();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,238 @@
|
||||||
|
/*
|
||||||
|
* JBoss, Home of Professional Open Source.
|
||||||
|
* Copyright 2009, Red Hat, Inc. and/or it's affiliates, and individual contributors
|
||||||
|
* as indicated by the @author tags. See the copyright.txt file in the
|
||||||
|
* distribution for a full listing of individual contributors.
|
||||||
|
*
|
||||||
|
* This is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU Lesser General Public License as
|
||||||
|
* published by the Free Software Foundation; either version 2.1 of
|
||||||
|
* the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This software is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this software; if not, write to the Free
|
||||||
|
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||||
|
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
|
||||||
|
*/
|
||||||
|
package org.hibernate.test.cache.infinispan.functional.cluster;
|
||||||
|
|
||||||
|
import org.hibernate.Session;
|
||||||
|
import org.hibernate.cfg.Configuration;
|
||||||
|
import org.hibernate.cfg.Environment;
|
||||||
|
import org.hibernate.cfg.Mappings;
|
||||||
|
import org.hibernate.dialect.Dialect;
|
||||||
|
import org.hibernate.engine.SessionFactoryImplementor;
|
||||||
|
import org.hibernate.junit.functional.ExecutionEnvironment;
|
||||||
|
import org.hibernate.junit.functional.FunctionalTestCase;
|
||||||
|
import org.hibernate.transaction.CMTTransactionFactory;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AbstractDualNodeTestCase.
|
||||||
|
*
|
||||||
|
* @author Galder Zamarreño
|
||||||
|
* @since 3.5
|
||||||
|
*/
|
||||||
|
public abstract class AbstractDualNodeTestCase extends FunctionalTestCase {
|
||||||
|
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(AbstractDualNodeTestCase.class);
|
||||||
|
public static final String NODE_ID_PROP = "hibernate.test.cluster.node.id";
|
||||||
|
public static final String LOCAL = "local";
|
||||||
|
public static final String REMOTE = "remote";
|
||||||
|
private ExecutionEnvironment secondNodeEnvironment;
|
||||||
|
private Session secondNodeSession;
|
||||||
|
|
||||||
|
public AbstractDualNodeTestCase(String string) {
|
||||||
|
super(string);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String[] getMappings() {
|
||||||
|
return new String[] { "cache/infinispan/functional/Contact.hbm.xml", "cache/infinispan/functional/Customer.hbm.xml" };
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getCacheConcurrencyStrategy() {
|
||||||
|
return "transactional";
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Class getCacheRegionFactory() {
|
||||||
|
return ClusterAwareRegionFactory.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void configure(Configuration cfg) {
|
||||||
|
standardConfigure(cfg);
|
||||||
|
configureFirstNode(cfg);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void prepareTest() throws Exception {
|
||||||
|
log.info("Building second node locally managed execution env");
|
||||||
|
secondNodeEnvironment = new ExecutionEnvironment(new SecondNodeSettings());
|
||||||
|
secondNodeEnvironment.initialize();
|
||||||
|
super.prepareTest();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void runTest() throws Throwable {
|
||||||
|
try {
|
||||||
|
super.runTest();
|
||||||
|
} finally {
|
||||||
|
if ( secondNodeSession != null && secondNodeSession.isOpen() ) {
|
||||||
|
if ( secondNodeSession.isConnected() ) {
|
||||||
|
secondNodeSession.connection().rollback();
|
||||||
|
}
|
||||||
|
secondNodeSession.close();
|
||||||
|
secondNodeSession = null;
|
||||||
|
fail( "unclosed session" );
|
||||||
|
} else {
|
||||||
|
secondNodeSession = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void cleanupTest() throws Exception {
|
||||||
|
try {
|
||||||
|
super.cleanupTest();
|
||||||
|
|
||||||
|
log.info( "Destroying second node locally managed execution env" );
|
||||||
|
secondNodeEnvironment.complete();
|
||||||
|
secondNodeEnvironment = null;
|
||||||
|
} finally {
|
||||||
|
cleanupTransactionManagement();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void cleanupTransactionManagement() {
|
||||||
|
DualNodeJtaTransactionManagerImpl.cleanupTransactions();
|
||||||
|
DualNodeJtaTransactionManagerImpl.cleanupTransactionManagers();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ExecutionEnvironment getSecondNodeEnvironment() {
|
||||||
|
return secondNodeEnvironment;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Class getConnectionProviderClass() {
|
||||||
|
return DualNodeConnectionProviderImpl.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Class getTransactionManagerLookupClass() {
|
||||||
|
return DualNodeTransactionManagerLookup.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Class getTransactionFactoryClass() {
|
||||||
|
return CMTTransactionFactory.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply any node-specific configurations to our first node.
|
||||||
|
*
|
||||||
|
* @param the
|
||||||
|
* Configuration to update.
|
||||||
|
*/
|
||||||
|
protected void configureFirstNode(Configuration cfg) {
|
||||||
|
cfg.setProperty(NODE_ID_PROP, LOCAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply any node-specific configurations to our second node.
|
||||||
|
*
|
||||||
|
* @param the
|
||||||
|
* Configuration to update.
|
||||||
|
*/
|
||||||
|
protected void configureSecondNode(Configuration cfg) {
|
||||||
|
cfg.setProperty(NODE_ID_PROP, REMOTE);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void sleep(long ms) {
|
||||||
|
try {
|
||||||
|
Thread.sleep(ms);
|
||||||
|
}
|
||||||
|
catch (InterruptedException e) {
|
||||||
|
log.warn("Interrupted during sleep", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void standardConfigure(Configuration cfg) {
|
||||||
|
super.configure(cfg);
|
||||||
|
|
||||||
|
cfg.setProperty(Environment.CONNECTION_PROVIDER, getConnectionProviderClass().getName());
|
||||||
|
cfg.setProperty(Environment.TRANSACTION_MANAGER_STRATEGY, getTransactionManagerLookupClass().getName());
|
||||||
|
cfg.setProperty(Environment.TRANSACTION_STRATEGY, getTransactionFactoryClass().getName());
|
||||||
|
cfg.setProperty(Environment.CACHE_REGION_FACTORY, getCacheRegionFactory().getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Settings impl that delegates most calls to the DualNodeTestCase itself, but overrides the
|
||||||
|
* configure method to allow separate cache settings for the second node.
|
||||||
|
*/
|
||||||
|
public class SecondNodeSettings implements ExecutionEnvironment.Settings {
|
||||||
|
private final AbstractDualNodeTestCase delegate;
|
||||||
|
|
||||||
|
public SecondNodeSettings() {
|
||||||
|
this.delegate = AbstractDualNodeTestCase.this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is the important one -- we extend the delegate's work by adding second-node specific
|
||||||
|
* settings
|
||||||
|
*/
|
||||||
|
public void configure(Configuration arg0) {
|
||||||
|
delegate.standardConfigure(arg0);
|
||||||
|
configureSecondNode(arg0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disable creating of schemas; we let the primary session factory do that to our shared
|
||||||
|
* database.
|
||||||
|
*/
|
||||||
|
public boolean createSchema() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disable creating of schemas; we let the primary session factory do that to our shared
|
||||||
|
* database.
|
||||||
|
*/
|
||||||
|
public boolean recreateSchemaAfterFailure() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void afterConfigurationBuilt(Mappings arg0, Dialect arg1) {
|
||||||
|
delegate.afterConfigurationBuilt(arg0, arg1);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void afterSessionFactoryBuilt(SessionFactoryImplementor arg0) {
|
||||||
|
delegate.afterSessionFactoryBuilt(arg0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean appliesTo(Dialect arg0) {
|
||||||
|
return delegate.appliesTo(arg0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getBaseForMappings() {
|
||||||
|
return delegate.getBaseForMappings();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCacheConcurrencyStrategy() {
|
||||||
|
return delegate.getCacheConcurrencyStrategy();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String[] getMappings() {
|
||||||
|
return delegate.getMappings();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean overrideCacheStrategy() {
|
||||||
|
return delegate.overrideCacheStrategy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,123 @@
|
||||||
|
/*
|
||||||
|
* JBoss, Home of Professional Open Source.
|
||||||
|
* Copyright 2009, Red Hat, Inc. and/or it's affiliates, and individual contributors
|
||||||
|
* as indicated by the @author tags. See the copyright.txt file in the
|
||||||
|
* distribution for a full listing of individual contributors.
|
||||||
|
*
|
||||||
|
* This is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU Lesser General Public License as
|
||||||
|
* published by the Free Software Foundation; either version 2.1 of
|
||||||
|
* the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This software is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this software; if not, write to the Free
|
||||||
|
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||||
|
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
|
||||||
|
*/
|
||||||
|
package org.hibernate.test.cache.infinispan.functional.cluster;
|
||||||
|
|
||||||
|
import java.util.Hashtable;
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
import org.hibernate.cache.CacheDataDescription;
|
||||||
|
import org.hibernate.cache.CacheException;
|
||||||
|
import org.hibernate.cache.CollectionRegion;
|
||||||
|
import org.hibernate.cache.EntityRegion;
|
||||||
|
import org.hibernate.cache.QueryResultsRegion;
|
||||||
|
import org.hibernate.cache.RegionFactory;
|
||||||
|
import org.hibernate.cache.TimestampsRegion;
|
||||||
|
import org.hibernate.cache.infinispan.InfinispanRegionFactory;
|
||||||
|
import org.hibernate.cfg.Settings;
|
||||||
|
import org.infinispan.manager.CacheManager;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ClusterAwareRegionFactory.
|
||||||
|
*
|
||||||
|
* @author Galder Zamarreño
|
||||||
|
* @since 3.5
|
||||||
|
*/
|
||||||
|
public class ClusterAwareRegionFactory implements RegionFactory {
|
||||||
|
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(ClusterAwareRegionFactory.class);
|
||||||
|
private static final Hashtable<String, CacheManager> cacheManagers = new Hashtable<String, CacheManager>();
|
||||||
|
|
||||||
|
private final InfinispanRegionFactory delegate = new InfinispanRegionFactory();
|
||||||
|
private String cacheManagerName;
|
||||||
|
private boolean locallyAdded;
|
||||||
|
|
||||||
|
public ClusterAwareRegionFactory(Properties props) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static CacheManager getCacheManager(String name) {
|
||||||
|
return cacheManagers.get(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void addCacheManager(String name, CacheManager manager) {
|
||||||
|
cacheManagers.put(name, manager);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void clearCacheManagers() {
|
||||||
|
for (CacheManager manager : cacheManagers.values()) {
|
||||||
|
try {
|
||||||
|
manager.stop();
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Exception cleaning up CacheManager " + manager, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cacheManagers.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void start(Settings settings, Properties properties) throws CacheException {
|
||||||
|
cacheManagerName = properties.getProperty(AbstractDualNodeTestCase.NODE_ID_PROP);
|
||||||
|
|
||||||
|
CacheManager existing = getCacheManager(cacheManagerName);
|
||||||
|
locallyAdded = (existing == null);
|
||||||
|
|
||||||
|
if (locallyAdded) {
|
||||||
|
delegate.start(settings, properties);
|
||||||
|
cacheManagers.put(cacheManagerName, delegate.getCacheManager());
|
||||||
|
} else {
|
||||||
|
delegate.setCacheManager(existing);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void stop() {
|
||||||
|
if (locallyAdded) cacheManagers.remove(cacheManagerName);
|
||||||
|
delegate.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
public CollectionRegion buildCollectionRegion(String regionName, Properties properties,
|
||||||
|
CacheDataDescription metadata) throws CacheException {
|
||||||
|
return delegate.buildCollectionRegion(regionName, properties, metadata);
|
||||||
|
}
|
||||||
|
|
||||||
|
public EntityRegion buildEntityRegion(String regionName, Properties properties,
|
||||||
|
CacheDataDescription metadata) throws CacheException {
|
||||||
|
return delegate.buildEntityRegion(regionName, properties, metadata);
|
||||||
|
}
|
||||||
|
|
||||||
|
public QueryResultsRegion buildQueryResultsRegion(String regionName, Properties properties)
|
||||||
|
throws CacheException {
|
||||||
|
return delegate.buildQueryResultsRegion(regionName, properties);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TimestampsRegion buildTimestampsRegion(String regionName, Properties properties)
|
||||||
|
throws CacheException {
|
||||||
|
return delegate.buildTimestampsRegion(regionName, properties);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isMinimalPutsEnabledByDefault() {
|
||||||
|
return delegate.isMinimalPutsEnabledByDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
public long nextTimestamp() {
|
||||||
|
return delegate.nextTimestamp();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,85 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2007, Red Hat, Inc. and/or it's affiliates or third-party contributors as
|
||||||
|
* indicated by the @author tags or express copyright attribution
|
||||||
|
* statements applied by the authors. All third-party contributions are
|
||||||
|
* distributed under license by Red Hat, Inc. and/or it's affiliates.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||||
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
* Lesser General Public License, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this distribution; if not, write to:
|
||||||
|
* Free Software Foundation, Inc.
|
||||||
|
* 51 Franklin Street, Fifth Floor
|
||||||
|
* Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
package org.hibernate.test.cache.infinispan.functional.cluster;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A {@link ConnectionProvider} implementation adding JTA-style transactionality around the returned
|
||||||
|
* connections using the {@link DualNodeJtaTransactionManagerImpl}.
|
||||||
|
*
|
||||||
|
* @author Brian Stansberry
|
||||||
|
*/
|
||||||
|
public class DualNodeConnectionProviderImpl implements ConnectionProvider {
|
||||||
|
private static ConnectionProvider actualConnectionProvider = ConnectionProviderFactory.newConnectionProvider();
|
||||||
|
private String nodeId;
|
||||||
|
private boolean isTransactional;
|
||||||
|
|
||||||
|
public static ConnectionProvider getActualConnectionProvider() {
|
||||||
|
return actualConnectionProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void configure(Properties props) throws HibernateException {
|
||||||
|
nodeId = props.getProperty(AbstractDualNodeTestCase.NODE_ID_PROP);
|
||||||
|
if (nodeId == null)
|
||||||
|
throw new HibernateException(AbstractDualNodeTestCase.NODE_ID_PROP + " not configured");
|
||||||
|
}
|
||||||
|
|
||||||
|
public Connection getConnection() throws SQLException {
|
||||||
|
DualNodeJtaTransactionImpl currentTransaction = DualNodeJtaTransactionManagerImpl
|
||||||
|
.getInstance(nodeId).getCurrentTransaction();
|
||||||
|
if (currentTransaction == null) {
|
||||||
|
isTransactional = false;
|
||||||
|
return actualConnectionProvider.getConnection();
|
||||||
|
} else {
|
||||||
|
isTransactional = true;
|
||||||
|
Connection connection = currentTransaction.getEnlistedConnection();
|
||||||
|
if (connection == null) {
|
||||||
|
connection = actualConnectionProvider.getConnection();
|
||||||
|
currentTransaction.enlistConnection(connection);
|
||||||
|
}
|
||||||
|
return connection;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void closeConnection(Connection conn) throws SQLException {
|
||||||
|
if (!isTransactional) {
|
||||||
|
conn.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void close() throws HibernateException {
|
||||||
|
actualConnectionProvider.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean supportsAggressiveRelease() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,253 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2007, Red Hat, Inc. and/or it's affiliates or third-party contributors as
|
||||||
|
* indicated by the @author tags or express copyright attribution
|
||||||
|
* statements applied by the authors. All third-party contributions are
|
||||||
|
* distributed under license by Red Hat, Inc. and/or it's affiliates.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||||
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
* Lesser General Public License, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this distribution; if not, write to:
|
||||||
|
* Free Software Foundation, Inc.
|
||||||
|
* 51 Franklin Street, Fifth Floor
|
||||||
|
* Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
package org.hibernate.test.cache.infinispan.functional.cluster;
|
||||||
|
|
||||||
|
import java.sql.Connection;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
|
import javax.transaction.HeuristicMixedException;
|
||||||
|
import javax.transaction.HeuristicRollbackException;
|
||||||
|
import javax.transaction.RollbackException;
|
||||||
|
import javax.transaction.Status;
|
||||||
|
import javax.transaction.Synchronization;
|
||||||
|
import javax.transaction.SystemException;
|
||||||
|
import javax.transaction.Transaction;
|
||||||
|
import javax.transaction.xa.XAException;
|
||||||
|
import javax.transaction.xa.XAResource;
|
||||||
|
import javax.transaction.xa.Xid;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SimpleJtaTransactionImpl variant that works with DualNodeTransactionManagerImpl.
|
||||||
|
*
|
||||||
|
* @author Brian Stansberry
|
||||||
|
*/
|
||||||
|
public class DualNodeJtaTransactionImpl implements Transaction {
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(DualNodeJtaTransactionImpl.class);
|
||||||
|
|
||||||
|
private int status;
|
||||||
|
private LinkedList synchronizations;
|
||||||
|
private Connection connection; // the only resource we care about is jdbc connection
|
||||||
|
private final DualNodeJtaTransactionManagerImpl jtaTransactionManager;
|
||||||
|
private List<XAResource> enlistedResources = new ArrayList<XAResource>();
|
||||||
|
private Xid xid = new DualNodeJtaTransactionXid();
|
||||||
|
|
||||||
|
public DualNodeJtaTransactionImpl(DualNodeJtaTransactionManagerImpl jtaTransactionManager) {
|
||||||
|
this.jtaTransactionManager = jtaTransactionManager;
|
||||||
|
this.status = Status.STATUS_ACTIVE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getStatus() {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void commit() throws RollbackException, HeuristicMixedException,
|
||||||
|
HeuristicRollbackException, IllegalStateException, SystemException {
|
||||||
|
|
||||||
|
if (status == Status.STATUS_MARKED_ROLLBACK) {
|
||||||
|
log.trace("on commit, status was marked for rollback-only");
|
||||||
|
rollback();
|
||||||
|
} else {
|
||||||
|
status = Status.STATUS_PREPARING;
|
||||||
|
|
||||||
|
for (int i = 0; i < synchronizations.size(); i++) {
|
||||||
|
Synchronization s = (Synchronization) synchronizations.get(i);
|
||||||
|
s.beforeCompletion();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!runXaResourcePrepare()) {
|
||||||
|
status = Status.STATUS_ROLLING_BACK;
|
||||||
|
} else {
|
||||||
|
status = Status.STATUS_PREPARED;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = Status.STATUS_COMMITTING;
|
||||||
|
|
||||||
|
if (connection != null) {
|
||||||
|
try {
|
||||||
|
connection.commit();
|
||||||
|
connection.close();
|
||||||
|
} catch (SQLException sqle) {
|
||||||
|
status = Status.STATUS_UNKNOWN;
|
||||||
|
throw new SystemException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
runXaResourceCommitTx();
|
||||||
|
|
||||||
|
status = Status.STATUS_COMMITTED;
|
||||||
|
|
||||||
|
for (int i = 0; i < synchronizations.size(); i++) {
|
||||||
|
Synchronization s = (Synchronization) synchronizations.get(i);
|
||||||
|
s.afterCompletion(status);
|
||||||
|
}
|
||||||
|
|
||||||
|
// status = Status.STATUS_NO_TRANSACTION;
|
||||||
|
jtaTransactionManager.endCurrent(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void rollback() throws IllegalStateException, SystemException {
|
||||||
|
status = Status.STATUS_ROLLING_BACK;
|
||||||
|
runXaResourceRollback();
|
||||||
|
status = Status.STATUS_ROLLEDBACK;
|
||||||
|
|
||||||
|
if (connection != null) {
|
||||||
|
try {
|
||||||
|
connection.rollback();
|
||||||
|
connection.close();
|
||||||
|
} catch (SQLException sqle) {
|
||||||
|
status = Status.STATUS_UNKNOWN;
|
||||||
|
throw new SystemException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (synchronizations != null) {
|
||||||
|
for (int i = 0; i < synchronizations.size(); i++) {
|
||||||
|
Synchronization s = (Synchronization) synchronizations.get(i);
|
||||||
|
s.afterCompletion(status);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// status = Status.STATUS_NO_TRANSACTION;
|
||||||
|
jtaTransactionManager.endCurrent(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRollbackOnly() throws IllegalStateException, SystemException {
|
||||||
|
status = Status.STATUS_MARKED_ROLLBACK;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void registerSynchronization(Synchronization synchronization) throws RollbackException,
|
||||||
|
IllegalStateException, SystemException {
|
||||||
|
// todo : find the spec-allowable statuses during which synch can be registered...
|
||||||
|
if (synchronizations == null) {
|
||||||
|
synchronizations = new LinkedList();
|
||||||
|
}
|
||||||
|
synchronizations.add(synchronization);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void enlistConnection(Connection connection) {
|
||||||
|
if (this.connection != null) {
|
||||||
|
throw new IllegalStateException("Connection already registered");
|
||||||
|
}
|
||||||
|
this.connection = connection;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Connection getEnlistedConnection() {
|
||||||
|
return connection;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean enlistResource(XAResource xaResource) throws RollbackException,
|
||||||
|
IllegalStateException, SystemException {
|
||||||
|
enlistedResources.add(xaResource);
|
||||||
|
try {
|
||||||
|
xaResource.start(xid, 0);
|
||||||
|
} catch (XAException e) {
|
||||||
|
log.error("Got an exception", e);
|
||||||
|
throw new SystemException(e.getMessage());
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean delistResource(XAResource xaResource, int i) throws IllegalStateException,
|
||||||
|
SystemException {
|
||||||
|
throw new SystemException("not supported");
|
||||||
|
}
|
||||||
|
|
||||||
|
public Collection<XAResource> getEnlistedResources() {
|
||||||
|
return enlistedResources;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean runXaResourcePrepare() throws SystemException {
|
||||||
|
Collection<XAResource> resources = getEnlistedResources();
|
||||||
|
for (XAResource res : resources) {
|
||||||
|
try {
|
||||||
|
res.prepare(xid);
|
||||||
|
} catch (XAException e) {
|
||||||
|
log.trace("The resource wants to rollback!", e);
|
||||||
|
return false;
|
||||||
|
} catch (Throwable th) {
|
||||||
|
log.error("Unexpected error from resource manager!", th);
|
||||||
|
throw new SystemException(th.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void runXaResourceRollback() {
|
||||||
|
Collection<XAResource> resources = getEnlistedResources();
|
||||||
|
for (XAResource res : resources) {
|
||||||
|
try {
|
||||||
|
res.rollback(xid);
|
||||||
|
} catch (XAException e) {
|
||||||
|
log.warn("Error while rolling back",e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean runXaResourceCommitTx() throws HeuristicMixedException {
|
||||||
|
Collection<XAResource> resources = getEnlistedResources();
|
||||||
|
for (XAResource res : resources) {
|
||||||
|
try {
|
||||||
|
res.commit(xid, false);//todo we only support one phase commit for now, change this!!!
|
||||||
|
} catch (XAException e) {
|
||||||
|
log.warn("exception while committing",e);
|
||||||
|
throw new HeuristicMixedException(e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class DualNodeJtaTransactionXid implements Xid {
|
||||||
|
private static AtomicInteger txIdCounter = new AtomicInteger(0);
|
||||||
|
private int id = txIdCounter.incrementAndGet();
|
||||||
|
|
||||||
|
public int getFormatId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getGlobalTransactionId() {
|
||||||
|
throw new IllegalStateException("TODO - please implement me!!!"); //todo implement!!!
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getBranchQualifier() {
|
||||||
|
throw new IllegalStateException("TODO - please implement me!!!"); //todo implement!!!
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return getClass().getSimpleName() + "{" +
|
||||||
|
"id=" + id +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,158 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2007, Red Hat, Inc. and/or it's affiliates or third-party contributors as
|
||||||
|
* indicated by the @author tags or express copyright attribution
|
||||||
|
* statements applied by the authors. All third-party contributions are
|
||||||
|
* distributed under license by Red Hat, Inc. and/or it's affiliates.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||||
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
* Lesser General Public License, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this distribution; if not, write to:
|
||||||
|
* Free Software Foundation, Inc.
|
||||||
|
* 51 Franklin Street, Fifth Floor
|
||||||
|
* Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
package org.hibernate.test.cache.infinispan.functional.cluster;
|
||||||
|
|
||||||
|
import java.util.Hashtable;
|
||||||
|
|
||||||
|
import javax.transaction.HeuristicMixedException;
|
||||||
|
import javax.transaction.HeuristicRollbackException;
|
||||||
|
import javax.transaction.InvalidTransactionException;
|
||||||
|
import javax.transaction.NotSupportedException;
|
||||||
|
import javax.transaction.RollbackException;
|
||||||
|
import javax.transaction.Status;
|
||||||
|
import javax.transaction.SystemException;
|
||||||
|
import javax.transaction.Transaction;
|
||||||
|
import javax.transaction.TransactionManager;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Variant of SimpleJtaTransactionManagerImpl that doesn't use a VM-singleton, but rather a set of
|
||||||
|
* impls keyed by a node id.
|
||||||
|
*
|
||||||
|
* @author Brian Stansberry
|
||||||
|
*/
|
||||||
|
public class DualNodeJtaTransactionManagerImpl implements TransactionManager {
|
||||||
|
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(DualNodeJtaTransactionManagerImpl.class);
|
||||||
|
|
||||||
|
private static final Hashtable INSTANCES = new Hashtable();
|
||||||
|
|
||||||
|
private ThreadLocal currentTransaction = new ThreadLocal();
|
||||||
|
private String nodeId;
|
||||||
|
|
||||||
|
public synchronized static DualNodeJtaTransactionManagerImpl getInstance(String nodeId) {
|
||||||
|
DualNodeJtaTransactionManagerImpl tm = (DualNodeJtaTransactionManagerImpl) INSTANCES
|
||||||
|
.get(nodeId);
|
||||||
|
if (tm == null) {
|
||||||
|
tm = new DualNodeJtaTransactionManagerImpl(nodeId);
|
||||||
|
INSTANCES.put(nodeId, tm);
|
||||||
|
}
|
||||||
|
return tm;
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized static void cleanupTransactions() {
|
||||||
|
for (java.util.Iterator it = INSTANCES.values().iterator(); it.hasNext();) {
|
||||||
|
TransactionManager tm = (TransactionManager) it.next();
|
||||||
|
try {
|
||||||
|
tm.suspend();
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Exception cleaning up TransactionManager " + tm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized static void cleanupTransactionManagers() {
|
||||||
|
INSTANCES.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
private DualNodeJtaTransactionManagerImpl(String nodeId) {
|
||||||
|
this.nodeId = nodeId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getStatus() throws SystemException {
|
||||||
|
Transaction tx = getCurrentTransaction();
|
||||||
|
return tx == null ? Status.STATUS_NO_TRANSACTION : tx.getStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Transaction getTransaction() throws SystemException {
|
||||||
|
return (Transaction) currentTransaction.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public DualNodeJtaTransactionImpl getCurrentTransaction() {
|
||||||
|
return (DualNodeJtaTransactionImpl) currentTransaction.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void begin() throws NotSupportedException, SystemException {
|
||||||
|
currentTransaction.set(new DualNodeJtaTransactionImpl(this));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Transaction suspend() throws SystemException {
|
||||||
|
DualNodeJtaTransactionImpl suspended = getCurrentTransaction();
|
||||||
|
log.trace(nodeId + ": Suspending " + suspended + " for thread "
|
||||||
|
+ Thread.currentThread().getName());
|
||||||
|
currentTransaction.set(null);
|
||||||
|
return suspended;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void resume(Transaction transaction) throws InvalidTransactionException,
|
||||||
|
IllegalStateException, SystemException {
|
||||||
|
currentTransaction.set((DualNodeJtaTransactionImpl) transaction);
|
||||||
|
log.trace(nodeId + ": Resumed " + transaction + " for thread "
|
||||||
|
+ Thread.currentThread().getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void commit() throws RollbackException, HeuristicMixedException,
|
||||||
|
HeuristicRollbackException, SecurityException, IllegalStateException, SystemException {
|
||||||
|
Transaction tx = getCurrentTransaction();
|
||||||
|
if (tx == null) {
|
||||||
|
throw new IllegalStateException("no current transaction to commit");
|
||||||
|
}
|
||||||
|
tx.commit();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void rollback() throws IllegalStateException, SecurityException, SystemException {
|
||||||
|
Transaction tx = getCurrentTransaction();
|
||||||
|
if (tx == null) {
|
||||||
|
throw new IllegalStateException("no current transaction");
|
||||||
|
}
|
||||||
|
tx.rollback();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRollbackOnly() throws IllegalStateException, SystemException {
|
||||||
|
Transaction tx = getCurrentTransaction();
|
||||||
|
if (tx == null) {
|
||||||
|
throw new IllegalStateException("no current transaction");
|
||||||
|
}
|
||||||
|
tx.setRollbackOnly();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTransactionTimeout(int i) throws SystemException {
|
||||||
|
}
|
||||||
|
|
||||||
|
void endCurrent(DualNodeJtaTransactionImpl transaction) {
|
||||||
|
if (transaction == currentTransaction.get()) {
|
||||||
|
currentTransaction.set(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
StringBuffer sb = new StringBuffer(getClass().getName());
|
||||||
|
sb.append("[nodeId=");
|
||||||
|
sb.append(nodeId);
|
||||||
|
sb.append("]");
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,55 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2007, Red Hat, Inc. and/or it's affiliates or third-party contributors as
|
||||||
|
* indicated by the @author tags or express copyright attribution
|
||||||
|
* statements applied by the authors. All third-party contributions are
|
||||||
|
* distributed under license by Red Hat, Inc. and/or it's affiliates.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||||
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
* Lesser General Public License, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this distribution; if not, write to:
|
||||||
|
* Free Software Foundation, Inc.
|
||||||
|
* 51 Franklin Street, Fifth Floor
|
||||||
|
* Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
package org.hibernate.test.cache.infinispan.functional.cluster;
|
||||||
|
|
||||||
|
import java.util.Properties;
|
||||||
|
import javax.transaction.TransactionManager;
|
||||||
|
import javax.transaction.Transaction;
|
||||||
|
|
||||||
|
import org.hibernate.transaction.TransactionManagerLookup;
|
||||||
|
import org.hibernate.HibernateException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SimpleJtaTransactionManagerLookupImpl subclass that finds a different DualNodeTransactionManager
|
||||||
|
* based on the value of property {@link DualNodeTestUtil#NODE_ID_PROP}.
|
||||||
|
*
|
||||||
|
* @author Brian Stansberry
|
||||||
|
*/
|
||||||
|
public class DualNodeTransactionManagerLookup implements TransactionManagerLookup {
|
||||||
|
|
||||||
|
public TransactionManager getTransactionManager(Properties props) throws HibernateException {
|
||||||
|
String nodeId = props.getProperty(AbstractDualNodeTestCase.NODE_ID_PROP);
|
||||||
|
if (nodeId == null)
|
||||||
|
throw new HibernateException(AbstractDualNodeTestCase.NODE_ID_PROP + " not configured");
|
||||||
|
return DualNodeJtaTransactionManagerImpl.getInstance(nodeId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUserTransactionName() {
|
||||||
|
throw new UnsupportedOperationException("jndi currently not implemented for these tests");
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object getTransactionIdentifier(Transaction transaction) {
|
||||||
|
return transaction;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,387 @@
|
||||||
|
/*
|
||||||
|
* JBoss, Home of Professional Open Source.
|
||||||
|
* Copyright 2009, Red Hat, Inc. and/or it's affiliates, and individual contributors
|
||||||
|
* as indicated by the @author tags. See the copyright.txt file in the
|
||||||
|
* distribution for a full listing of individual contributors.
|
||||||
|
*
|
||||||
|
* This is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU Lesser General Public License as
|
||||||
|
* published by the Free Software Foundation; either version 2.1 of
|
||||||
|
* the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This software is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this software; if not, write to the Free
|
||||||
|
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||||
|
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
|
||||||
|
*/
|
||||||
|
package org.hibernate.test.cache.infinispan.functional.cluster;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import javax.transaction.TransactionManager;
|
||||||
|
|
||||||
|
import org.hibernate.Session;
|
||||||
|
import org.hibernate.SessionFactory;
|
||||||
|
import org.hibernate.cache.CacheKey;
|
||||||
|
import org.hibernate.test.cache.infinispan.functional.Contact;
|
||||||
|
import org.hibernate.test.cache.infinispan.functional.Customer;
|
||||||
|
import org.infinispan.Cache;
|
||||||
|
import org.infinispan.manager.CacheManager;
|
||||||
|
import org.infinispan.marshall.MarshalledValue;
|
||||||
|
import org.infinispan.notifications.Listener;
|
||||||
|
import org.infinispan.notifications.cachelistener.annotation.CacheEntryVisited;
|
||||||
|
import org.infinispan.notifications.cachelistener.event.CacheEntryVisitedEvent;
|
||||||
|
import org.jboss.util.collection.ConcurrentSet;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* EntityCollectionInvalidationTestCase.
|
||||||
|
*
|
||||||
|
* @author Galder Zamarreño
|
||||||
|
* @since 3.5
|
||||||
|
*/
|
||||||
|
public class EntityCollectionInvalidationTestCase extends AbstractDualNodeTestCase {
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(EntityCollectionInvalidationTestCase.class);
|
||||||
|
private static final long SLEEP_TIME = 50l;
|
||||||
|
private static final Integer CUSTOMER_ID = new Integer(1);
|
||||||
|
static int test = 0;
|
||||||
|
|
||||||
|
public EntityCollectionInvalidationTestCase(String string) {
|
||||||
|
super(string);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String getEntityCacheConfigName() {
|
||||||
|
return "entity";
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testAll() throws Exception {
|
||||||
|
log.info("*** testAll()");
|
||||||
|
|
||||||
|
// Bind a listener to the "local" cache
|
||||||
|
// Our region factory makes its CacheManager available to us
|
||||||
|
CacheManager localManager = ClusterAwareRegionFactory.getCacheManager(AbstractDualNodeTestCase.LOCAL);
|
||||||
|
// Cache localCache = localManager.getCache("entity");
|
||||||
|
Cache localCustomerCache = localManager.getCache(Customer.class.getName());
|
||||||
|
Cache localContactCache = localManager.getCache(Contact.class.getName());
|
||||||
|
Cache localCollectionCache = localManager.getCache(Customer.class.getName() + ".contacts");
|
||||||
|
MyListener localListener = new MyListener("local");
|
||||||
|
localCustomerCache.addListener(localListener);
|
||||||
|
localContactCache.addListener(localListener);
|
||||||
|
localCollectionCache.addListener(localListener);
|
||||||
|
TransactionManager localTM = DualNodeJtaTransactionManagerImpl.getInstance(AbstractDualNodeTestCase.LOCAL);
|
||||||
|
|
||||||
|
// Bind a listener to the "remote" cache
|
||||||
|
CacheManager remoteManager = ClusterAwareRegionFactory.getCacheManager(AbstractDualNodeTestCase.REMOTE);
|
||||||
|
Cache remoteCustomerCache = remoteManager.getCache(Customer.class.getName());
|
||||||
|
Cache remoteContactCache = remoteManager.getCache(Contact.class.getName());
|
||||||
|
Cache remoteCollectionCache = remoteManager.getCache(Customer.class.getName() + ".contacts");
|
||||||
|
MyListener remoteListener = new MyListener("remote");
|
||||||
|
remoteCustomerCache.addListener(remoteListener);
|
||||||
|
remoteContactCache.addListener(remoteListener);
|
||||||
|
remoteCollectionCache.addListener(remoteListener);
|
||||||
|
TransactionManager remoteTM = DualNodeJtaTransactionManagerImpl.getInstance(AbstractDualNodeTestCase.REMOTE);
|
||||||
|
|
||||||
|
SessionFactory localFactory = getEnvironment().getSessionFactory();
|
||||||
|
SessionFactory remoteFactory = getSecondNodeEnvironment().getSessionFactory();
|
||||||
|
|
||||||
|
try {
|
||||||
|
assertTrue(remoteListener.isEmpty());
|
||||||
|
assertTrue(localListener.isEmpty());
|
||||||
|
|
||||||
|
log.debug("Create node 0");
|
||||||
|
IdContainer ids = createCustomer(localFactory, localTM);
|
||||||
|
|
||||||
|
assertTrue(remoteListener.isEmpty());
|
||||||
|
assertTrue(localListener.isEmpty());
|
||||||
|
|
||||||
|
// Sleep a bit to let async commit propagate. Really just to
|
||||||
|
// help keep the logs organized for debugging any issues
|
||||||
|
sleep(SLEEP_TIME);
|
||||||
|
|
||||||
|
log.debug("Find node 0");
|
||||||
|
// This actually brings the collection into the cache
|
||||||
|
getCustomer(ids.customerId, localFactory, localTM);
|
||||||
|
|
||||||
|
sleep(SLEEP_TIME);
|
||||||
|
|
||||||
|
// Now the collection is in the cache so, the 2nd "get"
|
||||||
|
// should read everything from the cache
|
||||||
|
log.debug("Find(2) node 0");
|
||||||
|
localListener.clear();
|
||||||
|
getCustomer(ids.customerId, localFactory, localTM);
|
||||||
|
|
||||||
|
// Check the read came from the cache
|
||||||
|
log.debug("Check cache 0");
|
||||||
|
assertLoadedFromCache(localListener, ids.customerId, ids.contactIds);
|
||||||
|
|
||||||
|
log.debug("Find node 1");
|
||||||
|
// This actually brings the collection into the cache since invalidation is in use
|
||||||
|
getCustomer(ids.customerId, remoteFactory, remoteTM);
|
||||||
|
|
||||||
|
// Now the collection is in the cache so, the 2nd "get"
|
||||||
|
// should read everything from the cache
|
||||||
|
log.debug("Find(2) node 1");
|
||||||
|
remoteListener.clear();
|
||||||
|
getCustomer(ids.customerId, remoteFactory, remoteTM);
|
||||||
|
|
||||||
|
// Check the read came from the cache
|
||||||
|
log.debug("Check cache 1");
|
||||||
|
assertLoadedFromCache(remoteListener, ids.customerId, ids.contactIds);
|
||||||
|
|
||||||
|
// Modify customer in remote
|
||||||
|
remoteListener.clear();
|
||||||
|
ids = modifyCustomer(ids.customerId, remoteFactory, remoteTM);
|
||||||
|
sleep(250);
|
||||||
|
assertLoadedFromCache(remoteListener, ids.customerId, ids.contactIds);
|
||||||
|
|
||||||
|
// After modification, local cache should have been invalidated and hence should be empty
|
||||||
|
assertTrue(localCollectionCache.isEmpty());
|
||||||
|
assertTrue(localCustomerCache.isEmpty());
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Error", e);
|
||||||
|
throw e;
|
||||||
|
} finally {
|
||||||
|
// cleanup the db
|
||||||
|
log.debug("Cleaning up");
|
||||||
|
cleanup(localFactory, localTM);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private IdContainer createCustomer(SessionFactory sessionFactory, TransactionManager tm)
|
||||||
|
throws Exception {
|
||||||
|
log.debug("CREATE CUSTOMER");
|
||||||
|
|
||||||
|
tm.begin();
|
||||||
|
|
||||||
|
try {
|
||||||
|
Session session = sessionFactory.getCurrentSession();
|
||||||
|
Customer customer = new Customer();
|
||||||
|
customer.setName("JBoss");
|
||||||
|
Set<Contact> contacts = new HashSet<Contact>();
|
||||||
|
|
||||||
|
Contact kabir = new Contact();
|
||||||
|
kabir.setCustomer(customer);
|
||||||
|
kabir.setName("Kabir");
|
||||||
|
kabir.setTlf("1111");
|
||||||
|
contacts.add(kabir);
|
||||||
|
|
||||||
|
Contact bill = new Contact();
|
||||||
|
bill.setCustomer(customer);
|
||||||
|
bill.setName("Bill");
|
||||||
|
bill.setTlf("2222");
|
||||||
|
contacts.add(bill);
|
||||||
|
|
||||||
|
customer.setContacts(contacts);
|
||||||
|
|
||||||
|
session.save(customer);
|
||||||
|
tm.commit();
|
||||||
|
|
||||||
|
IdContainer ids = new IdContainer();
|
||||||
|
ids.customerId = customer.getId();
|
||||||
|
Set contactIds = new HashSet();
|
||||||
|
contactIds.add(kabir.getId());
|
||||||
|
contactIds.add(bill.getId());
|
||||||
|
ids.contactIds = contactIds;
|
||||||
|
|
||||||
|
return ids;
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Caught exception creating customer", e);
|
||||||
|
try {
|
||||||
|
tm.rollback();
|
||||||
|
} catch (Exception e1) {
|
||||||
|
log.error("Exception rolling back txn", e1);
|
||||||
|
}
|
||||||
|
throw e;
|
||||||
|
} finally {
|
||||||
|
log.debug("CREATE CUSTOMER - END");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Customer getCustomer(Integer id, SessionFactory sessionFactory, TransactionManager tm) throws Exception {
|
||||||
|
log.debug("Find customer with id=" + id);
|
||||||
|
tm.begin();
|
||||||
|
try {
|
||||||
|
Session session = sessionFactory.getCurrentSession();
|
||||||
|
Customer customer = doGetCustomer(id, session, tm);
|
||||||
|
tm.commit();
|
||||||
|
return customer;
|
||||||
|
} catch (Exception e) {
|
||||||
|
try {
|
||||||
|
tm.rollback();
|
||||||
|
} catch (Exception e1) {
|
||||||
|
log.error("Exception rolling back txn", e1);
|
||||||
|
}
|
||||||
|
throw e;
|
||||||
|
} finally {
|
||||||
|
log.debug("Find customer ended.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Customer doGetCustomer(Integer id, Session session, TransactionManager tm) throws Exception {
|
||||||
|
Customer customer = (Customer) session.get(Customer.class, id);
|
||||||
|
// Access all the contacts
|
||||||
|
for (Iterator it = customer.getContacts().iterator(); it.hasNext();) {
|
||||||
|
((Contact) it.next()).getName();
|
||||||
|
}
|
||||||
|
return customer;
|
||||||
|
}
|
||||||
|
|
||||||
|
private IdContainer modifyCustomer(Integer id, SessionFactory sessionFactory, TransactionManager tm) throws Exception {
|
||||||
|
log.debug("Modify customer with id=" + id);
|
||||||
|
tm.begin();
|
||||||
|
try {
|
||||||
|
Session session = sessionFactory.getCurrentSession();
|
||||||
|
IdContainer ids = new IdContainer();
|
||||||
|
Set contactIds = new HashSet();
|
||||||
|
Customer customer = doGetCustomer(id, session, tm);
|
||||||
|
customer.setName("NewJBoss");
|
||||||
|
ids.customerId = customer.getId();
|
||||||
|
|
||||||
|
// Set<Contact> contacts = customer.getContacts();
|
||||||
|
// for (Contact c : contacts) {
|
||||||
|
// if (c.getName().equals("Kabir")) {
|
||||||
|
// contacts.remove(c);
|
||||||
|
// } else {
|
||||||
|
// contactIds.add(c.getId());
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// ids.contactIds = contactIds;
|
||||||
|
// customer.setContacts(contacts);
|
||||||
|
Set<Contact> contacts = customer.getContacts();
|
||||||
|
for (Contact c : contacts) {
|
||||||
|
contactIds.add(c.getId());
|
||||||
|
}
|
||||||
|
Contact contact = contacts.iterator().next();
|
||||||
|
contacts.remove(contact);
|
||||||
|
contactIds.remove(contact.getId());
|
||||||
|
ids.contactIds = contactIds;
|
||||||
|
contact.setCustomer(null);
|
||||||
|
|
||||||
|
session.save(customer);
|
||||||
|
tm.commit();
|
||||||
|
return ids;
|
||||||
|
} catch (Exception e) {
|
||||||
|
try {
|
||||||
|
tm.rollback();
|
||||||
|
} catch (Exception e1) {
|
||||||
|
log.error("Exception rolling back txn", e1);
|
||||||
|
}
|
||||||
|
throw e;
|
||||||
|
} finally {
|
||||||
|
log.debug("Find customer ended.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void cleanup(SessionFactory sessionFactory, TransactionManager tm) throws Exception {
|
||||||
|
tm.begin();
|
||||||
|
try {
|
||||||
|
Session session = sessionFactory.getCurrentSession();
|
||||||
|
Customer c = (Customer) session.get(Customer.class, CUSTOMER_ID);
|
||||||
|
if (c != null) {
|
||||||
|
Set contacts = c.getContacts();
|
||||||
|
for (Iterator it = contacts.iterator(); it.hasNext();)
|
||||||
|
session.delete(it.next());
|
||||||
|
c.setContacts(null);
|
||||||
|
session.delete(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
tm.commit();
|
||||||
|
} catch (Exception e) {
|
||||||
|
try {
|
||||||
|
tm.rollback();
|
||||||
|
} catch (Exception e1) {
|
||||||
|
log.error("Exception rolling back txn", e1);
|
||||||
|
}
|
||||||
|
log.error("Caught exception in cleanup", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertLoadedFromCache(MyListener listener, Integer custId, Set contactIds) {
|
||||||
|
assertTrue("Customer#" + custId + " was in cache", listener.visited.contains("Customer#"
|
||||||
|
+ custId));
|
||||||
|
for (Iterator it = contactIds.iterator(); it.hasNext();) {
|
||||||
|
Integer contactId = (Integer) it.next();
|
||||||
|
assertTrue("Contact#" + contactId + " was in cache", listener.visited.contains("Contact#"
|
||||||
|
+ contactId));
|
||||||
|
assertTrue("Contact#" + contactId + " was in cache", listener.visited.contains("Contact#"
|
||||||
|
+ contactId));
|
||||||
|
}
|
||||||
|
assertTrue("Customer.contacts" + custId + " was in cache", listener.visited
|
||||||
|
.contains("Customer.contacts#" + custId));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Listener
|
||||||
|
public static class MyListener {
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(MyListener.class);
|
||||||
|
private Set<String> visited = new ConcurrentSet<String>();
|
||||||
|
private final String name;
|
||||||
|
|
||||||
|
public MyListener(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clear() {
|
||||||
|
visited.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isEmpty() {
|
||||||
|
return visited.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@CacheEntryVisited
|
||||||
|
public void nodeVisited(CacheEntryVisitedEvent event) {
|
||||||
|
log.debug(event.toString());
|
||||||
|
if (!event.isPre()) {
|
||||||
|
MarshalledValue mv = (MarshalledValue) event.getKey();
|
||||||
|
CacheKey cacheKey = (CacheKey) mv.get();
|
||||||
|
Integer primKey = (Integer) cacheKey.getKey();
|
||||||
|
String key = (String) cacheKey.getEntityOrRoleName() + '#' + primKey;
|
||||||
|
log.debug("MyListener[" + name +"] - Visiting key " + key);
|
||||||
|
// String name = fqn.toString();
|
||||||
|
String token = ".functional.";
|
||||||
|
int index = key.indexOf(token);
|
||||||
|
if (index > -1) {
|
||||||
|
index += token.length();
|
||||||
|
key = key.substring(index);
|
||||||
|
log.debug("MyListener[" + name +"] - recording visit to " + key);
|
||||||
|
visited.add(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// @CacheEntryModified
|
||||||
|
// public void nodeModified(CacheEntryModifiedEvent event) {
|
||||||
|
// log.debug(event.toString());
|
||||||
|
// if (!event.isPre()) {
|
||||||
|
// MarshalledValue mv = (MarshalledValue) event.getKey();
|
||||||
|
// CacheKey cacheKey = (CacheKey) mv.get();
|
||||||
|
// Integer primKey = (Integer) cacheKey.getKey();
|
||||||
|
// String key = (String) cacheKey.getEntityOrRoleName() + '#' + primKey;
|
||||||
|
// log.debug("MyListener[" + name +"] - Modified key " + key);
|
||||||
|
// // String name = fqn.toString();
|
||||||
|
// String token = ".functional.";
|
||||||
|
// int index = key.indexOf(token);
|
||||||
|
// if (index > -1) {
|
||||||
|
// index += token.length();
|
||||||
|
// key = key.substring(index);
|
||||||
|
// log.debug("MyListener[" + name +"] - recording modification of " + key);
|
||||||
|
// visited.add(key);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
private class IdContainer {
|
||||||
|
Integer customerId;
|
||||||
|
Set<Integer> contactIds;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,131 @@
|
||||||
|
/*
|
||||||
|
* JBoss, Home of Professional Open Source.
|
||||||
|
* Copyright 2009, Red Hat, Inc. and/or it's affiliates, and individual contributors
|
||||||
|
* as indicated by the @author tags. See the copyright.txt file in the
|
||||||
|
* distribution for a full listing of individual contributors.
|
||||||
|
*
|
||||||
|
* This is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU Lesser General Public License as
|
||||||
|
* published by the Free Software Foundation; either version 2.1 of
|
||||||
|
* the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This software is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this software; if not, write to the Free
|
||||||
|
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||||
|
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
|
||||||
|
*/
|
||||||
|
package org.hibernate.test.cache.infinispan.functional.cluster;
|
||||||
|
|
||||||
|
import javax.transaction.TransactionManager;
|
||||||
|
|
||||||
|
import org.hibernate.SessionFactory;
|
||||||
|
import org.hibernate.cfg.Configuration;
|
||||||
|
import org.hibernate.cfg.Environment;
|
||||||
|
import org.hibernate.test.cache.infinispan.functional.classloader.Account;
|
||||||
|
import org.hibernate.test.cache.infinispan.functional.classloader.ClassLoaderTestDAO;
|
||||||
|
import org.infinispan.Cache;
|
||||||
|
import org.infinispan.manager.CacheManager;
|
||||||
|
import org.infinispan.test.TestingUtil;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SessionRefreshTestCase.
|
||||||
|
*
|
||||||
|
* @author Galder Zamarreño
|
||||||
|
* @since 3.5
|
||||||
|
*/
|
||||||
|
public class SessionRefreshTestCase extends AbstractDualNodeTestCase {
|
||||||
|
|
||||||
|
public static final String OUR_PACKAGE = SessionRefreshTestCase.class.getPackage().getName();
|
||||||
|
|
||||||
|
protected final Logger log = LoggerFactory.getLogger(getClass());
|
||||||
|
|
||||||
|
static int test = 0;
|
||||||
|
|
||||||
|
private Cache localCache;
|
||||||
|
|
||||||
|
public SessionRefreshTestCase(String string) {
|
||||||
|
super(string);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String getEntityCacheConfigName() {
|
||||||
|
return "entity";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disables use of the second level cache for this session factory.
|
||||||
|
*
|
||||||
|
* {@inheritDoc}
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected void configureSecondNode(Configuration cfg) {
|
||||||
|
super.configureSecondNode(cfg);
|
||||||
|
cfg.setProperty(Environment.USE_SECOND_LEVEL_CACHE, "false");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String[] getMappings() {
|
||||||
|
return new String[] { "cache/infinispan/functional/classloader/Account.hbm.xml" };
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void cleanupTransactionManagement() {
|
||||||
|
// Don't clean up the managers, just the transactions
|
||||||
|
// Managers are still needed by the long-lived caches
|
||||||
|
DualNodeJtaTransactionManagerImpl.cleanupTransactions();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testRefreshAfterExternalChange() throws Exception {
|
||||||
|
// First session factory uses a cache
|
||||||
|
CacheManager localManager = ClusterAwareRegionFactory.getCacheManager(AbstractDualNodeTestCase.LOCAL);
|
||||||
|
localCache = localManager.getCache(Account.class.getName());
|
||||||
|
TransactionManager localTM = DualNodeJtaTransactionManagerImpl.getInstance(AbstractDualNodeTestCase.LOCAL);
|
||||||
|
SessionFactory localFactory = getEnvironment().getSessionFactory();
|
||||||
|
|
||||||
|
// Second session factory doesn't; just needs a transaction manager
|
||||||
|
TransactionManager remoteTM = DualNodeJtaTransactionManagerImpl.getInstance(AbstractDualNodeTestCase.REMOTE);
|
||||||
|
SessionFactory remoteFactory = getSecondNodeEnvironment().getSessionFactory();
|
||||||
|
|
||||||
|
ClassLoaderTestDAO dao0 = new ClassLoaderTestDAO(localFactory, localTM);
|
||||||
|
ClassLoaderTestDAO dao1 = new ClassLoaderTestDAO(remoteFactory, remoteTM);
|
||||||
|
|
||||||
|
Integer id = new Integer(1);
|
||||||
|
dao0.createAccount(dao0.getSmith(), id, new Integer(5), AbstractDualNodeTestCase.LOCAL);
|
||||||
|
|
||||||
|
// Basic sanity check
|
||||||
|
Account acct1 = dao1.getAccount(id);
|
||||||
|
assertNotNull(acct1);
|
||||||
|
assertEquals(AbstractDualNodeTestCase.LOCAL, acct1.getBranch());
|
||||||
|
|
||||||
|
// This dao's session factory isn't caching, so cache won't see this change
|
||||||
|
dao1.updateAccountBranch(id, AbstractDualNodeTestCase.REMOTE);
|
||||||
|
|
||||||
|
// dao1's session doesn't touch the cache,
|
||||||
|
// so reading from dao0 should show a stale value from the cache
|
||||||
|
// (we check to confirm the cache is used)
|
||||||
|
Account acct0 = dao0.getAccount(id);
|
||||||
|
assertNotNull(acct0);
|
||||||
|
assertEquals(AbstractDualNodeTestCase.LOCAL, acct0.getBranch());
|
||||||
|
log.debug("Contents when re-reading from local: " + TestingUtil.printCache(localCache));
|
||||||
|
|
||||||
|
// Now call session.refresh and confirm we get the correct value
|
||||||
|
acct0 = dao0.getAccountWithRefresh(id);
|
||||||
|
assertNotNull(acct0);
|
||||||
|
assertEquals(AbstractDualNodeTestCase.REMOTE, acct0.getBranch());
|
||||||
|
log.debug("Contents after refreshing in remote: " + TestingUtil.printCache(localCache));
|
||||||
|
|
||||||
|
// Double check with a brand new session, in case the other session
|
||||||
|
// for some reason bypassed the 2nd level cache
|
||||||
|
ClassLoaderTestDAO dao0A = new ClassLoaderTestDAO(localFactory, localTM);
|
||||||
|
Account acct0A = dao0A.getAccount(id);
|
||||||
|
assertNotNull(acct0A);
|
||||||
|
assertEquals(AbstractDualNodeTestCase.REMOTE, acct0A.getBranch());
|
||||||
|
log.debug("Contents after creating a new session: " + TestingUtil.printCache(localCache));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,303 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2007, Red Hat, Inc. and/or it's affiliates or third-party contributors as
|
||||||
|
* indicated by the @author tags or express copyright attribution
|
||||||
|
* statements applied by the authors. All third-party contributions are
|
||||||
|
* distributed under license by Red Hat, Inc. and/or it's affiliates.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||||
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
* Lesser General Public License, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this distribution; if not, write to:
|
||||||
|
* Free Software Foundation, Inc.
|
||||||
|
* 51 Franklin Street, Fifth Floor
|
||||||
|
* Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
package org.hibernate.test.cache.infinispan.query;
|
||||||
|
|
||||||
|
import java.util.Properties;
|
||||||
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import junit.framework.AssertionFailedError;
|
||||||
|
|
||||||
|
import org.hibernate.cache.CacheDataDescription;
|
||||||
|
import org.hibernate.cache.QueryResultsRegion;
|
||||||
|
import org.hibernate.cache.Region;
|
||||||
|
import org.hibernate.cache.StandardQueryCache;
|
||||||
|
import org.hibernate.cache.infinispan.InfinispanRegionFactory;
|
||||||
|
import org.hibernate.cfg.Configuration;
|
||||||
|
import org.hibernate.test.cache.infinispan.AbstractGeneralDataRegionTestCase;
|
||||||
|
import org.hibernate.test.cache.infinispan.util.CacheTestUtil;
|
||||||
|
import org.infinispan.Cache;
|
||||||
|
import org.infinispan.notifications.Listener;
|
||||||
|
import org.infinispan.notifications.cachelistener.annotation.CacheEntryVisited;
|
||||||
|
import org.infinispan.notifications.cachelistener.event.CacheEntryVisitedEvent;
|
||||||
|
import org.infinispan.transaction.tm.BatchModeTransactionManager;
|
||||||
|
import org.infinispan.util.concurrent.IsolationLevel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests of QueryResultRegionImpl.
|
||||||
|
*
|
||||||
|
* @author Galder Zamarreño
|
||||||
|
* @since 3.5
|
||||||
|
*/
|
||||||
|
public class QueryRegionImplTestCase extends AbstractGeneralDataRegionTestCase {
|
||||||
|
|
||||||
|
// protected static final String REGION_NAME = "test/" + StandardQueryCache.class.getName();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new EntityRegionImplTestCase.
|
||||||
|
*
|
||||||
|
* @param name
|
||||||
|
*/
|
||||||
|
public QueryRegionImplTestCase(String name) {
|
||||||
|
super(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Region createRegion(InfinispanRegionFactory regionFactory, String regionName, Properties properties, CacheDataDescription cdd) {
|
||||||
|
return regionFactory.buildQueryResultsRegion(regionName, properties);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getStandardRegionName(String regionPrefix) {
|
||||||
|
return regionPrefix + "/" + StandardQueryCache.class.getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Cache getInfinispanCache(InfinispanRegionFactory regionFactory) {
|
||||||
|
return regionFactory.getCacheManager().getCache("local-query");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Configuration createConfiguration() {
|
||||||
|
return CacheTestUtil.buildCustomQueryCacheConfiguration("test", "replicated-query");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testPutDoesNotBlockGet() throws Exception {
|
||||||
|
putDoesNotBlockGetTest();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void putDoesNotBlockGetTest() throws Exception {
|
||||||
|
Configuration cfg = createConfiguration();
|
||||||
|
InfinispanRegionFactory regionFactory = CacheTestUtil.startRegionFactory(cfg, getCacheTestSupport());
|
||||||
|
|
||||||
|
// Sleep a bit to avoid concurrent FLUSH problem
|
||||||
|
avoidConcurrentFlush();
|
||||||
|
|
||||||
|
final QueryResultsRegion region = regionFactory.buildQueryResultsRegion(getStandardRegionName(REGION_PREFIX), cfg
|
||||||
|
.getProperties());
|
||||||
|
|
||||||
|
region.put(KEY, VALUE1);
|
||||||
|
assertEquals(VALUE1, region.get(KEY));
|
||||||
|
|
||||||
|
final CountDownLatch readerLatch = new CountDownLatch(1);
|
||||||
|
final CountDownLatch writerLatch = new CountDownLatch(1);
|
||||||
|
final CountDownLatch completionLatch = new CountDownLatch(1);
|
||||||
|
final ExceptionHolder holder = new ExceptionHolder();
|
||||||
|
|
||||||
|
Thread reader = new Thread() {
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
BatchModeTransactionManager.getInstance().begin();
|
||||||
|
log.debug("Transaction began, get value for key");
|
||||||
|
assertTrue(VALUE2.equals(region.get(KEY)) == false);
|
||||||
|
BatchModeTransactionManager.getInstance().commit();
|
||||||
|
} catch (AssertionFailedError e) {
|
||||||
|
holder.a1 = e;
|
||||||
|
rollback();
|
||||||
|
} catch (Exception e) {
|
||||||
|
holder.e1 = e;
|
||||||
|
rollback();
|
||||||
|
} finally {
|
||||||
|
readerLatch.countDown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Thread writer = new Thread() {
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
BatchModeTransactionManager.getInstance().begin();
|
||||||
|
log.debug("Put value2");
|
||||||
|
region.put(KEY, VALUE2);
|
||||||
|
log.debug("Put finished for value2, await writer latch");
|
||||||
|
writerLatch.await();
|
||||||
|
log.debug("Writer latch finished");
|
||||||
|
BatchModeTransactionManager.getInstance().commit();
|
||||||
|
log.debug("Transaction committed");
|
||||||
|
} catch (Exception e) {
|
||||||
|
holder.e2 = e;
|
||||||
|
rollback();
|
||||||
|
} finally {
|
||||||
|
completionLatch.countDown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
reader.setDaemon(true);
|
||||||
|
writer.setDaemon(true);
|
||||||
|
|
||||||
|
writer.start();
|
||||||
|
assertFalse("Writer is blocking", completionLatch.await(100, TimeUnit.MILLISECONDS));
|
||||||
|
|
||||||
|
// Start the reader
|
||||||
|
reader.start();
|
||||||
|
assertTrue("Reader finished promptly", readerLatch.await(1000000000, TimeUnit.MILLISECONDS));
|
||||||
|
|
||||||
|
writerLatch.countDown();
|
||||||
|
assertTrue("Reader finished promptly", completionLatch.await(100, TimeUnit.MILLISECONDS));
|
||||||
|
|
||||||
|
assertEquals(VALUE2, region.get(KEY));
|
||||||
|
|
||||||
|
if (holder.a1 != null)
|
||||||
|
throw holder.a1;
|
||||||
|
else if (holder.a2 != null)
|
||||||
|
throw holder.a2;
|
||||||
|
|
||||||
|
assertEquals("writer saw no exceptions", null, holder.e1);
|
||||||
|
assertEquals("reader saw no exceptions", null, holder.e2);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testGetDoesNotBlockPut() throws Exception {
|
||||||
|
getDoesNotBlockPutTest();
|
||||||
|
}
|
||||||
|
|
||||||
|
// public void testGetDoesNotBlockPutPessimisticRepeatableRead() throws Exception {
|
||||||
|
// getDoesNotBlockPutTest();
|
||||||
|
// }
|
||||||
|
|
||||||
|
private void getDoesNotBlockPutTest() throws Exception {
|
||||||
|
Configuration cfg = createConfiguration();
|
||||||
|
InfinispanRegionFactory regionFactory = CacheTestUtil.startRegionFactory(cfg, getCacheTestSupport());
|
||||||
|
|
||||||
|
// Sleep a bit to avoid concurrent FLUSH problem
|
||||||
|
avoidConcurrentFlush();
|
||||||
|
|
||||||
|
final QueryResultsRegion region = regionFactory.buildQueryResultsRegion(getStandardRegionName(REGION_PREFIX), cfg
|
||||||
|
.getProperties());
|
||||||
|
|
||||||
|
region.put(KEY, VALUE1);
|
||||||
|
assertEquals(VALUE1, region.get(KEY));
|
||||||
|
|
||||||
|
// final Fqn rootFqn = getRegionFqn(getStandardRegionName(REGION_PREFIX), REGION_PREFIX);
|
||||||
|
final Cache jbc = getInfinispanCache(regionFactory);
|
||||||
|
|
||||||
|
final CountDownLatch blockerLatch = new CountDownLatch(1);
|
||||||
|
final CountDownLatch writerLatch = new CountDownLatch(1);
|
||||||
|
final CountDownLatch completionLatch = new CountDownLatch(1);
|
||||||
|
final ExceptionHolder holder = new ExceptionHolder();
|
||||||
|
|
||||||
|
Thread blocker = new Thread() {
|
||||||
|
|
||||||
|
public void run() {
|
||||||
|
// Fqn toBlock = new Fqn(rootFqn, KEY);
|
||||||
|
GetBlocker blocker = new GetBlocker(blockerLatch, KEY);
|
||||||
|
try {
|
||||||
|
jbc.addListener(blocker);
|
||||||
|
|
||||||
|
BatchModeTransactionManager.getInstance().begin();
|
||||||
|
region.get(KEY);
|
||||||
|
BatchModeTransactionManager.getInstance().commit();
|
||||||
|
} catch (Exception e) {
|
||||||
|
holder.e1 = e;
|
||||||
|
rollback();
|
||||||
|
} finally {
|
||||||
|
jbc.removeListener(blocker);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Thread writer = new Thread() {
|
||||||
|
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
writerLatch.await();
|
||||||
|
|
||||||
|
BatchModeTransactionManager.getInstance().begin();
|
||||||
|
region.put(KEY, VALUE2);
|
||||||
|
BatchModeTransactionManager.getInstance().commit();
|
||||||
|
} catch (Exception e) {
|
||||||
|
holder.e2 = e;
|
||||||
|
rollback();
|
||||||
|
} finally {
|
||||||
|
completionLatch.countDown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
blocker.setDaemon(true);
|
||||||
|
writer.setDaemon(true);
|
||||||
|
|
||||||
|
boolean unblocked = false;
|
||||||
|
try {
|
||||||
|
blocker.start();
|
||||||
|
writer.start();
|
||||||
|
|
||||||
|
assertFalse("Blocker is blocking", completionLatch.await(100, TimeUnit.MILLISECONDS));
|
||||||
|
// Start the writer
|
||||||
|
writerLatch.countDown();
|
||||||
|
assertTrue("Writer finished promptly", completionLatch.await(100, TimeUnit.MILLISECONDS));
|
||||||
|
|
||||||
|
blockerLatch.countDown();
|
||||||
|
unblocked = true;
|
||||||
|
|
||||||
|
if (IsolationLevel.REPEATABLE_READ.equals(jbc.getConfiguration().getIsolationLevel())) {
|
||||||
|
assertEquals(VALUE1, region.get(KEY));
|
||||||
|
} else {
|
||||||
|
assertEquals(VALUE2, region.get(KEY));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (holder.a1 != null)
|
||||||
|
throw holder.a1;
|
||||||
|
else if (holder.a2 != null)
|
||||||
|
throw holder.a2;
|
||||||
|
|
||||||
|
assertEquals("blocker saw no exceptions", null, holder.e1);
|
||||||
|
assertEquals("writer saw no exceptions", null, holder.e2);
|
||||||
|
} finally {
|
||||||
|
if (!unblocked)
|
||||||
|
blockerLatch.countDown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Listener
|
||||||
|
public class GetBlocker {
|
||||||
|
|
||||||
|
private CountDownLatch latch;
|
||||||
|
// private Fqn fqn;
|
||||||
|
private Object key;
|
||||||
|
|
||||||
|
GetBlocker(CountDownLatch latch, Object key) {
|
||||||
|
this.latch = latch;
|
||||||
|
this.key = key;
|
||||||
|
}
|
||||||
|
|
||||||
|
@CacheEntryVisited
|
||||||
|
public void nodeVisisted(CacheEntryVisitedEvent event) {
|
||||||
|
if (event.isPre() && event.getKey().equals(key)) {
|
||||||
|
try {
|
||||||
|
latch.await();
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
log.error("Interrupted waiting for latch", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ExceptionHolder {
|
||||||
|
Exception e1;
|
||||||
|
Exception e2;
|
||||||
|
AssertionFailedError a1;
|
||||||
|
AssertionFailedError a2;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,62 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2007, Red Hat, Inc. and/or it's affiliates or third-party contributors as
|
||||||
|
* indicated by the @author tags or express copyright attribution
|
||||||
|
* statements applied by the authors. All third-party contributions are
|
||||||
|
* distributed under license by Red Hat, Inc. and/or it's affiliates.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||||
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
* Lesser General Public License, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this distribution; if not, write to:
|
||||||
|
* Free Software Foundation, Inc.
|
||||||
|
* 51 Franklin Street, Fifth Floor
|
||||||
|
* Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
package org.hibernate.test.cache.infinispan.timestamp;
|
||||||
|
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
import org.hibernate.cache.CacheDataDescription;
|
||||||
|
import org.hibernate.cache.Region;
|
||||||
|
import org.hibernate.cache.UpdateTimestampsCache;
|
||||||
|
import org.hibernate.cache.infinispan.InfinispanRegionFactory;
|
||||||
|
import org.hibernate.test.cache.infinispan.AbstractGeneralDataRegionTestCase;
|
||||||
|
import org.infinispan.Cache;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests of TimestampsRegionImpl.
|
||||||
|
*
|
||||||
|
* @author Galder Zamarreño
|
||||||
|
* @since 3.5
|
||||||
|
*/
|
||||||
|
public class TimestampsRegionImplTestCase extends AbstractGeneralDataRegionTestCase {
|
||||||
|
|
||||||
|
public TimestampsRegionImplTestCase(String name) {
|
||||||
|
super(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getStandardRegionName(String regionPrefix) {
|
||||||
|
return regionPrefix + "/" + UpdateTimestampsCache.class.getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Region createRegion(InfinispanRegionFactory regionFactory, String regionName, Properties properties, CacheDataDescription cdd) {
|
||||||
|
return regionFactory.buildTimestampsRegion(regionName, properties);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Cache getInfinispanCache(InfinispanRegionFactory regionFactory) {
|
||||||
|
return regionFactory.getCacheManager().getCache("timestamps");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
78
cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/tm/XaConnectionProvider.java
vendored
Normal file
78
cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/tm/XaConnectionProvider.java
vendored
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
/*
|
||||||
|
* JBoss, Home of Professional Open Source.
|
||||||
|
* Copyright 2009, Red Hat, Inc. and/or it's affiliates, and individual contributors
|
||||||
|
* as indicated by the @author tags. See the copyright.txt file in the
|
||||||
|
* distribution for a full listing of individual contributors.
|
||||||
|
*
|
||||||
|
* This is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU Lesser General Public License as
|
||||||
|
* published by the Free Software Foundation; either version 2.1 of
|
||||||
|
* the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This software is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this software; if not, write to the Free
|
||||||
|
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||||
|
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
|
||||||
|
*/
|
||||||
|
package org.hibernate.test.cache.infinispan.tm;
|
||||||
|
|
||||||
|
import java.sql.Connection;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
import org.hibernate.HibernateException;
|
||||||
|
import org.hibernate.connection.ConnectionProvider;
|
||||||
|
import org.hibernate.connection.ConnectionProviderFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* XaConnectionProvider.
|
||||||
|
*
|
||||||
|
* @author Galder Zamarreño
|
||||||
|
* @since 3.5
|
||||||
|
*/
|
||||||
|
public class XaConnectionProvider implements ConnectionProvider {
|
||||||
|
private static ConnectionProvider actualConnectionProvider = ConnectionProviderFactory.newConnectionProvider();
|
||||||
|
private boolean isTransactional;
|
||||||
|
|
||||||
|
public static ConnectionProvider getActualConnectionProvider() {
|
||||||
|
return actualConnectionProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void configure(Properties props) throws HibernateException {
|
||||||
|
}
|
||||||
|
|
||||||
|
public Connection getConnection() throws SQLException {
|
||||||
|
XaTransactionImpl currentTransaction = XaTransactionManagerImpl.getInstance().getCurrentTransaction();
|
||||||
|
if (currentTransaction == null) {
|
||||||
|
isTransactional = false;
|
||||||
|
return actualConnectionProvider.getConnection();
|
||||||
|
} else {
|
||||||
|
isTransactional = true;
|
||||||
|
Connection connection = currentTransaction.getEnlistedConnection();
|
||||||
|
if (connection == null) {
|
||||||
|
connection = actualConnectionProvider.getConnection();
|
||||||
|
currentTransaction.enlistConnection(connection);
|
||||||
|
}
|
||||||
|
return connection;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void closeConnection(Connection conn) throws SQLException {
|
||||||
|
if (!isTransactional) {
|
||||||
|
conn.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void close() throws HibernateException {
|
||||||
|
actualConnectionProvider.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean supportsAggressiveRelease() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
247
cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/tm/XaTransactionImpl.java
vendored
Normal file
247
cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/tm/XaTransactionImpl.java
vendored
Normal file
|
@ -0,0 +1,247 @@
|
||||||
|
/*
|
||||||
|
* JBoss, Home of Professional Open Source.
|
||||||
|
* Copyright 2009, Red Hat, Inc. and/or it's affiliates, and individual contributors
|
||||||
|
* as indicated by the @author tags. See the copyright.txt file in the
|
||||||
|
* distribution for a full listing of individual contributors.
|
||||||
|
*
|
||||||
|
* This is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU Lesser General Public License as
|
||||||
|
* published by the Free Software Foundation; either version 2.1 of
|
||||||
|
* the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This software is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this software; if not, write to the Free
|
||||||
|
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||||
|
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
|
||||||
|
*/
|
||||||
|
package org.hibernate.test.cache.infinispan.tm;
|
||||||
|
|
||||||
|
import java.sql.Connection;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
|
import javax.transaction.HeuristicMixedException;
|
||||||
|
import javax.transaction.HeuristicRollbackException;
|
||||||
|
import javax.transaction.RollbackException;
|
||||||
|
import javax.transaction.Status;
|
||||||
|
import javax.transaction.Synchronization;
|
||||||
|
import javax.transaction.SystemException;
|
||||||
|
import javax.transaction.Transaction;
|
||||||
|
import javax.transaction.xa.XAException;
|
||||||
|
import javax.transaction.xa.XAResource;
|
||||||
|
import javax.transaction.xa.Xid;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* XaResourceCapableTransactionImpl.
|
||||||
|
*
|
||||||
|
* @author Galder Zamarreño
|
||||||
|
* @since 3.5
|
||||||
|
*/
|
||||||
|
public class XaTransactionImpl implements Transaction {
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(XaTransactionImpl.class);
|
||||||
|
private int status;
|
||||||
|
private LinkedList synchronizations;
|
||||||
|
private Connection connection; // the only resource we care about is jdbc connection
|
||||||
|
private final XaTransactionManagerImpl jtaTransactionManager;
|
||||||
|
private List<XAResource> enlistedResources = new ArrayList<XAResource>();
|
||||||
|
private Xid xid = new XaResourceCapableTransactionXid();
|
||||||
|
|
||||||
|
public XaTransactionImpl(XaTransactionManagerImpl jtaTransactionManager) {
|
||||||
|
this.jtaTransactionManager = jtaTransactionManager;
|
||||||
|
this.status = Status.STATUS_ACTIVE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getStatus() {
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void commit() throws RollbackException, HeuristicMixedException, HeuristicRollbackException,
|
||||||
|
IllegalStateException, SystemException {
|
||||||
|
|
||||||
|
if (status == Status.STATUS_MARKED_ROLLBACK) {
|
||||||
|
log.trace("on commit, status was marked for rollback-only");
|
||||||
|
rollback();
|
||||||
|
} else {
|
||||||
|
status = Status.STATUS_PREPARING;
|
||||||
|
|
||||||
|
for (int i = 0; i < synchronizations.size(); i++) {
|
||||||
|
Synchronization s = (Synchronization) synchronizations.get(i);
|
||||||
|
s.beforeCompletion();
|
||||||
|
}
|
||||||
|
|
||||||
|
// if (!runXaResourcePrepare()) {
|
||||||
|
// status = Status.STATUS_ROLLING_BACK;
|
||||||
|
// } else {
|
||||||
|
// status = Status.STATUS_PREPARED;
|
||||||
|
// }
|
||||||
|
|
||||||
|
status = Status.STATUS_COMMITTING;
|
||||||
|
|
||||||
|
if (connection != null) {
|
||||||
|
try {
|
||||||
|
connection.commit();
|
||||||
|
connection.close();
|
||||||
|
} catch (SQLException sqle) {
|
||||||
|
status = Status.STATUS_UNKNOWN;
|
||||||
|
throw new SystemException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// runXaResourceCommitTx();
|
||||||
|
|
||||||
|
status = Status.STATUS_COMMITTED;
|
||||||
|
|
||||||
|
for (int i = 0; i < synchronizations.size(); i++) {
|
||||||
|
Synchronization s = (Synchronization) synchronizations.get(i);
|
||||||
|
s.afterCompletion(status);
|
||||||
|
}
|
||||||
|
|
||||||
|
// status = Status.STATUS_NO_TRANSACTION;
|
||||||
|
jtaTransactionManager.endCurrent(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void rollback() throws IllegalStateException, SystemException {
|
||||||
|
// status = Status.STATUS_ROLLING_BACK;
|
||||||
|
// runXaResourceRollback();
|
||||||
|
status = Status.STATUS_ROLLEDBACK;
|
||||||
|
|
||||||
|
if (connection != null) {
|
||||||
|
try {
|
||||||
|
connection.rollback();
|
||||||
|
connection.close();
|
||||||
|
} catch (SQLException sqle) {
|
||||||
|
status = Status.STATUS_UNKNOWN;
|
||||||
|
throw new SystemException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < synchronizations.size(); i++) {
|
||||||
|
Synchronization s = (Synchronization) synchronizations.get(i);
|
||||||
|
s.afterCompletion(status);
|
||||||
|
}
|
||||||
|
|
||||||
|
// status = Status.STATUS_NO_TRANSACTION;
|
||||||
|
jtaTransactionManager.endCurrent(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRollbackOnly() throws IllegalStateException, SystemException {
|
||||||
|
status = Status.STATUS_MARKED_ROLLBACK;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void registerSynchronization(Synchronization synchronization) throws RollbackException,
|
||||||
|
IllegalStateException, SystemException {
|
||||||
|
// todo : find the spec-allowable statuses during which synch can be registered...
|
||||||
|
if (synchronizations == null) {
|
||||||
|
synchronizations = new LinkedList();
|
||||||
|
}
|
||||||
|
synchronizations.add(synchronization);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void enlistConnection(Connection connection) {
|
||||||
|
if (this.connection != null) {
|
||||||
|
throw new IllegalStateException("Connection already registered");
|
||||||
|
}
|
||||||
|
this.connection = connection;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Connection getEnlistedConnection() {
|
||||||
|
return connection;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean enlistResource(XAResource xaResource) throws RollbackException, IllegalStateException,
|
||||||
|
SystemException {
|
||||||
|
enlistedResources.add(xaResource);
|
||||||
|
try {
|
||||||
|
xaResource.start(xid, 0);
|
||||||
|
} catch (XAException e) {
|
||||||
|
log.error("Got an exception", e);
|
||||||
|
throw new SystemException(e.getMessage());
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean delistResource(XAResource xaResource, int i) throws IllegalStateException, SystemException {
|
||||||
|
throw new SystemException("not supported");
|
||||||
|
}
|
||||||
|
|
||||||
|
public Collection<XAResource> getEnlistedResources() {
|
||||||
|
return enlistedResources;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean runXaResourcePrepare() throws SystemException {
|
||||||
|
Collection<XAResource> resources = getEnlistedResources();
|
||||||
|
for (XAResource res : resources) {
|
||||||
|
try {
|
||||||
|
res.prepare(xid);
|
||||||
|
} catch (XAException e) {
|
||||||
|
log.trace("The resource wants to rollback!", e);
|
||||||
|
return false;
|
||||||
|
} catch (Throwable th) {
|
||||||
|
log.error("Unexpected error from resource manager!", th);
|
||||||
|
throw new SystemException(th.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void runXaResourceRollback() {
|
||||||
|
Collection<XAResource> resources = getEnlistedResources();
|
||||||
|
for (XAResource res : resources) {
|
||||||
|
try {
|
||||||
|
res.rollback(xid);
|
||||||
|
} catch (XAException e) {
|
||||||
|
log.warn("Error while rolling back",e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean runXaResourceCommitTx() throws HeuristicMixedException {
|
||||||
|
Collection<XAResource> resources = getEnlistedResources();
|
||||||
|
for (XAResource res : resources) {
|
||||||
|
try {
|
||||||
|
res.commit(xid, false);//todo we only support one phase commit for now, change this!!!
|
||||||
|
} catch (XAException e) {
|
||||||
|
log.warn("exception while committing",e);
|
||||||
|
throw new HeuristicMixedException(e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class XaResourceCapableTransactionXid implements Xid {
|
||||||
|
private static AtomicInteger txIdCounter = new AtomicInteger(0);
|
||||||
|
private int id = txIdCounter.incrementAndGet();
|
||||||
|
|
||||||
|
public int getFormatId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getGlobalTransactionId() {
|
||||||
|
throw new IllegalStateException("TODO - please implement me!!!"); //todo implement!!!
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getBranchQualifier() {
|
||||||
|
throw new IllegalStateException("TODO - please implement me!!!"); //todo implement!!!
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return getClass().getSimpleName() + "{" +
|
||||||
|
"id=" + id +
|
||||||
|
'}';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
105
cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/tm/XaTransactionManagerImpl.java
vendored
Normal file
105
cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/tm/XaTransactionManagerImpl.java
vendored
Normal file
|
@ -0,0 +1,105 @@
|
||||||
|
/*
|
||||||
|
* JBoss, Home of Professional Open Source.
|
||||||
|
* Copyright 2009, Red Hat, Inc. and/or it's affiliates, and individual contributors
|
||||||
|
* as indicated by the @author tags. See the copyright.txt file in the
|
||||||
|
* distribution for a full listing of individual contributors.
|
||||||
|
*
|
||||||
|
* This is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU Lesser General Public License as
|
||||||
|
* published by the Free Software Foundation; either version 2.1 of
|
||||||
|
* the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This software is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this software; if not, write to the Free
|
||||||
|
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||||
|
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
|
||||||
|
*/
|
||||||
|
package org.hibernate.test.cache.infinispan.tm;
|
||||||
|
|
||||||
|
import javax.transaction.HeuristicMixedException;
|
||||||
|
import javax.transaction.HeuristicRollbackException;
|
||||||
|
import javax.transaction.InvalidTransactionException;
|
||||||
|
import javax.transaction.NotSupportedException;
|
||||||
|
import javax.transaction.RollbackException;
|
||||||
|
import javax.transaction.Status;
|
||||||
|
import javax.transaction.SystemException;
|
||||||
|
import javax.transaction.Transaction;
|
||||||
|
import javax.transaction.TransactionManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* XaResourceCapableTransactionManagerImpl.
|
||||||
|
*
|
||||||
|
* @author Galder Zamarreño
|
||||||
|
* @since 3.5
|
||||||
|
*/
|
||||||
|
public class XaTransactionManagerImpl implements TransactionManager {
|
||||||
|
private static final XaTransactionManagerImpl INSTANCE = new XaTransactionManagerImpl();
|
||||||
|
private XaTransactionImpl currentTransaction;
|
||||||
|
|
||||||
|
public static XaTransactionManagerImpl getInstance() {
|
||||||
|
return INSTANCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getStatus() throws SystemException {
|
||||||
|
return currentTransaction == null ? Status.STATUS_NO_TRANSACTION : currentTransaction.getStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Transaction getTransaction() throws SystemException {
|
||||||
|
return currentTransaction;
|
||||||
|
}
|
||||||
|
|
||||||
|
public XaTransactionImpl getCurrentTransaction() {
|
||||||
|
return currentTransaction;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void begin() throws NotSupportedException, SystemException {
|
||||||
|
currentTransaction = new XaTransactionImpl(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Transaction suspend() throws SystemException {
|
||||||
|
Transaction suspended = currentTransaction;
|
||||||
|
currentTransaction = null;
|
||||||
|
return suspended;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void resume(Transaction transaction) throws InvalidTransactionException, IllegalStateException,
|
||||||
|
SystemException {
|
||||||
|
currentTransaction = (XaTransactionImpl) transaction;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void commit() throws RollbackException, HeuristicMixedException, HeuristicRollbackException,
|
||||||
|
SecurityException, IllegalStateException, SystemException {
|
||||||
|
if (currentTransaction == null) {
|
||||||
|
throw new IllegalStateException("no current transaction to commit");
|
||||||
|
}
|
||||||
|
currentTransaction.commit();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void rollback() throws IllegalStateException, SecurityException, SystemException {
|
||||||
|
if (currentTransaction == null) {
|
||||||
|
throw new IllegalStateException("no current transaction");
|
||||||
|
}
|
||||||
|
currentTransaction.rollback();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRollbackOnly() throws IllegalStateException, SystemException {
|
||||||
|
if (currentTransaction == null) {
|
||||||
|
throw new IllegalStateException("no current transaction");
|
||||||
|
}
|
||||||
|
currentTransaction.setRollbackOnly();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTransactionTimeout(int i) throws SystemException {
|
||||||
|
}
|
||||||
|
|
||||||
|
void endCurrent(Transaction transaction) {
|
||||||
|
if (transaction == currentTransaction) {
|
||||||
|
currentTransaction = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,52 @@
|
||||||
|
/*
|
||||||
|
* JBoss, Home of Professional Open Source.
|
||||||
|
* Copyright 2009, Red Hat, Inc. and/or it's affiliates, and individual contributors
|
||||||
|
* as indicated by the @author tags. See the copyright.txt file in the
|
||||||
|
* distribution for a full listing of individual contributors.
|
||||||
|
*
|
||||||
|
* This is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU Lesser General Public License as
|
||||||
|
* published by the Free Software Foundation; either version 2.1 of
|
||||||
|
* the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This software is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public
|
||||||
|
* License along with this software; if not, write to the Free
|
||||||
|
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||||
|
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
|
||||||
|
*/
|
||||||
|
package org.hibernate.test.cache.infinispan.tm;
|
||||||
|
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
import javax.transaction.Transaction;
|
||||||
|
import javax.transaction.TransactionManager;
|
||||||
|
|
||||||
|
import org.hibernate.HibernateException;
|
||||||
|
import org.hibernate.transaction.TransactionManagerLookup;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* XaResourceCapableTransactionManagerLookup.
|
||||||
|
*
|
||||||
|
* @author Galder Zamarreño
|
||||||
|
* @since 3.5
|
||||||
|
*/
|
||||||
|
public class XaTransactionManagerLookup implements TransactionManagerLookup {
|
||||||
|
|
||||||
|
public Object getTransactionIdentifier(Transaction transaction) {
|
||||||
|
return transaction;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TransactionManager getTransactionManager(Properties props) throws HibernateException {
|
||||||
|
return XaTransactionManagerImpl.getInstance();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUserTransactionName() {
|
||||||
|
throw new UnsupportedOperationException( "jndi currently not implemented for these tests" );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
61
cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/util/BatchModeTransactionManagerLookup.java
vendored
Executable file
61
cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/util/BatchModeTransactionManagerLookup.java
vendored
Executable file
|
@ -0,0 +1,61 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2007, Red Hat, Inc. and/or it's affiliates or third-party contributors as
|
||||||
|
* indicated by the @author tags or express copyright attribution
|
||||||
|
* statements applied by the authors. All third-party contributions are
|
||||||
|
* distributed under license by Red Hat, Inc. and/or it's affiliates.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||||
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
* Lesser General Public License, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this distribution; if not, write to:
|
||||||
|
* Free Software Foundation, Inc.
|
||||||
|
* 51 Franklin Street, Fifth Floor
|
||||||
|
* Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
package org.hibernate.test.cache.infinispan.util;
|
||||||
|
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
import javax.transaction.TransactionManager;
|
||||||
|
import javax.transaction.Transaction;
|
||||||
|
|
||||||
|
import org.hibernate.HibernateException;
|
||||||
|
import org.hibernate.transaction.TransactionManagerLookup;
|
||||||
|
import org.infinispan.transaction.tm.BatchModeTransactionManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Uses the JBoss Cache BatchModeTransactionManager. Should not be used in
|
||||||
|
* any tests that simulate usage of database connections.
|
||||||
|
*
|
||||||
|
* @author Brian Stansberry
|
||||||
|
*/
|
||||||
|
public class BatchModeTransactionManagerLookup
|
||||||
|
implements TransactionManagerLookup {
|
||||||
|
|
||||||
|
public TransactionManager getTransactionManager(Properties props) throws HibernateException {
|
||||||
|
try {
|
||||||
|
return BatchModeTransactionManager.getInstance();
|
||||||
|
}
|
||||||
|
catch (Exception e) {
|
||||||
|
throw new HibernateException("Failed getting BatchModeTransactionManager", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUserTransactionName() {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Object getTransactionIdentifier(Transaction transaction) {
|
||||||
|
return transaction;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
151
cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/util/CacheTestSupport.java
vendored
Normal file
151
cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/util/CacheTestSupport.java
vendored
Normal file
|
@ -0,0 +1,151 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2007, Red Hat, Inc. and/or it's affiliates or third-party contributors as
|
||||||
|
* indicated by the @author tags or express copyright attribution
|
||||||
|
* statements applied by the authors. All third-party contributions are
|
||||||
|
* distributed under license by Red Hat, Inc. and/or it's affiliates.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||||
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
* Lesser General Public License, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this distribution; if not, write to:
|
||||||
|
* Free Software Foundation, Inc.
|
||||||
|
* 51 Franklin Street, Fifth Floor
|
||||||
|
* Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
package org.hibernate.test.cache.infinispan.util;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
|
||||||
|
import org.hibernate.cache.RegionFactory;
|
||||||
|
import org.infinispan.Cache;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Support class for tracking and cleaning up objects used in tests.
|
||||||
|
*
|
||||||
|
* @author <a href="brian.stansberry@jboss.com">Brian Stansberry</a>
|
||||||
|
*/
|
||||||
|
public class CacheTestSupport {
|
||||||
|
|
||||||
|
private static final String PREFER_IPV4STACK = "java.net.preferIPv4Stack";
|
||||||
|
|
||||||
|
private Logger log;
|
||||||
|
|
||||||
|
private Set<Cache> caches = new HashSet();
|
||||||
|
private Set<RegionFactory> factories = new HashSet();
|
||||||
|
private Exception exception;
|
||||||
|
private String preferIPv4Stack;
|
||||||
|
|
||||||
|
public CacheTestSupport(Logger log) {
|
||||||
|
this.log = log;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void registerCache(Cache cache) {
|
||||||
|
caches.add(cache);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void registerFactory(RegionFactory factory) {
|
||||||
|
factories.add(factory);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void unregisterCache(Cache cache) {
|
||||||
|
caches.remove(cache);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void unregisterFactory(RegionFactory factory) {
|
||||||
|
factories.remove(factory);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUp() throws Exception {
|
||||||
|
|
||||||
|
// Try to ensure we use IPv4; otherwise cluster formation is very slow
|
||||||
|
preferIPv4Stack = System.getProperty(PREFER_IPV4STACK);
|
||||||
|
System.setProperty(PREFER_IPV4STACK, "true");
|
||||||
|
|
||||||
|
cleanUp();
|
||||||
|
throwStoredException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void tearDown() throws Exception {
|
||||||
|
|
||||||
|
if (preferIPv4Stack == null)
|
||||||
|
System.clearProperty(PREFER_IPV4STACK);
|
||||||
|
else
|
||||||
|
System.setProperty(PREFER_IPV4STACK, preferIPv4Stack);
|
||||||
|
|
||||||
|
cleanUp();
|
||||||
|
throwStoredException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void avoidConcurrentFlush() {
|
||||||
|
// JG 2.6.1 has a problem where calling flush more than once too quickly
|
||||||
|
// can result in several second delays
|
||||||
|
sleep(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sleep(long ms) {
|
||||||
|
try {
|
||||||
|
Thread.sleep(ms);
|
||||||
|
}
|
||||||
|
catch (InterruptedException e) {
|
||||||
|
log.warn("Interrupted during sleep", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void cleanUp() {
|
||||||
|
for (Iterator it = factories.iterator(); it.hasNext(); ) {
|
||||||
|
try {
|
||||||
|
((RegionFactory) it.next()).stop();
|
||||||
|
}
|
||||||
|
catch (Exception e) {
|
||||||
|
storeException(e);
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
it.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
factories.clear();
|
||||||
|
|
||||||
|
for (Iterator it = caches.iterator(); it.hasNext(); ) {
|
||||||
|
try {
|
||||||
|
Cache cache = (Cache) it.next();
|
||||||
|
cache.stop();
|
||||||
|
}
|
||||||
|
catch (Exception e) {
|
||||||
|
storeException(e);
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
it.remove();
|
||||||
|
}
|
||||||
|
avoidConcurrentFlush();
|
||||||
|
}
|
||||||
|
caches.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void storeException(Exception e) {
|
||||||
|
if (this.exception == null) {
|
||||||
|
this.exception = e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void throwStoredException() throws Exception {
|
||||||
|
if (exception != null) {
|
||||||
|
Exception toThrow = exception;
|
||||||
|
exception = null;
|
||||||
|
throw toThrow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
145
cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/util/CacheTestUtil.java
vendored
Normal file
145
cache-infinispan/src/test/java/org/hibernate/test/cache/infinispan/util/CacheTestUtil.java
vendored
Normal file
|
@ -0,0 +1,145 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* Copyright (c) 2007, Red Hat, Inc. and/or it's affiliates or third-party contributors as
|
||||||
|
* indicated by the @author tags or express copyright attribution
|
||||||
|
* statements applied by the authors. All third-party contributions are
|
||||||
|
* distributed under license by Red Hat, Inc. and/or it's affiliates.
|
||||||
|
*
|
||||||
|
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||||
|
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
* Lesser General Public License, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
* for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Lesser General Public License
|
||||||
|
* along with this distribution; if not, write to:
|
||||||
|
* Free Software Foundation, Inc.
|
||||||
|
* 51 Franklin Street, Fifth Floor
|
||||||
|
* Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
package org.hibernate.test.cache.infinispan.util;
|
||||||
|
|
||||||
|
import java.util.Enumeration;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Properties;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import junit.framework.Test;
|
||||||
|
import junit.framework.TestCase;
|
||||||
|
import junit.framework.TestSuite;
|
||||||
|
|
||||||
|
import org.hibernate.cache.infinispan.InfinispanRegionFactory;
|
||||||
|
import org.hibernate.cfg.Configuration;
|
||||||
|
import org.hibernate.cfg.Environment;
|
||||||
|
import org.hibernate.cfg.Settings;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Utilities for cache testing.
|
||||||
|
*
|
||||||
|
* @author <a href="brian.stansberry@jboss.com">Brian Stansberry</a>
|
||||||
|
*/
|
||||||
|
public class CacheTestUtil {
|
||||||
|
|
||||||
|
public static Configuration buildConfiguration(String regionPrefix, Class regionFactory, boolean use2ndLevel, boolean useQueries) {
|
||||||
|
Configuration cfg = new Configuration();
|
||||||
|
cfg.setProperty(Environment.GENERATE_STATISTICS, "true");
|
||||||
|
cfg.setProperty(Environment.USE_STRUCTURED_CACHE, "true");
|
||||||
|
cfg.setProperty(Environment.TRANSACTION_MANAGER_STRATEGY, BatchModeTransactionManagerLookup.class.getName());
|
||||||
|
|
||||||
|
cfg.setProperty(Environment.CACHE_REGION_FACTORY, regionFactory.getName());
|
||||||
|
cfg.setProperty(Environment.CACHE_REGION_PREFIX, regionPrefix);
|
||||||
|
cfg.setProperty(Environment.USE_SECOND_LEVEL_CACHE, String.valueOf(use2ndLevel));
|
||||||
|
cfg.setProperty(Environment.USE_QUERY_CACHE, String.valueOf(useQueries));
|
||||||
|
|
||||||
|
return cfg;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Configuration buildLocalOnlyConfiguration(String regionPrefix, boolean use2ndLevel, boolean useQueries) {
|
||||||
|
Configuration cfg = buildConfiguration(regionPrefix, InfinispanRegionFactory.class, use2ndLevel, useQueries);
|
||||||
|
cfg.setProperty(InfinispanRegionFactory.INFINISPAN_CONFIG_RESOURCE_PROP,
|
||||||
|
InfinispanRegionFactory.DEF_INFINISPAN_CONFIG_RESOURCE);
|
||||||
|
return cfg;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Configuration buildCustomQueryCacheConfiguration(String regionPrefix, String queryCacheName) {
|
||||||
|
Configuration cfg = buildConfiguration(regionPrefix, InfinispanRegionFactory.class, true, true);
|
||||||
|
cfg.setProperty(InfinispanRegionFactory.QUERY_CACHE_RESOURCE_PROP, queryCacheName);
|
||||||
|
return cfg;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static InfinispanRegionFactory startRegionFactory(Configuration cfg) throws ClassNotFoundException,
|
||||||
|
InstantiationException, IllegalAccessException {
|
||||||
|
|
||||||
|
Settings settings = cfg.buildSettings();
|
||||||
|
Properties properties = cfg.getProperties();
|
||||||
|
|
||||||
|
String factoryType = cfg.getProperty(Environment.CACHE_REGION_FACTORY);
|
||||||
|
Class factoryClass = Thread.currentThread().getContextClassLoader().loadClass(factoryType);
|
||||||
|
InfinispanRegionFactory regionFactory = (InfinispanRegionFactory) factoryClass.newInstance();
|
||||||
|
|
||||||
|
regionFactory.start(settings, properties);
|
||||||
|
|
||||||
|
return regionFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static InfinispanRegionFactory startRegionFactory(Configuration cfg, CacheTestSupport testSupport)
|
||||||
|
throws ClassNotFoundException, InstantiationException, IllegalAccessException {
|
||||||
|
InfinispanRegionFactory factory = startRegionFactory(cfg);
|
||||||
|
testSupport.registerFactory(factory);
|
||||||
|
return factory;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void stopRegionFactory(InfinispanRegionFactory factory, CacheTestSupport testSupport) {
|
||||||
|
factory.stop();
|
||||||
|
testSupport.unregisterFactory(factory);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Supports easy creation of a TestSuite where a subclass' "FailureExpected" version of a base
|
||||||
|
* test is included in the suite, while the base test is excluded. E.g. test class FooTestCase
|
||||||
|
* includes method testBar(), while test class SubFooTestCase extends FooTestCase includes method
|
||||||
|
* testBarFailureExcluded(). Passing SubFooTestCase.class to this method will return a suite that
|
||||||
|
* does not include testBar().
|
||||||
|
*
|
||||||
|
* FIXME Move this to UnitTestCase
|
||||||
|
*/
|
||||||
|
public static TestSuite createFailureExpectedSuite(Class testClass) {
|
||||||
|
|
||||||
|
TestSuite allTests = new TestSuite(testClass);
|
||||||
|
Set failureExpected = new HashSet();
|
||||||
|
Enumeration tests = allTests.tests();
|
||||||
|
while (tests.hasMoreElements()) {
|
||||||
|
Test t = (Test) tests.nextElement();
|
||||||
|
if (t instanceof TestCase) {
|
||||||
|
String name = ((TestCase) t).getName();
|
||||||
|
if (name.endsWith("FailureExpected"))
|
||||||
|
failureExpected.add(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TestSuite result = new TestSuite();
|
||||||
|
tests = allTests.tests();
|
||||||
|
while (tests.hasMoreElements()) {
|
||||||
|
Test t = (Test) tests.nextElement();
|
||||||
|
if (t instanceof TestCase) {
|
||||||
|
String name = ((TestCase) t).getName();
|
||||||
|
if (!failureExpected.contains(name + "FailureExpected")) {
|
||||||
|
result.addTest(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prevent instantiation.
|
||||||
|
*/
|
||||||
|
private CacheTestUtil() {
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
################################################################################
|
||||||
|
# Hibernate, Relational Persistence for Idiomatic Java #
|
||||||
|
# #
|
||||||
|
# Copyright (c) 2007, Red Hat, Inc. and/or it's affiliates or third-party contributors as #
|
||||||
|
# indicated by the @author tags or express copyright attribution #
|
||||||
|
# statements applied by the authors. All third-party contributions are #
|
||||||
|
# distributed under license by Red Hat, Inc. and/or it's affiliates. #
|
||||||
|
# #
|
||||||
|
# This copyrighted material is made available to anyone wishing to use, modify,#
|
||||||
|
# copy, or redistribute it subject to the terms and conditions of the GNU #
|
||||||
|
# Lesser General Public License, as published by the Free Software Foundation. #
|
||||||
|
# #
|
||||||
|
# This program is distributed in the hope that it will be useful, #
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
# for more details. #
|
||||||
|
# #
|
||||||
|
# You should have received a copy of the GNU Lesser General Public License #
|
||||||
|
# along with this distribution; if not, write to: #
|
||||||
|
# Free Software Foundation, Inc. #
|
||||||
|
# 51 Franklin Street, Fifth Floor #
|
||||||
|
# Boston, MA 02110-1301 USA #
|
||||||
|
################################################################################
|
||||||
|
hibernate.dialect org.hibernate.dialect.HSQLDialect
|
||||||
|
hibernate.connection.driver_class org.hsqldb.jdbcDriver
|
||||||
|
hibernate.connection.url jdbc:hsqldb:mem:/test
|
||||||
|
hibernate.connection.username sa
|
||||||
|
hibernate.connection.password
|
||||||
|
|
||||||
|
hibernate.connection.pool_size 5
|
||||||
|
|
||||||
|
hibernate.format_sql true
|
||||||
|
|
||||||
|
hibernate.max_fetch_depth 5
|
||||||
|
|
||||||
|
hibernate.generate_statistics true
|
||||||
|
|
||||||
|
hibernate.cache.use_second_level_cache true
|
||||||
|
hibernate.cache.use_query_cache true
|
||||||
|
hibernate.cache.region.factory_class org.hibernate.cache.infinispan.InfinispanRegionFactory
|
|
@ -0,0 +1,37 @@
|
||||||
|
################################################################################
|
||||||
|
# Hibernate, Relational Persistence for Idiomatic Java #
|
||||||
|
# #
|
||||||
|
# Copyright (c) 2007, Red Hat, Inc. and/or it's affiliates or third-party contributors as #
|
||||||
|
# indicated by the @author tags or express copyright attribution #
|
||||||
|
# statements applied by the authors. All third-party contributions are #
|
||||||
|
# distributed under license by Red Hat, Inc. and/or it's affiliates. #
|
||||||
|
# #
|
||||||
|
# This copyrighted material is made available to anyone wishing to use, modify,#
|
||||||
|
# copy, or redistribute it subject to the terms and conditions of the GNU #
|
||||||
|
# Lesser General Public License, as published by the Free Software Foundation. #
|
||||||
|
# #
|
||||||
|
# This program is distributed in the hope that it will be useful, #
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
# for more details. #
|
||||||
|
# #
|
||||||
|
# You should have received a copy of the GNU Lesser General Public License #
|
||||||
|
# along with this distribution; if not, write to: #
|
||||||
|
# Free Software Foundation, Inc. #
|
||||||
|
# 51 Franklin Street, Fifth Floor #
|
||||||
|
# Boston, MA 02110-1301 USA #
|
||||||
|
################################################################################
|
||||||
|
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
|
||||||
|
log4j.appender.stdout.Target=System.out
|
||||||
|
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
|
||||||
|
log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p [%t] %c{1}:%L - %m%n
|
||||||
|
|
||||||
|
|
||||||
|
log4j.rootLogger=info, stdout
|
||||||
|
|
||||||
|
#log4j.logger.org.hibernate.test=info
|
||||||
|
log4j.logger.org.hibernate.test=trace
|
||||||
|
log4j.logger.org.hibernate.cache=trace
|
||||||
|
log4j.logger.org.hibernate.SQL=debug
|
||||||
|
#log4j.logger.org.jgroups=info
|
||||||
|
#log4j.logger.org.infinispan=trace
|
37
cache-infinispan/src/test/resources/org/hibernate/test/cache/infinispan/functional/Contact.hbm.xml
vendored
Executable file
37
cache-infinispan/src/test/resources/org/hibernate/test/cache/infinispan/functional/Contact.hbm.xml
vendored
Executable file
|
@ -0,0 +1,37 @@
|
||||||
|
<?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, Relational Persistence for Idiomatic Java ~ ~
|
||||||
|
Copyright (c) 2007, Red Hat, Inc. and/or it's affiliates or third-party
|
||||||
|
contributors as ~ indicated by the @author tags or express
|
||||||
|
copyright attribution ~ statements applied by the authors. All
|
||||||
|
third-party contributions are ~ distributed under license by Red
|
||||||
|
Hat Middleware LLC. ~ ~ This copyrighted material is made
|
||||||
|
available to anyone wishing to use, modify, ~ copy, or
|
||||||
|
redistribute it subject to the terms and conditions of the GNU ~
|
||||||
|
Lesser General Public License, as published by the Free Software
|
||||||
|
Foundation. ~ ~ This program is distributed in the hope that it
|
||||||
|
will be useful, ~ but WITHOUT ANY WARRANTY; without even the
|
||||||
|
implied warranty of MERCHANTABILITY ~ or FITNESS FOR A PARTICULAR
|
||||||
|
PURPOSE. See the GNU Lesser General Public License ~ for more
|
||||||
|
details. ~ ~ You should have received a copy of the GNU Lesser
|
||||||
|
General Public License ~ along with this distribution; if not,
|
||||||
|
write to: ~ Free Software Foundation, Inc. ~ 51 Franklin Street,
|
||||||
|
Fifth Floor ~ Boston, MA 02110-1301 USA
|
||||||
|
-->
|
||||||
|
<hibernate-mapping
|
||||||
|
package="org.hibernate.test.cache.infinispan.functional">
|
||||||
|
|
||||||
|
<class name="Contact" table="Contacts">
|
||||||
|
<id name="id">
|
||||||
|
<generator class="increment" />
|
||||||
|
</id>
|
||||||
|
<property name="name" not-null="true" />
|
||||||
|
<property name="tlf" not-null="true" />
|
||||||
|
<many-to-one name="customer" column="cust_id" class="Customer" />
|
||||||
|
</class>
|
||||||
|
|
||||||
|
</hibernate-mapping>
|
|
@ -0,0 +1,40 @@
|
||||||
|
<?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, Relational Persistence for Idiomatic Java ~ ~
|
||||||
|
Copyright (c) 2007, Red Hat, Inc. and/or it's affiliates or third-party
|
||||||
|
contributors as ~ indicated by the @author tags or express
|
||||||
|
copyright attribution ~ statements applied by the authors. All
|
||||||
|
third-party contributions are ~ distributed under license by Red
|
||||||
|
Hat Middleware LLC. ~ ~ This copyrighted material is made
|
||||||
|
available to anyone wishing to use, modify, ~ copy, or
|
||||||
|
redistribute it subject to the terms and conditions of the GNU ~
|
||||||
|
Lesser General Public License, as published by the Free Software
|
||||||
|
Foundation. ~ ~ This program is distributed in the hope that it
|
||||||
|
will be useful, ~ but WITHOUT ANY WARRANTY; without even the
|
||||||
|
implied warranty of MERCHANTABILITY ~ or FITNESS FOR A PARTICULAR
|
||||||
|
PURPOSE. See the GNU Lesser General Public License ~ for more
|
||||||
|
details. ~ ~ You should have received a copy of the GNU Lesser
|
||||||
|
General Public License ~ along with this distribution; if not,
|
||||||
|
write to: ~ Free Software Foundation, Inc. ~ 51 Franklin Street,
|
||||||
|
Fifth Floor ~ Boston, MA 02110-1301 USA
|
||||||
|
-->
|
||||||
|
<hibernate-mapping
|
||||||
|
package="org.hibernate.test.cache.infinispan.functional">
|
||||||
|
|
||||||
|
<class name="Customer" table="Customers">
|
||||||
|
<id name="id">
|
||||||
|
<generator class="increment" />
|
||||||
|
</id>
|
||||||
|
<property name="name" not-null="true" />
|
||||||
|
<set name="contacts" inverse="true" cascade="save-update">
|
||||||
|
<key column="cust_id" />
|
||||||
|
<one-to-many class="Contact" />
|
||||||
|
</set>
|
||||||
|
|
||||||
|
</class>
|
||||||
|
|
||||||
|
</hibernate-mapping>
|
49
cache-infinispan/src/test/resources/org/hibernate/test/cache/infinispan/functional/Item.hbm.xml
vendored
Executable file
49
cache-infinispan/src/test/resources/org/hibernate/test/cache/infinispan/functional/Item.hbm.xml
vendored
Executable file
|
@ -0,0 +1,49 @@
|
||||||
|
<?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, Relational Persistence for Idiomatic Java ~ ~
|
||||||
|
Copyright (c) 2007, Red Hat, Inc. and/or it's affiliates or third-party
|
||||||
|
contributors as ~ indicated by the @author tags or express
|
||||||
|
copyright attribution ~ statements applied by the authors. All
|
||||||
|
third-party contributions are ~ distributed under license by Red
|
||||||
|
Hat Middleware LLC. ~ ~ This copyrighted material is made
|
||||||
|
available to anyone wishing to use, modify, ~ copy, or
|
||||||
|
redistribute it subject to the terms and conditions of the GNU ~
|
||||||
|
Lesser General Public License, as published by the Free Software
|
||||||
|
Foundation. ~ ~ This program is distributed in the hope that it
|
||||||
|
will be useful, ~ but WITHOUT ANY WARRANTY; without even the
|
||||||
|
implied warranty of MERCHANTABILITY ~ or FITNESS FOR A PARTICULAR
|
||||||
|
PURPOSE. See the GNU Lesser General Public License ~ for more
|
||||||
|
details. ~ ~ You should have received a copy of the GNU Lesser
|
||||||
|
General Public License ~ along with this distribution; if not,
|
||||||
|
write to: ~ Free Software Foundation, Inc. ~ 51 Franklin Street,
|
||||||
|
Fifth Floor ~ Boston, MA 02110-1301 USA
|
||||||
|
-->
|
||||||
|
<hibernate-mapping package="org.hibernate.test.cache.infinispan.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" />
|
||||||
|
<many-to-one name="owner" column="owner_id" class="Item" />
|
||||||
|
<set name="items" inverse="true">
|
||||||
|
<key column="owner_id" />
|
||||||
|
<one-to-many class="Item" />
|
||||||
|
</set>
|
||||||
|
</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>
|
46
cache-infinispan/src/test/resources/org/hibernate/test/cache/infinispan/functional/classloader/Account.hbm.xml
vendored
Executable file
46
cache-infinispan/src/test/resources/org/hibernate/test/cache/infinispan/functional/classloader/Account.hbm.xml
vendored
Executable file
|
@ -0,0 +1,46 @@
|
||||||
|
<?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, Relational Persistence for Idiomatic Java
|
||||||
|
~
|
||||||
|
~ Copyright (c) 2008, Red Hat, Inc. and/or it's affiliates or third-party contributors as
|
||||||
|
~ indicated by the @author tags or express copyright attribution
|
||||||
|
~ statements applied by the authors. All third-party contributions are
|
||||||
|
~ distributed under license by Red Hat, Inc. and/or it's affiliates.
|
||||||
|
~
|
||||||
|
~ This copyrighted material is made available to anyone wishing to use, modify,
|
||||||
|
~ copy, or redistribute it subject to the terms and conditions of the GNU
|
||||||
|
~ Lesser General Public License, as published by the Free Software Foundation.
|
||||||
|
~
|
||||||
|
~ This program is distributed in the hope that it will be useful,
|
||||||
|
~ but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
~ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||||
|
~ for more details.
|
||||||
|
~
|
||||||
|
~ You should have received a copy of the GNU Lesser General Public License
|
||||||
|
~ along with this distribution; if not, write to:
|
||||||
|
~ Free Software Foundation, Inc.
|
||||||
|
~ 51 Franklin Street, Fifth Floor
|
||||||
|
~ Boston, MA 02110-1301 USA
|
||||||
|
-->
|
||||||
|
<hibernate-mapping
|
||||||
|
package="org.hibernate.test.cache.infinispan.functional.classloader">
|
||||||
|
|
||||||
|
<class name="Account" table="Accounts">
|
||||||
|
|
||||||
|
<cache usage="transactional"/>
|
||||||
|
|
||||||
|
<id name="id">
|
||||||
|
<generator class="assigned"/>
|
||||||
|
</id>
|
||||||
|
|
||||||
|
<property name="branch" not-null="true"/>
|
||||||
|
<property name="balance" not-null="true"/>
|
||||||
|
<property name="accountHolder" type="serializable" not-null="true"/>
|
||||||
|
|
||||||
|
</class>
|
||||||
|
|
||||||
|
</hibernate-mapping>
|
Loading…
Reference in New Issue