Java tutorial
/** * Copyright 2003-2007 Luck Consulting Pty Ltd * * 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 net.sf.ehcache; import net.sf.ehcache.config.Configuration; import net.sf.ehcache.config.ConfigurationFactory; import net.sf.ehcache.config.ConfigurationHelper; import net.sf.ehcache.config.DiskStoreConfiguration; import net.sf.ehcache.distribution.CacheManagerPeerListener; import net.sf.ehcache.distribution.CacheManagerPeerProvider; import net.sf.ehcache.event.CacheManagerEventListener; import net.sf.ehcache.event.CacheManagerEventListenerRegistry; import net.sf.ehcache.store.DiskStore; import net.sf.ehcache.util.PropertyUtil; import net.sf.ehcache.jcache.JCache; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import java.io.File; import java.io.InputStream; import java.net.URL; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; /** * A container for {@link Ehcache}s that maintain all aspects of their lifecycle. * <p/> * CacheManager may be either be a singleton if created with factory methods, or multiple instances may exist, * in which case resources required by each must be unique. * <p/> * A CacheManager holds references to Cache, Ehcache, and JCache objects and manages their creation and lifecycle. * * @author Greg Luck * @version $Id: CacheManager.java 612 2008-05-07 22:48:26Z gregluck $ */ public class CacheManager { /** * Keeps track of all known CacheManagers. Used to check on conflicts. * CacheManagers should remove themselves from this list during shut down. */ public static final List ALL_CACHE_MANAGERS = Collections.synchronizedList(new ArrayList()); /** * System property to enable creation of a shutdown hook for CacheManager. */ public static final String ENABLE_SHUTDOWN_HOOK_PROPERTY = "net.sf.ehcache.enableShutdownHook"; private static final Log LOG = LogFactory.getLog(CacheManager.class.getName()); /** * The Singleton Instance. */ private static CacheManager singleton; /** * Ehcaches managed by this manager. */ protected final Map ehcaches = new HashMap(); /** * Caches managed by this manager. A Cache is also an Ehcache. * For central managment the cache is also in the ehcaches map. */ protected final Map caches = new HashMap(); /** * JCaches managed by this manager. For each JCache there is a backing ehcache stored in the ehcaches map. */ protected final Map jCaches = new HashMap(); /** * Default cache cache. */ private Ehcache defaultCache; /** * The path for the directory in which disk caches are created. */ private String diskStorePath; /** * A name for this CacheManager to distinguish it from others. */ private String name; private Status status; private CacheManagerPeerProvider cacheManagerPeerProvider; private CacheManagerPeerListener cacheManagerPeerListener; private CacheManagerEventListenerRegistry cacheManagerEventListenerRegistry = new CacheManagerEventListenerRegistry(); /** * The shutdown hook thread for CacheManager. This ensures that the CacheManager and Caches are left in a * consistent state on a CTRL-C or kill. * <p/> * This thread must be unregistered as a shutdown hook, when the CacheManager is disposed. * Otherwise the CacheManager is not GC-able. * <p/> * Of course kill -9 or abrupt termination will not run the shutdown hook. In this case, various * sanity checks are made at start up. */ private Thread shutdownHook; /** * An constructor for CacheManager, which takes a configuration object, rather than one created by parsing * an ehcache.xml file. This constructor gives complete control over the creation of the CacheManager. * <p/> * Care should be taken to ensure that, if multiple CacheManages are created, they do now overwrite each others * disk store files, as would happend if two were created which used the same diskStore path. * <p/> * This method does not act as a singleton. Callers must maintain their own reference to it. * <p/> * Note that if one of the {@link #create()} methods are called, a new singleton instance will be created, * separate from any instances created in this method. * * @param configuration * @throws CacheException */ public CacheManager(Configuration configuration) throws CacheException { status = Status.STATUS_UNINITIALISED; init(configuration, null, null, null); } /** * An ordinary constructor for CacheManager. * This method does not act as a singleton. Callers must maintain a reference to it. * Note that if one of the {@link #create()} methods are called, a new singleton will be created, * separate from any instances created in this method. * * @param configurationFileName an xml configuration file available through a file name. The configuration * {@link File} is created * using new <code>File(configurationFileName)</code> * @throws CacheException * @see #create(String) */ public CacheManager(String configurationFileName) throws CacheException { status = Status.STATUS_UNINITIALISED; init(null, configurationFileName, null, null); } /** * An ordinary constructor for CacheManager. * This method does not act as a singleton. Callers must maintain a reference to it. * Note that if one of the {@link #create()} methods are called, a new singleton will be created, * separate from any instances created in this method. * <p/> * This method can be used to specify a configuration resource in the classpath other * than the default of \"/ehcache.xml\": * <pre> * URL url = this.getClass().getResource("/ehcache-2.xml"); * </pre> * Note that {@link Class#getResource} will look for resources in the same package unless a leading "/" * is used, in which case it will look in the root of the classpath. * <p/> * You can also load a resource using other class loaders. e.g. {@link Thread#getContextClassLoader()} * * @param configurationURL an xml configuration available through a URL. * @throws CacheException * @see #create(java.net.URL) * @since 1.2 */ public CacheManager(URL configurationURL) throws CacheException { status = Status.STATUS_UNINITIALISED; init(null, null, configurationURL, null); } /** * An ordinary constructor for CacheManager. * This method does not act as a singleton. Callers must maintain a reference to it. * Note that if one of the {@link #create()} methods are called, a new singleton will be created, * separate from any instances created in this method. * * @param configurationInputStream an xml configuration file available through an inputstream * @throws CacheException * @see #create(java.io.InputStream) */ public CacheManager(InputStream configurationInputStream) throws CacheException { status = Status.STATUS_UNINITIALISED; init(null, null, null, configurationInputStream); } /** * Constructor. * * @throws CacheException */ public CacheManager() throws CacheException { //default config will be done status = Status.STATUS_UNINITIALISED; init(null, null, null, null); } private void init(Configuration configuration, String configurationFileName, URL configurationURL, InputStream configurationInputStream) { Configuration localConfiguration = configuration; if (configuration == null) { localConfiguration = parseConfiguration(configurationFileName, configurationURL, configurationInputStream); } else { localConfiguration.setSource("Programmatically configured."); } ConfigurationHelper configurationHelper = new ConfigurationHelper(this, localConfiguration); configure(configurationHelper); status = Status.STATUS_ALIVE; if (cacheManagerPeerProvider != null) { cacheManagerPeerProvider.init(); } cacheManagerEventListenerRegistry.init(); addShutdownHookIfRequired(); //do this last addConfiguredCaches(configurationHelper); } /** * Loads configuration, either from the supplied {@link ConfigurationHelper} or by creating a new Configuration instance * from the configuration file referred to by file, inputstream or URL. * <p/> * Should only be called once. * * @param configurationFileName the file name to parse, or null * @param configurationURL the URL to pass, or null * @param configurationInputStream, the InputStream to parse, or null * @return the loaded configuration * @throws CacheException if the configuration cannot be parsed */ private synchronized Configuration parseConfiguration(String configurationFileName, URL configurationURL, InputStream configurationInputStream) throws CacheException { reinitialisationCheck(); Configuration configuration; String configurationSource; if (configurationFileName != null) { if (LOG.isDebugEnabled()) { LOG.debug("Configuring CacheManager from " + configurationFileName); } configuration = ConfigurationFactory.parseConfiguration(new File(configurationFileName)); configurationSource = "file located at " + configurationFileName; } else if (configurationURL != null) { configuration = ConfigurationFactory.parseConfiguration(configurationURL); configurationSource = "URL of " + configurationURL; } else if (configurationInputStream != null) { configuration = ConfigurationFactory.parseConfiguration(configurationInputStream); configurationSource = "InputStream " + configurationInputStream; } else { if (LOG.isDebugEnabled()) { LOG.debug("Configuring ehcache from classpath."); } configuration = ConfigurationFactory.parseConfiguration(); configurationSource = "classpath"; } configuration.setSource(configurationSource); return configuration; } private void configure(ConfigurationHelper configurationHelper) { diskStorePath = configurationHelper.getDiskStorePath(); int cachesRequiringDiskStores = configurationHelper.numberOfCachesThatOverflowToDisk().intValue() + configurationHelper.numberOfCachesThatAreDiskPersistent().intValue(); if (diskStorePath == null && cachesRequiringDiskStores > 0) { diskStorePath = DiskStoreConfiguration.getDefaultPath(); LOG.warn("One or more caches require a DiskStore but there is no diskStore element configured." + " Using the default disk store path of " + DiskStoreConfiguration.getDefaultPath() + ". Please explicitly configure the diskStore element in ehcache.xml."); } detectAndFixDiskStorePathConflict(configurationHelper); cacheManagerEventListenerRegistry.registerListener(configurationHelper.createCacheManagerEventListener()); cacheManagerPeerListener = configurationHelper.createCachePeerListener(); cacheManagerEventListenerRegistry.registerListener(cacheManagerPeerListener); detectAndFixCacheManagerPeerListenerConflict(configurationHelper); ALL_CACHE_MANAGERS.add(this); cacheManagerPeerProvider = configurationHelper.createCachePeerProvider(); defaultCache = configurationHelper.createDefaultCache(); } private void detectAndFixDiskStorePathConflict(ConfigurationHelper configurationHelper) { if (diskStorePath == null) { if (LOG.isDebugEnabled()) { LOG.debug("No disk store path defined. Skipping disk store path conflict test."); } return; } for (int i = 0; i < ALL_CACHE_MANAGERS.size(); i++) { CacheManager cacheManager = (CacheManager) ALL_CACHE_MANAGERS.get(i); if (diskStorePath.equals(cacheManager.diskStorePath)) { String newDiskStorePath = diskStorePath + File.separator + DiskStore.generateUniqueDirectory(); LOG.warn("Creating a new instance of CacheManager using the diskStorePath \"" + diskStorePath + "\" which is already used" + " by an existing CacheManager.\nThe source of the configuration was " + configurationHelper.getConfigurationBean().getConfigurationSource() + ".\n" + "The diskStore path for this CacheManager will be set to " + newDiskStorePath + ".\nTo avoid this" + " warning consider using the CacheManager factory methods to create a singleton CacheManager " + "or specifying a separate ehcache configuration (ehcache.xml) for each CacheManager instance."); diskStorePath = newDiskStorePath; break; } } } private void detectAndFixCacheManagerPeerListenerConflict(ConfigurationHelper configurationHelper) { if (cacheManagerPeerListener == null) { return; } String uniqueResourceIdentifier = cacheManagerPeerListener.getUniqueResourceIdentifier(); for (int i = 0; i < ALL_CACHE_MANAGERS.size(); i++) { CacheManager cacheManager = (CacheManager) ALL_CACHE_MANAGERS.get(i); CacheManagerPeerListener otherCacheManagerPeerListener = cacheManager.cacheManagerPeerListener; if (otherCacheManagerPeerListener == null) { continue; } String otherUniqueResourceIdentifier = otherCacheManagerPeerListener.getUniqueResourceIdentifier(); if (uniqueResourceIdentifier.equals(otherUniqueResourceIdentifier)) { LOG.warn("Creating a new instance of CacheManager with a CacheManagerPeerListener which " + "has a conflict on a resource that must be unique.\n" + "The resource is " + uniqueResourceIdentifier + ".\n" + "Attempting automatic resolution. The source of the configuration was " + configurationHelper.getConfigurationBean().getConfigurationSource() + ".\n" + "To avoid this warning consider using the CacheManager factory methods to create a " + "singleton CacheManager " + "or specifying a separate ehcache configuration (ehcache.xml) for each CacheManager instance."); cacheManagerPeerListener.attemptResolutionOfUniqueResourceConflict(); break; } } } private void addConfiguredCaches(ConfigurationHelper configurationHelper) { Set unitialisedCaches = configurationHelper.createCaches(); for (Iterator iterator = unitialisedCaches.iterator(); iterator.hasNext();) { Ehcache unitialisedCache = (Ehcache) iterator.next(); addCacheNoCheck(unitialisedCache); } } private void reinitialisationCheck() throws IllegalStateException { if (defaultCache != null || diskStorePath != null || ehcaches.size() != 0 || status.equals(Status.STATUS_SHUTDOWN)) { throw new IllegalStateException("Attempt to reinitialise the CacheManager"); } } /** * A factory method to create a singleton CacheManager with default config, or return it if it exists. * <p/> * The configuration will be read, {@link Ehcache}s created and required stores initialized. * When the {@link CacheManager} is no longer required, call shutdown to free resources. * * @return the singleton CacheManager * @throws CacheException if the CacheManager cannot be created */ public static CacheManager create() throws CacheException { synchronized (CacheManager.class) { if (singleton == null) { if (LOG.isDebugEnabled()) { LOG.debug("Creating new CacheManager with default config"); } singleton = new CacheManager(); } else { if (LOG.isDebugEnabled()) { LOG.debug("Attempting to create an existing singleton. Existing singleton returned."); } } return singleton; } } /** * A factory method to create a singleton CacheManager with default config, or return it if it exists. * <p/> * This has the same effect as {@link CacheManager#create} * <p/> * Same as {@link #create()} * * @return the singleton CacheManager * @throws CacheException if the CacheManager cannot be created */ public static CacheManager getInstance() throws CacheException { return CacheManager.create(); } /** * A factory method to create a singleton CacheManager with a specified configuration. * * @param configurationFileName an xml file compliant with the ehcache.xsd schema * <p/> * The configuration will be read, {@link Ehcache}s created and required stores initialized. * When the {@link CacheManager} is no longer required, call shutdown to free resources. */ public static CacheManager create(String configurationFileName) throws CacheException { synchronized (CacheManager.class) { if (singleton == null) { if (LOG.isDebugEnabled()) { LOG.debug("Creating new CacheManager with config file: " + configurationFileName); } singleton = new CacheManager(configurationFileName); } return singleton; } } /** * A factory method to create a singleton CacheManager from an URL. * <p/> * This method can be used to specify a configuration resource in the classpath other * than the default of \"/ehcache.xml\": * This method can be used to specify a configuration resource in the classpath other * than the default of \"/ehcache.xml\": * <pre> * URL url = this.getClass().getResource("/ehcache-2.xml"); * </pre> * Note that {@link Class#getResource} will look for resources in the same package unless a leading "/" * is used, in which case it will look in the root of the classpath. * <p/> * You can also load a resource using other class loaders. e.g. {@link Thread#getContextClassLoader()} * * @param configurationFileURL an URL to an xml file compliant with the ehcache.xsd schema * <p/> * The configuration will be read, {@link Ehcache}s created and required stores initialized. * When the {@link CacheManager} is no longer required, call shutdown to free resources. */ public static CacheManager create(URL configurationFileURL) throws CacheException { synchronized (CacheManager.class) { if (singleton == null) { if (LOG.isDebugEnabled()) { LOG.debug("Creating new CacheManager with config URL: " + configurationFileURL); } singleton = new CacheManager(configurationFileURL); } return singleton; } } /** * A factory method to create a singleton CacheManager from a java.io.InputStream. * <p/> * This method makes it possible to use an inputstream for configuration. * Note: it is the clients responsibility to close the inputstream. * <p/> * * @param inputStream InputStream of xml compliant with the ehcache.xsd schema * <p/> * The configuration will be read, {@link Ehcache}s created and required stores initialized. * When the {@link CacheManager} is no longer required, call shutdown to free resources. */ public static CacheManager create(InputStream inputStream) throws CacheException { synchronized (CacheManager.class) { if (singleton == null) { if (LOG.isDebugEnabled()) { LOG.debug("Creating new CacheManager with InputStream"); } singleton = new CacheManager(inputStream); } return singleton; } } /** * Returns a concrete implementation of Cache, it it is available in the CacheManager. * Consider using getEhcache(String name) instead, which will return decorated caches that are registered. * <p/> * If a decorated ehcache is registered in CacheManager, an undecorated Cache with the same name will also exist. * * @return a Cache, if an object of that type exists by that name, else null * @throws IllegalStateException if the cache is not {@link Status#STATUS_ALIVE} * @see #getEhcache(String) */ public synchronized Cache getCache(String name) throws IllegalStateException, ClassCastException { checkStatus(); return (Cache) caches.get(name); } /** * Gets an Ehcache * <p/> * * @return a Cache, if an object of type Cache exists by that name, else null * @throws IllegalStateException if the cache is not {@link Status#STATUS_ALIVE} */ public synchronized Ehcache getEhcache(String name) throws IllegalStateException { checkStatus(); return (Ehcache) ehcaches.get(name); } /** * Gets a draft JSR107 spec JCache. * <p/> * If a JCache does not exist for the name, but an ehcache does, a new JCache will be created dynamically and added * to the list of JCaches managed by this CacheManager. * Warning: JCache will change as the specification changes, so no guarantee of backward compatibility is made for this method. * * @return a JSR 107 Cache, if an object of that type exists by that name, else null * @throws IllegalStateException if the cache is not {@link Status#STATUS_ALIVE} */ public synchronized JCache getJCache(String name) throws IllegalStateException { checkStatus(); if (jCaches.get(name) != null) { return (JCache) jCaches.get(name); } else if (ehcaches.get(name) != null) { jCaches.put(name, new JCache((Ehcache) ehcaches.get(name), null)); } return (JCache) jCaches.get(name); } /** * Some caches might be persistent, so we want to add a shutdown hook if that is the * case, so that the data and index can be written to disk. */ private void addShutdownHookIfRequired() { String shutdownHookProperty = System.getProperty(ENABLE_SHUTDOWN_HOOK_PROPERTY); boolean enabled = PropertyUtil.parseBoolean(shutdownHookProperty); if (!enabled) { return; } else { LOG.info("The CacheManager shutdown hook is enabled because " + ENABLE_SHUTDOWN_HOOK_PROPERTY + " is set to true."); Thread localShutdownHook = new Thread() { public void run() { synchronized (this) { if (status.equals(Status.STATUS_ALIVE)) { // clear shutdown hook reference to prevent // removeShutdownHook to remove it during shutdown shutdownHook = null; if (LOG.isInfoEnabled()) { LOG.info("VM shutting down with the CacheManager still active. Calling shutdown."); } shutdown(); } } } }; Runtime.getRuntime().addShutdownHook(localShutdownHook); shutdownHook = localShutdownHook; } } /** * Remove the shutdown hook to prevent leaving orphaned CacheManagers around. This * is called by {@link #shutdown()}} AFTER the status has been set to shutdown. */ private void removeShutdownHook() { if (shutdownHook != null) { // remove shutdown hook try { Runtime.getRuntime().removeShutdownHook(shutdownHook); } catch (IllegalStateException e) { //This will be thrown if the VM is shutting down. In this case //we do not need to worry about leaving references to CacheManagers lying //around and the call is ok to fail. if (LOG.isDebugEnabled()) { LOG.debug("IllegalStateException due to attempt to remove a shutdown" + "hook while the VM is actually shutting down.", e); } } shutdownHook = null; } } /** * Adds a {@link Ehcache} based on the defaultCache with the given name. * <p/> * Memory and Disk stores will be configured for it and it will be added * to the map of caches. * <p/> * Also notifies the CacheManagerEventListener after the cache was initialised and added. * <p/> * It will be created with the defaultCache attributes specified in ehcache.xml * * @param cacheName the name for the cache * @throws ObjectExistsException if the cache already exists * @throws CacheException if there was an error creating the cache. */ public synchronized void addCache(String cacheName) throws IllegalStateException, ObjectExistsException, CacheException { checkStatus(); //NPE guard if (cacheName == null || cacheName.length() == 0) { return; } if (ehcaches.get(cacheName) != null) { throw new ObjectExistsException("Cache " + cacheName + " already exists"); } Ehcache cache = null; try { cache = (Ehcache) defaultCache.clone(); } catch (CloneNotSupportedException e) { throw new CacheException("Failure adding cache. Initial cause was " + e.getMessage(), e); } if (cache != null) { cache.setName(cacheName); } addCache(cache); } /** * Adds a {@link Cache} to the CacheManager. * <p/> * Memory and Disk stores will be configured for it and it will be added to the map of caches. * Also notifies the CacheManagerEventListener after the cache was initialised and added. * * @param cache * @throws IllegalStateException if the cache is not {@link Status#STATUS_UNINITIALISED} before this method is called. * @throws ObjectExistsException if the cache already exists in the CacheManager * @throws CacheException if there was an error adding the cache to the CacheManager */ public synchronized void addCache(Cache cache) throws IllegalStateException, ObjectExistsException, CacheException { checkStatus(); if (cache == null) { return; } addCache((Ehcache) cache); caches.put(cache.getName(), cache); } /** * Adds a {@link Cache} to the CacheManager. * <p/> * Memory and Disk stores will be configured for it and it will be added to the map of caches. * Also notifies the CacheManagerEventListener after the cache was initialised and added. * * @param jCache * @throws IllegalStateException if the cache is not {@link Status#STATUS_UNINITIALISED} before this method is called. * @throws ObjectExistsException if the cache already exists in the CacheManager * @throws CacheException if there was an error adding the cache to the CacheManager */ public synchronized void addCache(JCache jCache) throws IllegalStateException, ObjectExistsException, CacheException { checkStatus(); if (jCache == null) { return; } Ehcache backingCache = jCache.getBackingCache(); addCache(backingCache); jCaches.put(backingCache.getName(), jCache); } /** * Adds an {@link Ehcache} to the CacheManager. * <p/> * Memory and Disk stores will be configured for it and it will be added to the map of caches. * Also notifies the CacheManagerEventListener after the cache was initialised and added. * * @param cache * @throws IllegalStateException if the cache is not {@link Status#STATUS_UNINITIALISED} before this method is called. * @throws ObjectExistsException if the cache already exists in the CacheManager * @throws CacheException if there was an error adding the cache to the CacheManager */ public synchronized void addCache(Ehcache cache) throws IllegalStateException, ObjectExistsException, CacheException { checkStatus(); if (cache == null) { return; } addCacheNoCheck(cache); } private synchronized void addCacheNoCheck(Ehcache cache) throws IllegalStateException, ObjectExistsException, CacheException { if (ehcaches.get(cache.getName()) != null) { throw new ObjectExistsException("Cache " + cache.getName() + " already exists"); } cache.setCacheManager(this); cache.setDiskStorePath(diskStorePath); cache.initialise(); try { cache.bootstrap(); } catch (CacheException e) { LOG.warn("Cache " + cache.getName() + "requested bootstrap but a CacheException occured. " + e.getMessage(), e); } ehcaches.put(cache.getName(), cache); if (cache instanceof Cache) { caches.put(cache.getName(), cache); } //Don't notify initial config. The init method of each listener should take care of this. if (status.equals(Status.STATUS_ALIVE)) { cacheManagerEventListenerRegistry.notifyCacheAdded(cache.getName()); } } /** * Checks whether a cache of type ehcache exists. * <p/> * * @param cacheName the cache name to check for * @return true if it exists * @throws IllegalStateException if the cache is not {@link Status#STATUS_ALIVE} */ public synchronized boolean cacheExists(String cacheName) throws IllegalStateException { checkStatus(); return (ehcaches.get(cacheName) != null); } /** * Removes all caches using {@link #removeCache} for each cache. */ public synchronized void removalAll() { String[] cacheNames = getCacheNames(); for (int i = 0; i < cacheNames.length; i++) { String cacheName = cacheNames[i]; removeCache(cacheName); } } /** * Remove a cache from the CacheManager. The cache is disposed of. * * @param cacheName the cache name * @throws IllegalStateException if the cache is not {@link Status#STATUS_ALIVE} */ public synchronized void removeCache(String cacheName) throws IllegalStateException { checkStatus(); //NPE guard if (cacheName == null || cacheName.length() == 0) { return; } Ehcache cache = (Ehcache) ehcaches.remove(cacheName); if (cache != null && cache.getStatus().equals(Status.STATUS_ALIVE)) { cache.dispose(); cacheManagerEventListenerRegistry.notifyCacheRemoved(cache.getName()); } jCaches.remove(cacheName); caches.remove(cacheName); } /** * Shuts down the CacheManager. * <p/> * If the shutdown occurs on the singleton, then the singleton is removed, so that if a singleton access method * is called, a new singleton will be created. * <p/> * By default there is no shutdown hook (ehcache-1.3-beta2 and higher). * <p/> * Set the system property net.sf.ehcache.enableShutdownHook=true to turn it on. */ public void shutdown() { synchronized (CacheManager.class) { if (status.equals(Status.STATUS_SHUTDOWN)) { if (LOG.isDebugEnabled()) { LOG.debug("CacheManager already shutdown"); } return; } if (cacheManagerPeerProvider != null) { cacheManagerPeerProvider.dispose(); } cacheManagerEventListenerRegistry.dispose(); synchronized (CacheManager.class) { ALL_CACHE_MANAGERS.remove(this); Collection cacheSet = ehcaches.values(); for (Iterator iterator = cacheSet.iterator(); iterator.hasNext();) { Ehcache cache = (Ehcache) iterator.next(); if (cache != null) { cache.dispose(); } } defaultCache.dispose(); status = Status.STATUS_SHUTDOWN; //only delete singleton if the singleton is shutting down. if (this == singleton) { singleton = null; } removeShutdownHook(); } } } /** * Returns a list of the current cache names. * * @return an array of {@link String}s * @throws IllegalStateException if the cache is not {@link Status#STATUS_ALIVE} */ public synchronized String[] getCacheNames() throws IllegalStateException { checkStatus(); String[] list = new String[ehcaches.size()]; return (String[]) ehcaches.keySet().toArray(list); } private void checkStatus() { if (!(status.equals(Status.STATUS_ALIVE))) { throw new IllegalStateException("The CacheManager is not alive."); } } /** * Gets the status attribute of the Ehcache * * @return The status value from the Status enum class */ public Status getStatus() { return status; } /** * Clears the contents of all caches in the CacheManager, but without * removing any caches. * <p/> * This method is not synchronized. It only guarantees to clear those elements in a cache * at the time that the {@link Ehcache#removeAll()} mehod on each cache is called. */ public void clearAll() throws CacheException { String[] cacheNames = getCacheNames(); if (LOG.isDebugEnabled()) { LOG.debug("Clearing all caches"); } for (int i = 0; i < cacheNames.length; i++) { String cacheName = cacheNames[i]; Ehcache cache = getEhcache(cacheName); cache.removeAll(); } } /** * Gets the <code>CacheManagerPeerProvider</code> * For distributed caches, the peer provider finds other cache managers and their caches in the same cluster * * @return the provider, or null if one does not exist */ public CacheManagerPeerProvider getCachePeerProvider() { return cacheManagerPeerProvider; } /** * When CacheManage is configured as part of a cluster, a CacheManagerPeerListener will * be registered in it. Use this to access the individual cache listeners * * @return the listener, or null if one does not exist */ public CacheManagerPeerListener getCachePeerListener() { return cacheManagerPeerListener; } /** * Returns the composite listener. A notification sent to this listener will notify all registered * listeners. * * @return null if none * @see "getCacheManagerEventListenerRegistry" */ public CacheManagerEventListener getCacheManagerEventListener() { return cacheManagerEventListenerRegistry; } /** * Same as getCacheManagerEventListenerRegistry().registerListener(cacheManagerEventListener); * Left for backward compatiblity * * @param cacheManagerEventListener the listener to set. * @see "getCacheManagerEventListenerRegistry" * @deprecated Use getCacheManagerEventListenerRegistry instead */ public void setCacheManagerEventListener(CacheManagerEventListener cacheManagerEventListener) { getCacheManagerEventListenerRegistry().registerListener(cacheManagerEventListener); } /** * Gets the CacheManagerEventListenerRegistry. Add and remove listeners here. */ public CacheManagerEventListenerRegistry getCacheManagerEventListenerRegistry() { return cacheManagerEventListenerRegistry; } /** * Gets the CacheManagerPeerProvider, which can be useful for programmatically adding peers. Adding peers * will only be useful if the peer providers are manually provided rather than automatically discovered, otherwise * they will go stale. * * @return the CacheManagerPeerProvider, or null if there is not one. */ public CacheManagerPeerProvider getCacheManagerPeerProvider() { return cacheManagerPeerProvider; } /** * Replaces in the map of Caches managed by this CacheManager an Ehcache with a decorated version of the same * Ehcache. CacheManager can operate fully with a decorated Ehcache. * <p/> * Ehcache Decorators can be used to obtain different behaviour from an Ehcache in a very flexible way. Some examples in * ehcache are: * <ol> * <li>{@link net.sf.ehcache.constructs.blocking.BlockingCache} - A cache that blocks other threads from getting a null element until the first thread * has placed a value in it. * <li>{@link net.sf.ehcache.constructs.blocking.SelfPopulatingCache} - A BlockingCache that has the additional * property of knowing how to load its own entries. * </ol> * Many other kinds are possible. * <p/> * It is generally required that a decorated cache, once constructed, is made available to other execution threads. * The simplest way of doing this is to substitute the original cache for the decorated one here. * <p/> * Note that any overwritten Ehcache methods will take on new behaviours without casting. Casting is only required * for new methods that the decorator introduces. * For more information see the well known Gang of Four Decorator pattern. * * @param ehcache * @param decoratedCache An implementation of Ehcache that wraps the original cache. * @throws CacheException if the two caches do not equal each other. */ public synchronized void replaceCacheWithDecoratedCache(Ehcache ehcache, Ehcache decoratedCache) throws CacheException { if (!ehcache.equals(decoratedCache)) { throw new CacheException( "Cannot replace " + decoratedCache.getName() + " It does not equal the incumbent cache."); } else { String cacheName = ehcache.getName(); ehcaches.remove(cacheName); caches.remove(cacheName); ehcaches.put(decoratedCache.getName(), decoratedCache); if (decoratedCache instanceof Cache) { caches.put(decoratedCache.getName(), decoratedCache); } } } /** * Replaces in the map of Caches managed by this CacheManager an Ehcache with a JCache decorated version of the <i>same</i> (see Ehcache equals method) * Ehcache, in a single synchronized method. * <p/> * Warning: JCache will change as the specification changes, so no guarantee of backward compatibility is made for this method. * * @param ehcache * @param jCache A JCache that wraps the original cache. * @throws CacheException */ public synchronized void replaceEhcacheWithJCache(Ehcache ehcache, JCache jCache) throws CacheException { if (!ehcache.getName().equals(jCache.getBackingCache().getName())) { throw new CacheException( "Cannot replace ehcache with a JCache where the backing cache has a different name"); } Ehcache backingCache = jCache.getBackingCache(); if (!ehcache.equals(backingCache)) { throw new CacheException( "Cannot replace " + backingCache.getName() + " It does not equal the incumbent cache."); } else { jCaches.put(backingCache.getName(), jCache); } } /** * Gets the name of the CacheManager. This is useful for distinguishing multiple CacheManagers * * @return the name, or the output of toString() if it is not set. * @see #toString() which uses either the name or Object.toString() */ public String getName() { if (name != null) { return name; } else { return super.toString(); } } /** * Sets the name of the CacheManager. This is useful for distinguishing multiple CacheManagers * in a monitoring situation. * * @param name a name with characters legal in a JMX ObjectName */ public void setName(String name) { this.name = name; } /** * @return either the name of this CacheManager, or if unset, Object.toString() */ public String toString() { return getName(); } /** * Returns the disk store path. This may be null if no caches need a DiskStore and none was configured. * The path cannot be changed after creation of the CacheManager. All caches take the disk store path * from this value. * @return the disk store path. */ public String getDiskStorePath() { return diskStorePath; } }