/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.cache.jcache;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Properties;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.cache.Cache;
import javax.cache.CacheManager;
import javax.cache.Caching;
import javax.cache.configuration.Configuration;
import javax.cache.configuration.MutableConfiguration;
import javax.cache.spi.CachingProvider;
import org.hibernate.boot.spi.SessionFactoryOptions;
import org.hibernate.cache.CacheException;
import org.hibernate.cache.jcache.time.Timestamper;
import org.hibernate.cache.spi.CacheDataDescription;
import org.hibernate.cache.spi.CollectionRegion;
import org.hibernate.cache.spi.EntityRegion;
import org.hibernate.cache.spi.NaturalIdRegion;
import org.hibernate.cache.spi.QueryResultsRegion;
import org.hibernate.cache.spi.RegionFactory;
import org.hibernate.cache.spi.TimestampsRegion;
import org.hibernate.cache.spi.access.AccessType;
import org.jboss.logging.Logger;
/**
* @author Alex Snaps
*/
public class JCacheRegionFactory implements RegionFactory {
private static final String PROP_PREFIX = "hibernate.javax.cache";
public static final String PROVIDER = PROP_PREFIX + ".provider";
public static final String CONFIG_URI = PROP_PREFIX + ".uri";
private static final JCacheMessageLogger LOG = Logger.getMessageLogger(
JCacheMessageLogger.class,
JCacheRegionFactory.class.getName()
);
static long nextTS() {
return Timestamper.next();
}
static int timeOut() {
return (int) TimeUnit.SECONDS.toMillis( 60 ) * Timestamper.ONE_MS;
}
private final AtomicBoolean started = new AtomicBoolean( false );
private volatile CacheManager cacheManager;
private SessionFactoryOptions options;
@Override
public void start(final SessionFactoryOptions options, final Properties properties) throws CacheException {
if ( started.compareAndSet( false, true ) ) {
synchronized ( this ) {
this.options = options;
try {
this.cacheManager = getCacheManager( properties );
}
finally {
if ( this.cacheManager == null ) {
started.set( false );
}
}
}
}
else {
LOG.attemptToRestartAlreadyStartedJCacheProvider();
}
}
@Override
public void stop() {
if ( started.compareAndSet( true, false ) ) {
synchronized ( this ) {
cacheManager.close();
cacheManager = null;
}
}
else {
LOG.attemptToRestopAlreadyStoppedJCacheProvider();
}
}
@Override
public boolean isMinimalPutsEnabledByDefault() {
return true;
}
@Override
public AccessType getDefaultAccessType() {
return AccessType.READ_WRITE;
}
@Override
public long nextTimestamp() {
return nextTS();
}
@Override
public EntityRegion buildEntityRegion(final String regionName, final Properties properties, final CacheDataDescription metadata)
throws CacheException {
final Cache<Object, Object> cache = getOrCreateCache( regionName, properties, metadata );
return new JCacheEntityRegion( cache, metadata, options );
}
@Override
public NaturalIdRegion buildNaturalIdRegion(final String regionName, final Properties properties, final CacheDataDescription metadata)
throws CacheException {
final Cache<Object, Object> cache = getOrCreateCache( regionName, properties, metadata );
return new JCacheNaturalIdRegion( cache, metadata, options );
}
@Override
public CollectionRegion buildCollectionRegion(final String regionName, final Properties properties, final CacheDataDescription metadata)
throws CacheException {
final Cache<Object, Object> cache = getOrCreateCache( regionName, properties, metadata );
return new JCacheCollectionRegion( cache, metadata, options );
}
@Override
public QueryResultsRegion buildQueryResultsRegion(final String regionName, final Properties properties)
throws CacheException {
final Cache<Object, Object> cache = getOrCreateCache( regionName, properties, null );
return new JCacheQueryResultsRegion( cache );
}
@Override
public TimestampsRegion buildTimestampsRegion(final String regionName, final Properties properties)
throws CacheException {
final Cache<Object, Object> cache = getOrCreateCache( regionName, properties, null );
return new JCacheTimestampsRegion( cache );
}
boolean isStarted() {
return started.get() && cacheManager != null;
}
protected SessionFactoryOptions getOptions() {
return options;
}
protected CachingProvider getCachingProvider(final Properties properties){
final CachingProvider cachingProvider;
final String provider = getProp( properties, PROVIDER );
if ( provider != null ) {
cachingProvider = Caching.getCachingProvider( provider );
}
else {
cachingProvider = Caching.getCachingProvider();
}
return cachingProvider;
}
protected CacheManager getCacheManager(final Properties properties){
final CachingProvider cachingProvider = getCachingProvider( properties );
final CacheManager cacheManager;
final String cacheManagerUri = getProp( properties, CONFIG_URI );
if ( cacheManagerUri != null ) {
URI uri;
try {
uri = new URI( cacheManagerUri );
}
catch ( URISyntaxException e ) {
throw new CacheException( "Couldn't create URI from " + cacheManagerUri, e );
}
cacheManager = cachingProvider.getCacheManager( uri, cachingProvider.getDefaultClassLoader() );
}
else {
cacheManager = cachingProvider.getCacheManager();
}
return cacheManager;
}
protected Cache<Object, Object> getOrCreateCache(String regionName, Properties properties, CacheDataDescription metadata) {
checkStatus();
final Cache<Object, Object> cache = cacheManager.getCache( regionName );
if ( cache == null ) {
try {
return createCache( regionName, properties, metadata );
}
catch ( CacheException e ) {
final Cache<Object, Object> existing = cacheManager.getCache( regionName );
if ( existing != null ) {
return existing;
}
throw e;
}
}
return cache;
}
protected Cache<Object, Object> createCache(String regionName, Properties properties, CacheDataDescription metadata) {
return cacheManager.createCache( regionName, newDefaultConfig( properties, metadata ) );
}
protected Configuration<Object, Object> newDefaultConfig(Properties properties, CacheDataDescription metadata) {
return new MutableConfiguration<Object, Object>();
}
protected CacheManager getCacheManager() {
return cacheManager;
}
protected String getProp(Properties properties, String prop) {
return properties != null ? properties.getProperty( prop ) : null;
}
protected void checkStatus() {
if(!isStarted()) {
throw new IllegalStateException("JCacheRegionFactory not yet started!");
}
}
}