[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:
Galder Zamarreno 2009-08-21 08:39:33 +00:00
parent ce8df153eb
commit 9ccd912bde
78 changed files with 10640 additions and 0 deletions

160
cache-infinispan/pom.xml Normal file
View File

@ -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>

View 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;
}
}

View 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);
}
}

View 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();
}
}

View File

@ -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() + "]");
}
}

View 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");
}
}

View File

@ -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 {
}
}

View 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() + "]");
}
}

View 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");
}
}

View 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;
}
}

View 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);
}
}

View 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);
// }
// }
// }
}

View File

@ -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;
}
}

View 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);
}
}

View File

@ -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");
}
}
}

View 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);
}
}

View File

@ -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);
}
}

View 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);
// }
}

View File

@ -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>

View File

@ -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());
}
}

View File

@ -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);
}
}
}

View File

@ -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();
}
}

View File

@ -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);
}
}

View File

@ -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();
}
}
}

View File

@ -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();
}
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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");
}
}

View File

@ -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) {}
}
}

View File

@ -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());
}
}

View File

@ -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 {
}
}

View File

@ -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();
}
}
}

View File

@ -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) {}
}
}

View File

@ -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));
}
}

View File

@ -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");
}
}

View File

@ -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");
}
}

View File

@ -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) {}
}
}

View 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());
}
}

View File

@ -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 {
}
}

View File

@ -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());
}
}

View File

@ -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");
}
}

View File

@ -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();
}
}

View 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;
}
}

View 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;
}
}

View 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 );
}
}

View 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;
}
}

View File

@ -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");
}
}
}

View File

@ -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)));
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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);
}
}
}

View File

@ -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();
}
}
}

View File

@ -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");
}
}

View File

@ -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;
}
}

View File

@ -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();
}
}

View File

@ -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();
}
}
}

View File

@ -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();
}
}

View File

@ -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;
}
}

View File

@ -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 +
'}';
}
}
}

View File

@ -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();
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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));
}
}

View File

@ -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;
}
}

View 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.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");
}
}

View 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;
}
}

View 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 +
'}';
}
}
}

View 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;
}
}
}

View File

@ -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" );
}
}

View 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;
}
}

View 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;
}
}
}

View 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() {
}
}

View File

@ -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

View File

@ -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

View 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>

View File

@ -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>

View 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>

View 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>