/* vim: set ts=2 et sw=2 cindent fo=qroca: */
package com.globant.katari.ehcache.hibernate;
import java.util.List;
import java.util.Properties;
import net.sf.ehcache.Cache;
import net.sf.ehcache.CacheManager;
import net.sf.ehcache.Ehcache;
import net.sf.ehcache.config.CacheConfiguration;
import net.sf.ehcache.hibernate.management.impl
.ProviderMBeanRegistrationHelper;
import net.sf.ehcache.hibernate.nonstop.NonstopAccessStrategyFactory;
import net.sf.ehcache.hibernate.regions.EhcacheCollectionRegion;
import net.sf.ehcache.hibernate.regions.EhcacheEntityRegion;
import net.sf.ehcache.hibernate.regions.EhcacheQueryResultsRegion;
import net.sf.ehcache.hibernate.regions.EhcacheTimestampsRegion;
import net.sf.ehcache.hibernate.strategy.EhcacheAccessStrategyFactory;
import net.sf.ehcache.hibernate.strategy.EhcacheAccessStrategyFactoryImpl;
import net.sf.ehcache.util.Timestamper;
import org.apache.commons.lang.Validate;
import org.hibernate.cache.CacheDataDescription;
import org.hibernate.cache.CacheException;
import org.hibernate.cache.CollectionRegion;
import org.hibernate.cache.EntityRegion;
import org.hibernate.cache.QueryResultsRegion;
import org.hibernate.cache.RegionFactory;
import org.hibernate.cache.TimestampsRegion;
import org.hibernate.cache.access.AccessType;
import org.hibernate.cfg.Settings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/** Region factory implementation.
*
* This adapts hibernate cache regions to ehcache caches.
*
* @author waabox (emiliano[dot]arango[at]globant[dot]com)
*/
public class EhCacheRegionFactory implements RegionFactory {
/** The class logger.*/
private Logger log = LoggerFactory.getLogger(EhCacheRegionFactory.class);
/** Ehcache CacheManager that supplied Ehcache instances for this Hibernate
* RegionFactory.
*
* This is never null.
*/
private volatile CacheManager manager;
/** The cacheConfigurations, never null.*/
private final List<CacheConfiguration> cacheConfigurations;
/** Mbean for hibernate management, never null.*/
private final ProviderMBeanRegistrationHelper mBean;
/** Factory for creating various access strategies, never null.*/
private final EhcacheAccessStrategyFactory accessStrategyFactory;
/** Settings object for the Hibernate persistence unit.
*
* Ignored if null.
*/
private Settings hibernateSettings;
/** True if the cache will record hit, miss and evict statistics. */
private boolean statistics;
/** Flag that checks if the region has been bootstraped or not.*/
private boolean bootstraped = false;
/** Creates a new instance of the KatariSingletonEhCacheRegionFactory.
*
* @param cacheManager the cache manager attached to this factory. It cannot
* be null.
*
* @param cacheConfiguration the cache configuration for each region. It
* cannot be null.
*
* @param recordStatistics true if the cache will record hit, miss and evict
* statistics.
*/
public EhCacheRegionFactory(final CacheManager cacheManager,
final List<CacheConfiguration> cacheConfiguration,
final boolean recordStatistics) {
Validate.notNull(cacheManager, "The cache manager cannot be null");
Validate.notNull(cacheConfiguration,
"The cache configuration cannot be null");
manager = cacheManager;
cacheConfigurations = cacheConfiguration;
mBean = new ProviderMBeanRegistrationHelper();
accessStrategyFactory = new NonstopAccessStrategyFactory(
new EhcacheAccessStrategyFactoryImpl());
statistics = recordStatistics;
}
/** {@inheritDoc} . */
public synchronized void start(final Settings settings,
final Properties properties) {
log.trace("Entering start");
if (!bootstraped) {
log.debug("Starting the katari cache manager");
if (settings == null) {
hibernateSettings = settings;
}
for (CacheConfiguration config : cacheConfigurations) {
log.debug("adding the cache: " + config.getName());
config.setStatistics(statistics);
manager.addCache(new Cache(config));
}
mBean.registerMBean(manager, properties);
bootstraped = true;
}
log.trace("Leaving start");
}
/** {@inheritDoc} . */
public synchronized void stop() {
try {
if (manager != null) {
mBean.unregisterMBean();
manager.shutdown();
manager = null;
}
} catch (net.sf.ehcache.CacheException e) {
throw new CacheException(e);
}
}
/** {@inheritDoc} . */
public boolean isMinimalPutsEnabledByDefault() {
return true;
}
/** {@inheritDoc} . */
public AccessType getDefaultAccessType() {
return AccessType.READ_WRITE;
}
/** {@inheritDoc} . */
public long nextTimestamp() {
return Timestamper.next();
}
/** Retrieves the cache instance given by the supplied name, if the
* given cache name it's not within the cache manager, adds a new cache
* with the given name.
*
* @param name the name of the cache to retrieve. It cannot be null.
*
* @return the cache instance. @throws CacheException
*/
protected Ehcache getCache(final String name) {
Validate.notNull(name, "The cache name cannot be null");
try {
Ehcache cache = manager.getEhcache(name);
if (cache == null) {
log.debug("Couldn't find a specific ehcache configuration "
+ "for cache named [" + name + "]; using defaults.");
manager.addCache(name);
cache = manager.getEhcache(name);
log.debug("started EHCache region: " + name);
}
return cache;
} catch (net.sf.ehcache.CacheException e) {
throw new CacheException(e);
}
}
/** {@inheritDoc} . */
public EntityRegion buildEntityRegion(final String regionName,
final Properties properties, final CacheDataDescription metadata) {
return new EhcacheEntityRegion(accessStrategyFactory, getCache(regionName),
hibernateSettings, metadata, properties);
}
/** {@inheritDoc} . */
public CollectionRegion buildCollectionRegion(final String regionName,
final Properties properties, final CacheDataDescription metadata) {
return new EhcacheCollectionRegion(accessStrategyFactory,
getCache(regionName), hibernateSettings, metadata, properties);
}
/** {@inheritDoc} . */
public QueryResultsRegion buildQueryResultsRegion(final String regionName,
final Properties properties) {
return new EhcacheQueryResultsRegion(accessStrategyFactory,
getCache(regionName), properties);
}
/** {@inheritDoc} . */
public TimestampsRegion buildTimestampsRegion(final String regionName,
final Properties properties) {
return new EhcacheTimestampsRegion(accessStrategyFactory,
getCache(regionName), properties);
}
}