package org.qi4j.cache.ehcache;
import java.util.concurrent.ConcurrentHashMap;
import net.sf.ehcache.CacheManager;
import net.sf.ehcache.config.CacheConfiguration;
import org.qi4j.api.common.Optional;
import org.qi4j.api.configuration.Configuration;
import org.qi4j.api.injection.scope.This;
import org.qi4j.api.service.Activatable;
import org.qi4j.api.util.NullArgumentException;
import org.qi4j.spi.cache.Cache;
import org.qi4j.spi.cache.CachePool;
public class EhCachePoolMixin
implements CachePool, Activatable
{
private ConcurrentHashMap<String, EhCacheImpl> caches;
@Optional
@This
private Configuration<EhCacheConfiguration> config;
private CacheManager cacheManager;
public EhCachePoolMixin()
{
caches = new ConcurrentHashMap<String, EhCacheImpl>();
}
public <T> Cache<T> fetchCache( String cacheId, Class<T> valueType )
{
// Note: Small bug in Ehcache; If the cache name is an empty String it will actually work until
// you try to remove the Cache instance from the CacheManager, at which point it is silently
// ignored but not removed so there is an follow up problem of too much in the CacheManager.
NullArgumentException.validateNotEmpty( "cacheId", cacheId );
EhCacheImpl<T> cache = caches.get( cacheId );
if( cache == null )
{
cache = createNewCache( cacheId, valueType );
caches.put( cacheId, cache );
}
cache.incRefCount();
return cache;
}
private <T> EhCacheImpl<T> createNewCache( String cacheId, Class<T> valueType )
{
net.sf.ehcache.Cache cache = cacheManager.getCache( cacheId );
if( cache == null )
{
CacheConfiguration cc = createCacheConfiguration( cacheId );
// TODO: We also need all the other Configurations that are possible, like cacheLoaderFactoryConfiguration
cache = new net.sf.ehcache.Cache( cc );
cacheManager.addCache( cache );
}
return new EhCacheImpl<T>( cacheId, cache, valueType );
}
public void returnCache( Cache cache )
{
EhCacheImpl eh = (EhCacheImpl) cache;
eh.decRefCount();
if( eh.isNotUsed() )
{
caches.remove( eh.cacheId() );
cacheManager.removeCache( eh.cacheId() );
}
}
public void activate()
throws Exception
{
net.sf.ehcache.config.Configuration configuration = new net.sf.ehcache.config.Configuration();
EhCacheConfiguration conf = config.configuration();
Boolean updateCheck = conf.updateCheck().get();
configuration.setUpdateCheck( updateCheck );
configuration.setDynamicConfig( true );
String monitoring = conf.monitoring().get().trim();
if( monitoring.length() > 0 )
{
configuration.setMonitoring( monitoring );
}
String name = conf.cacheManagerName().get();
if( name == null )
{
name = "Qi4j Cache Extension";
}
configuration.setName( name );
CacheConfiguration cc = createCacheConfiguration( "qi4j.ehcache.config.default" );
configuration.setDefaultCacheConfiguration( cc );
cacheManager = new CacheManager( configuration );
}
public void passivate()
throws Exception
{
cacheManager.shutdown();
}
private CacheConfiguration createCacheConfiguration( String cacheId )
{
EhCacheConfiguration conf = config.configuration();
Integer maxElementsInMemory = conf.maxElementsInMemory().get();
if( maxElementsInMemory <= 0 )
{
maxElementsInMemory = 10000;
}
CacheConfiguration cc = new CacheConfiguration( cacheId, maxElementsInMemory );
String transactionalMode = conf.transactionalMode().get();
if( transactionalMode.length() > 0 )
{
cc.transactionalMode( transactionalMode );
}
Long timeToLiveSeconds = conf.timeToLiveSeconds().get();
if( timeToLiveSeconds > 0 )
{
cc.timeToLiveSeconds( timeToLiveSeconds );
}
Long timeToIdleSeconds = conf.timeToIdleSeconds().get();
if( timeToIdleSeconds > 0 )
{
cc.timeToIdleSeconds( timeToIdleSeconds );
}
Boolean overflowToDisk = conf.overflowToDisk().get();
cc.overflowToDisk( overflowToDisk );
String name = conf.name().get();
if( name.length() > 0 )
{
cc.name( name );
}
String memoryStoreEvictionPolicy = conf.memoryStoreEvictionPolicy().get();
if( memoryStoreEvictionPolicy.length() > 0 )
{
cc.memoryStoreEvictionPolicy( memoryStoreEvictionPolicy );
}
Integer maxElementsOnDisk = conf.maxElementsOnDisk().get();
if( maxElementsOnDisk > 0 )
{
cc.maxElementsOnDisk( maxElementsOnDisk );
}
// Boolean loggingEnabled = conf.loggingEnabled().get();
// if( loggingEnabled != null )
// {
// cc.loggingEnabled( loggingEnabled );
// }
Boolean eternal = conf.eternal().get();
cc.eternal( eternal );
String diskStorePath = conf.diskStorePath().get();
if( diskStorePath.length() > 0 )
{
cc.diskStorePath( diskStorePath );
}
Integer diskSpoolBufferSizeMB = conf.diskSpoolBufferSizeMB().get();
if( diskSpoolBufferSizeMB > 0 )
{
cc.diskSpoolBufferSizeMB( diskSpoolBufferSizeMB );
}
Boolean diskPersistent = conf.diskPersistent().get();
cc.diskPersistent( diskPersistent );
Long diskExpiryThreadIntervalSeconds = conf.diskExpiryThreadIntervalSeconds().get();
if( diskExpiryThreadIntervalSeconds > 0 )
{
cc.diskExpiryThreadIntervalSeconds( diskExpiryThreadIntervalSeconds );
}
Integer diskAccessStripes = conf.diskAccessStripes().get();
if( diskAccessStripes > 0 )
{
cc.diskAccessStripes( diskAccessStripes );
}
Boolean clearOnFlush = conf.clearOnFlush().get();
cc.clearOnFlush( clearOnFlush );
return cc;
}
}