/* * Copyright 2008-2014 the original author or authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.kaleidofoundry.core.cache; import static org.kaleidofoundry.core.cache.CacheConstants.EhCacheManagerPluginName; import static org.kaleidofoundry.core.cache.CacheManagerContextBuilder.FileStoreUri; import static org.kaleidofoundry.core.i18n.InternalBundleHelper.CacheMessageBundle; import java.io.FileNotFoundException; import java.io.InputStream; import java.io.Serializable; import java.util.LinkedHashMap; import java.util.Map; import net.sf.ehcache.CacheManager; import org.kaleidofoundry.core.context.RuntimeContext; import org.kaleidofoundry.core.lang.annotation.NotNull; import org.kaleidofoundry.core.plugin.Declare; import org.kaleidofoundry.core.util.StringHelper; /** * Terracotta ehcache manager provider <br/> * <br/> * http://ehcache.org/documentation/configuration.html <br/> * Cache statistics are disabled in this version for performance reason (prior to 1.7.x) <br/> * With EhCache 2.x you can disable statistics cache by configuration :) * * @see CacheManagerFactory * @author jraduget */ @Declare(value = EhCacheManagerPluginName) public class EhCacheManagerImpl extends AbstractCacheManager { /** Default cache configuration */ private static final String DefaultCacheConfiguration = "ehcache.xml"; // internal ehCache cache manager final net.sf.ehcache.CacheManager ehCacheManager; /** * @param context */ public EhCacheManagerImpl(final RuntimeContext<org.kaleidofoundry.core.cache.CacheManager> context) { this(context.getString(FileStoreUri), context); } /** * @param configuration url to the configuration file of the cache.<br/> * This file have to be in classpath or on external file system. If null is specified, default / fail-safe * cache configuration implementation will be loaded<br/> * override the context configuration file (if defined) * @param context */ public EhCacheManagerImpl(final String configuration, final RuntimeContext<org.kaleidofoundry.core.cache.CacheManager> context) { super(configuration, context); try { if (StringHelper.isEmpty(configuration)) { ehCacheManager = new CacheManager(); if (ehCacheManager == null) { throw newCacheException("cache.configuration.notfound", new String[] { EhCacheManagerPluginName, DefaultCacheConfiguration }); } } else { final InputStream inConf = getConfiguration(configuration); if (inConf != null) { ehCacheManager = new CacheManager(inConf); } else { ehCacheManager = new CacheManager(configuration); } if (ehCacheManager == null) { throw newCacheException("cache.configuration.notfound", new String[] { EhCacheManagerPluginName, configuration }); } } if (!StringHelper.isEmpty(context.getName()) && StringHelper.isEmpty(ehCacheManager.getName())) { ehCacheManager.setName(context.getName()); } } catch (final net.sf.ehcache.CacheException ehce) { throw newCacheConfigurationException("cache.configuration.error", ehce, EhCacheManagerPluginName, getCurrentConfiguration()); } } /** * @see AbstractCacheManager#AbstractCacheManager() */ EhCacheManagerImpl() { super(); ehCacheManager = null; } /* * (non-Javadoc) * @see org.kaleidofoundry.core.cache.CacheManager#getDefaultConfiguration() */ @Override public String getDefaultConfiguration() { return DefaultCacheConfiguration; } /* * (non-Javadoc) * @see org.kaleidofoundry.core.cache.AbstractCacheManager#getMetaInformations() */ @Override public String getMetaInformations() { return "ehcache-2.x (1.2.x -> 2.6.x)"; } /* * (non-Javadoc) * @see org.kaleidofoundry.core.cache.CacheFactory#getCache(java.lang.String, java.lang.String) */ @SuppressWarnings("unchecked") @Override public <K extends Serializable, V extends Serializable> Cache<K, V> getCache(final String name, @NotNull final RuntimeContext<Cache<K, V>> context) { Cache<K, V> cache = cachesByName.get(name); if (cache == null) { cache = new EhCacheImpl<K, V>(name, this, context); // registered it to cache manager cachesByName.put(name, cache); } return cache; } /* * (non-Javadoc) * @see org.kaleidofoundry.core.cache.CacheFactory#destroy(java.lang.String) */ @Override public synchronized void destroy(final String cacheName) { final Cache<?, ?> cache = cachesByName.get(cacheName); if (cache != null) { // custom ehcache destroy ((EhCacheImpl<?, ?>) cache).destroy(); cachesByName.remove(cacheName); } } /* * (non-Javadoc) * @see org.kaleidofoundry.core.cache.CacheFactory#destroyAll() */ @Override public synchronized void destroyAll() { super.destroyAll(); // destroy all cache instances for (final String name : cachesByName.keySet()) { LOGGER.info(CacheMessageBundle.getMessage("cachemanager.destroy.info", name)); destroy(name); } // ehcache cacheManager shutdown if (ehCacheManager != null) { ehCacheManager.shutdown(); } } /** * @param code * @param args * @return cache provider exception converter */ static CacheConfigurationException newCacheException(final String code, final String... args) { return newCacheConfigurationException(code, null, args); } /** * @param code * @param th * @param args * @return cache provider exception converter */ static CacheConfigurationException newCacheConfigurationException(final String code, final Throwable th, final String... args) { if (th == null) { return new CacheConfigurationException(code, args); } else { final Throwable cause = th.getCause(); if (cause != null && cause instanceof FileNotFoundException) { return new CacheConfigurationNotFoundException(code, th, args); } else { return new CacheConfigurationException(code, th, args); } } } /* * (non-Javadoc) * @see org.kaleidofoundry.core.cache.CacheFactory#clearStatistics(java.lang.String) */ @Override public void clearStatistics(final String cacheName) { final Cache<?, ?> cache = getCache(cacheName); if (cache != null) { final net.sf.ehcache.Cache ehcache = ((EhCacheImpl<?, ?>) cache).getCache(); ehcache.clearStatistics(); } } /* * (non-Javadoc) * @see org.kaleidofoundry.core.cache.CacheFactory#dumpStatistics(java.lang.String) */ @Override public Map<String, Object> dumpStatistics(final String cacheName) { final Cache<?, ?> cache = getCache(cacheName); if (cache != null) { final net.sf.ehcache.Cache ehcache = ((EhCacheImpl<?, ?>) cache).getCache(); final Map<String, Object> lcacheStats = new LinkedHashMap<String, Object>(); lcacheStats.put("CacheSize", ehcache.getSize()); lcacheStats.put("MemoryStoreSize", ehcache.getStatistics().getMemoryStoreObjectCount()); lcacheStats.put("DiskStoreSize", ehcache.getStatistics().getDiskStoreObjectCount()); lcacheStats.put("MemoryHits", ehcache.getStatistics().getInMemoryHits()); lcacheStats.put("DiskHits", ehcache.getStatistics().getOnDiskHits()); return lcacheStats; } else { return null; } } /* * (non-Javadoc) * @see org.kaleidofoundry.core.cache.CacheManager#getDelegate() */ @Override public Object getDelegate() { return ehCacheManager; } /** * @param name * @return cache provider */ protected net.sf.ehcache.Cache createCache(final String name) { LOGGER.info(CacheMessageBundle.getMessage("cachemanager.create.default", name, getName())); try { // the internal ehcache instance that will be created final net.sf.ehcache.Cache cache; cache = ehCacheManager.getCache(name); if (cache == null) { throw new CacheDefinitionNotFoundException("cache.configuration.notCachefound", name, getCurrentConfiguration()); } else { // for version <= 1.7.x : performance decrease a lot with statistics // for version >= 2.x, statistics can be change in xml configuration cache.setStatisticsEnabled(false); return cache; } } catch (final net.sf.ehcache.CacheException ehce) { throw newCacheConfigurationException("cache.configuration.error", ehce, EhCacheManagerPluginName, getCurrentConfiguration()); } } }