| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you 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.apache.ki.cache.ehcache; |
| |
| import java.io.IOException; |
| import java.io.InputStream; |
| |
| import org.apache.commons.logging.Log; |
| import org.apache.commons.logging.LogFactory; |
| |
| import org.apache.ki.cache.Cache; |
| import org.apache.ki.cache.CacheException; |
| import org.apache.ki.cache.CacheManager; |
| import org.apache.ki.io.ResourceUtils; |
| import org.apache.ki.session.mgt.eis.CachingSessionDAO; |
| import org.apache.ki.util.Destroyable; |
| import org.apache.ki.util.Initializable; |
| |
| /** |
| * Apache Ki <code>CacheManager</code> implementation utilizing the Ehcache framework for all cache functionality. |
| * <p/> |
| * This class can {@link #setCacheManager(net.sf.ehcache.CacheManager) accept} a manually configured |
| * {@link net.sf.ehcache.CacheManager net.sf.ehcache.CacheManager} instance, |
| * or an <code>ehcache.xml</code> path location can be specified instead and one will be constructed. If neither are |
| * specified, Apache Ki's failsafe <code><a href="./ehcache.xml">ehcache.xml</a></code> file will be used by default. |
| * |
| * <p>This implementation requires EhCache 1.2 and above. Make sure EhCache 1.1 or earlier |
| * is not in the classpath or it will not work.</p> |
| * |
| * <p>Please see the <a href="http://ehcache.sf.net" target="_top">Ehcache website</a> for their documentation.</p> |
| * |
| * @author Jeremy Haile |
| * @author Les Hazlewood |
| * @see <a href="http://ehcache.sf.net" target="_top">The Ehcache website</a> |
| * @since 0.2 |
| */ |
| public class EhCacheManager implements CacheManager, Initializable, Destroyable { |
| |
| /** |
| * The default name for the active sessions cache, equal to |
| * {@link org.apache.ki.session.mgt.eis.CachingSessionDAO#ACTIVE_SESSION_CACHE_NAME CachingSessionDAO.ACTIVE_SESSION_CACHE_NAME}. |
| */ |
| public static final String DEFAULT_ACTIVE_SESSIONS_CACHE_NAME = CachingSessionDAO.ACTIVE_SESSION_CACHE_NAME; |
| |
| /** |
| * The default maximum number of active sessions in cache <em>memory</em>, equal to <code>20,000</code>. |
| */ |
| public static final int DEFAULT_ACTIVE_SESSIONS_CACHE_MAX_ELEM_IN_MEM = 20000; |
| |
| /** |
| * The default time the active sessions disk expiration thread will run, equal to <code>600</code> (10 minutes). |
| */ |
| public static final int DEFAULT_ACTIVE_SESSIONS_DISK_EXPIRY_THREAD_INTERVAL_SECONDS = 600; |
| |
| /** |
| * This class's private log instance. |
| */ |
| private static final Log log = LogFactory.getLog(EhCacheManager.class); |
| |
| /** |
| * The EhCache cache manager used by this implementation to create caches. |
| */ |
| protected net.sf.ehcache.CacheManager manager; |
| |
| /** |
| * Indicates if the CacheManager instance was implicitly/automatically created by this instance, indicating that |
| * it should be automatically cleaned up as well on shutdown. |
| */ |
| private boolean cacheManagerImplicitlyCreated = false; |
| |
| /** |
| * Classpath file location of the ehcache CacheManager config file. |
| */ |
| private String cacheManagerConfigFile = "classpath:org/ki/cache/ehcache/ehcache.xml"; |
| |
| /** |
| * Default no argument constructor |
| */ |
| public EhCacheManager() { |
| } |
| |
| /** |
| * Returns the wrapped Ehcache {@link net.sf.ehcache.CacheManager CacheManager} instance. |
| * |
| * @return the wrapped Ehcache {@link net.sf.ehcache.CacheManager CacheManager} instance. |
| */ |
| public net.sf.ehcache.CacheManager getCacheManager() { |
| return manager; |
| } |
| |
| /** |
| * Sets the wrapped Ehcache {@link net.sf.ehcache.CacheManager CacheManager} instance. |
| * |
| * @param manager the wrapped Ehcache {@link net.sf.ehcache.CacheManager CacheManager} instance. |
| */ |
| public void setCacheManager(net.sf.ehcache.CacheManager manager) { |
| this.manager = manager; |
| } |
| |
| /** |
| * Returns the resource location of the config file used to initialize a new |
| * EhCache CacheManager instance. The string can be any resource path supported by the |
| * {@link org.apache.ki.io.ResourceUtils#getInputStreamForPath(String)} call. |
| * |
| * <p>This property is ignored if the CacheManager instance is injected directly - that is, it is only used to |
| * lazily create a CacheManager if one is not already provided.</p> |
| * |
| * @return the resource location of the config file used to initialize the wrapped |
| * EhCache CacheManager instance. |
| */ |
| public String getCacheManagerConfigFile() { |
| return this.cacheManagerConfigFile; |
| } |
| |
| /** |
| * Sets the resource location of the config file used to initialize the wrapped |
| * EhCache CacheManager instance. The string can be any resource path supported by the |
| * {@link org.apache.ki.io.ResourceUtils#getInputStreamForPath(String)} call. |
| * |
| * <p>This property is ignored if the CacheManager instance is injected directly - that is, it is only used to |
| * lazily create a CacheManager if one is not already provided.</p> |
| * |
| * @param classpathLocation resource location of the config file used to create the wrapped |
| * EhCache CacheManager instance. |
| */ |
| public void setCacheManagerConfigFile(String classpathLocation) { |
| this.cacheManagerConfigFile = classpathLocation; |
| } |
| |
| /** |
| * Acquires the InputStream for the ehcache configuration file using |
| * {@link ResourceUtils#getInputStreamForPath(String) ResourceUtils.getInputStreamForPath} with the |
| * path returned from {@link #getCacheManagerConfigFile() getCacheManagerConfigFile()}. |
| * |
| * @return the InputStream for the ehcache configuration file. |
| */ |
| protected InputStream getCacheManagerConfigFileInputStream() { |
| String configFile = getCacheManagerConfigFile(); |
| try { |
| return ResourceUtils.getInputStreamForPath(configFile); |
| } catch (IOException e) { |
| throw new IllegalStateException("Unable to obtain input stream for cacheManagerConfigFile.", e); |
| } |
| } |
| |
| /** |
| * Loads an existing EhCache from the cache manager, or starts a new cache if one is not found. |
| * |
| * @param name the name of the cache to load/create. |
| */ |
| public final Cache getCache(String name) throws CacheException { |
| |
| if (log.isTraceEnabled()) { |
| log.trace("Loading a new EhCache cache named [" + name + "]"); |
| } |
| |
| try { |
| net.sf.ehcache.Cache cache = getCacheManager().getCache(name); |
| if (cache == null) { |
| if (log.isInfoEnabled()) { |
| log.info("Could not find a specific ehcache configuration for cache named [" + name + "]; using defaults."); |
| } |
| if (name.equals(DEFAULT_ACTIVE_SESSIONS_CACHE_NAME)) { |
| if (log.isInfoEnabled()) { |
| log.info("Creating " + DEFAULT_ACTIVE_SESSIONS_CACHE_NAME + " cache with default Apache Ki " + |
| "session cache settings."); |
| } |
| cache = buildDefaultActiveSessionsCache(); |
| manager.addCache(cache); |
| } else { |
| manager.addCache(name); |
| } |
| |
| cache = manager.getCache(name); |
| |
| if (log.isInfoEnabled()) { |
| log.info("Started EHCache named [" + name + "]"); |
| } |
| } else { |
| if (log.isInfoEnabled()) { |
| log.info("Using preconfigured EHCache named [" + cache.getName() + "]"); |
| } |
| } |
| return new EhCache(cache); |
| } catch (net.sf.ehcache.CacheException e) { |
| throw new CacheException(e); |
| } |
| } |
| |
| /** |
| * Builds the default cache instance to use for Apache Ki's Session Cache when enterprise Sessions are |
| * enabled. |
| * |
| * @return the default cache instance to use for Apache Ki's Session Cache when enterprise Sessions are |
| * enabled. |
| * @throws CacheException if there is a problem constructing the Cache instance. |
| */ |
| private net.sf.ehcache.Cache buildDefaultActiveSessionsCache() throws CacheException { |
| return new net.sf.ehcache.Cache(DEFAULT_ACTIVE_SESSIONS_CACHE_NAME, |
| DEFAULT_ACTIVE_SESSIONS_CACHE_MAX_ELEM_IN_MEM, |
| true, |
| true, |
| 0, |
| 0, |
| true, |
| DEFAULT_ACTIVE_SESSIONS_DISK_EXPIRY_THREAD_INTERVAL_SECONDS); |
| } |
| |
| /** |
| * Initializes this instance. |
| * |
| * <p>If a {@link #setCacheManager CacheManager} has been |
| * explicitly set (e.g. via Dependency Injection or programatically) prior to calling this |
| * method, this method does nothing.</p> |
| * |
| * <p>However, if no <tt>CacheManager</tt> has been set, the default Ehcache singleton will be initialized, where |
| * Ehcache will look for an <tt>ehcache.xml</tt> file at the root of the classpath. If one is not found, |
| * Ehcache will use its own failsafe configuration file.</p> |
| * |
| * <p>Because Apache Ki cannot use the failsafe defaults (failsafe expunges cached objects after 2 minutes, |
| * something not desireable for Apache Ki sessions), this class manages an internal default configuration for |
| * this case.</p> |
| * |
| * @throws org.apache.ki.cache.CacheException |
| * if there are any CacheExceptions thrown by EhCache. |
| * @see net.sf.ehcache.CacheManager#create |
| */ |
| public final void init() throws CacheException { |
| try { |
| net.sf.ehcache.CacheManager cacheMgr = getCacheManager(); |
| if (cacheMgr == null) { |
| if (log.isDebugEnabled()) { |
| log.debug("cacheManager property not set. Constructing CacheManager instance... "); |
| } |
| //using the CacheManager constructor, the resulting instance is _not_ a VM singleton |
| //(as would be the case by calling CacheManager.getInstance(). We do not use the getInstance here |
| //because we need to know if we need to destroy the CacheManager instance - using the static call, |
| //we don't know which component is responsible for shutting it down. By using a single EhCacheManager, |
| //it will always know to shut down the instance if it was responsible for creating it. |
| cacheMgr = new net.sf.ehcache.CacheManager(getCacheManagerConfigFileInputStream()); |
| if (log.isTraceEnabled()) { |
| log.trace("instantiated Ehcache CacheManager instance."); |
| } |
| cacheManagerImplicitlyCreated = true; |
| setCacheManager(cacheMgr); |
| if (log.isDebugEnabled()) { |
| log.debug("implicit cacheManager created successfully."); |
| } |
| } |
| } catch (Exception e) { |
| throw new CacheException(e); |
| } |
| } |
| |
| /** |
| * Shuts-down the wrapped Ehcache CacheManager <b>only if implicitly created</b>. |
| * |
| * <p>If another component injected |
| * a non-null CacheManager into this instace before calling {@link #init() init}, this instance expects that same |
| * component to also destroy the CacheManager instance, and it will not attempt to do so. |
| */ |
| public void destroy() { |
| if (cacheManagerImplicitlyCreated) { |
| try { |
| net.sf.ehcache.CacheManager cacheMgr = getCacheManager(); |
| cacheMgr.shutdown(); |
| } catch (Exception e) { |
| if (log.isWarnEnabled()) { |
| log.warn("Unable to cleanly shutdown implicitly created CacheManager instance. " + |
| "Ignoring (shutting down)..."); |
| } |
| } |
| cacheManagerImplicitlyCreated = false; |
| } |
| } |
| } |