Java from design pattern singleton to implement that is terracotta ehcache cacheManager
https://www.runoob.com/design-pattern/singleton-pattern.html#:~:text=单例模式 单例模式(Singleton Pattern)是,Java 中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。 这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建
public class Singleton {
private volatile static Singleton singleton;
private Singleton (){}
public static Singleton getSingleton() {
if (singleton == null) {
synchronized (Singleton.class) {
if (singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
}
/**
- Copyright 2003-2010 Terracotta, Inc.
- 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 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.Properties;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.TimeoutException;
import net.sf.ehcache.cluster.CacheCluster;
import net.sf.ehcache.cluster.ClusterScheme;
import net.sf.ehcache.cluster.ClusterSchemeNotAvailableException;
import net.sf.ehcache.cluster.NoopCacheCluster;
import net.sf.ehcache.config.CacheConfiguration;
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.config.FactoryConfiguration;
import net.sf.ehcache.config.InvalidConfigurationException;
import net.sf.ehcache.config.TerracottaClientConfiguration;
import net.sf.ehcache.config.TerracottaConfiguration.Consistency;
import net.sf.ehcache.config.TerracottaConfiguration.StorageStrategy;
import net.sf.ehcache.config.generator.ConfigurationUtil;
import net.sf.ehcache.constructs.nonstop.CacheManagerExecutorServiceFactory;
import net.sf.ehcache.constructs.nonstop.NonStopCacheException;
import net.sf.ehcache.constructs.nonstop.NonstopExecutorService;
import net.sf.ehcache.constructs.nonstop.NonstopExecutorServiceFactory;
import net.sf.ehcache.distribution.CacheManagerPeerListener;
import net.sf.ehcache.distribution.CacheManagerPeerProvider;
import net.sf.ehcache.event.CacheEventListener;
import net.sf.ehcache.event.CacheManagerEventListener;
import net.sf.ehcache.event.CacheManagerEventListenerRegistry;
import net.sf.ehcache.management.provider.MBeanRegistrationProvider;
import net.sf.ehcache.management.provider.MBeanRegistrationProviderException;
import net.sf.ehcache.management.provider.MBeanRegistrationProviderFactory;
import net.sf.ehcache.management.provider.MBeanRegistrationProviderFactoryImpl;
import net.sf.ehcache.store.DiskStore;
import net.sf.ehcache.store.Store;
import net.sf.ehcache.terracotta.ClusteredInstanceFactory;
import net.sf.ehcache.terracotta.TerracottaClient;
import net.sf.ehcache.terracotta.TerracottaClientRejoinListener;
import net.sf.ehcache.transaction.ReadCommittedSoftLockFactoryImpl;
import net.sf.ehcache.transaction.SoftLockFactory;
import net.sf.ehcache.transaction.TransactionIDFactory;
import net.sf.ehcache.transaction.TransactionIDFactoryImpl;
import net.sf.ehcache.transaction.manager.TransactionManagerLookup;
import net.sf.ehcache.transaction.xa.processor.XARequestProcessor;
import net.sf.ehcache.util.FailSafeTimer;
import net.sf.ehcache.util.PropertyUtil;
import net.sf.ehcache.util.UpdateChecker;
import net.sf.ehcache.writer.writebehind.WriteBehind;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
-
A container for {@link Ehcache}s that maintain all aspects of their lifecycle.
-
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.
-
A CacheManager holds references to Caches and Ehcaches and manages their creation and lifecycle.
-
@author Greg Luck
-
@version $Id: CacheManager.java 4187 2011-06-27 11:46:16Z asingh $
*/
public class CacheManager {/**
- Default name if not specified in the configuration/
*/
public static final String DEFAULT_NAME = "DEFAULT";
/**
- Keeps track of all known CacheManagers. Used to check on conflicts.
- CacheManagers should remove themselves from this list during shut down.
*/
public static final ListALL_CACHE_MANAGERS = new CopyOnWriteArrayList ();
/**
- 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 Logger LOG = LoggerFactory.getLogger(CacheManager.class);
/**
- Update check interval - one week in milliseconds
*/
private static final long EVERY_WEEK = 7 * 24 * 60 * 60 * 1000;
/**
- delay period before doing update check
*/
private static final long DELAY_UPDATE_CHECK = 1000;
/**
- The Singleton Instance.
*/
private static volatile CacheManager singleton;
/**
- The factory to use for creating MBeanRegistrationProvider's
*/
private static final MBeanRegistrationProviderFactory MBEAN_REGISTRATION_PROVIDER_FACTORY = new MBeanRegistrationProviderFactoryImpl();
private static final String NO_DEFAULT_CACHE_ERROR_MSG = "Caches cannot be added by name when default cache config is not specified"
+ " in the config. Please add a default cache config in the configuration.";/**
- A name for this CacheManager to distinguish it from others.
*/
protected volatile String name;
/**
- Status of the Cache Manager
*/
protected volatile Status status;
/**
- The map of providers
*/
protected final MapcacheManagerPeerProviders = new ConcurrentHashMap ();
/**
- The map of listeners
*/
protected final MapcacheManagerPeerListeners = new ConcurrentHashMap ();
/**
- The listener registry
*/
protected final 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.
- This thread must be unregistered as a shutdown hook, when the CacheManager is disposed. Otherwise the CacheManager is not GC-able.
- Of course kill -9 or abrupt termination will not run the shutdown hook. In this case, various sanity checks are made at start up.
*/
protected Thread shutdownHook;
/**
- Ehcaches managed by this manager.
*/
private final ConcurrentMapehcaches = new ConcurrentHashMap ();
/**
- Default cache cache.
*/
private Ehcache defaultCache;
/**
- The path for the directory in which disk caches are created.
*/
private String diskStorePath;
private MBeanRegistrationProvider mbeanRegistrationProvider;
private FailSafeTimer cacheManagerTimer;
private volatile TerracottaClient terracottaClient;
/**
- The {@link TerracottaClientConfiguration} used for this {@link CacheManager}
*/
private TerracottaClientConfiguration terracottaClientConfiguration;
private Configuration configuration;
private volatile boolean allowsDynamicCacheConfig = true;
private volatile TransactionManagerLookup transactionManagerLookup;
private volatile TransactionController transactionController;
private final ConcurrentMap
softLockFactories = new ConcurrentHashMap (); private final NonstopExecutorServiceFactory nonstopExecutorServiceFactory = CacheManagerExecutorServiceFactory.getInstance();
/**
- 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.
- 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.
- This method does not act as a singleton. Callers must maintain their own reference to it.
- 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
File(configurationFileName)
- @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.
- This method can be used to specify a configuration resource in the classpath other than the default of "/ehcache.xml":
- URL url = this.getClass().getResource("/ehcache-2.xml");
- 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.
- 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);
}
/**
-
initialises the CacheManager
*/
protected void init(Configuration initialConfiguration, String configurationFileName, URL configurationURL,
InputStream configurationInputStream) {
Configuration localConfiguration = initialConfiguration;
if (initialConfiguration == null) {
localConfiguration = parseConfiguration(configurationFileName, configurationURL, configurationInputStream);
this.configuration = localConfiguration;
} else {
this.configuration = initialConfiguration;
}if (this.configuration.getTerracottaConfiguration() != null) {
this.configuration.getTerracottaConfiguration().freezeConfig();
}
validateConfiguration();if (localConfiguration.getName() != null) {
this.name = localConfiguration.getName();
}this.allowsDynamicCacheConfig = localConfiguration.getDynamicConfig();
this.terracottaClientConfiguration = localConfiguration.getTerracottaConfiguration();terracottaClient = new TerracottaClient(this, new TerracottaClientRejoinListener() {
public void clusterRejoinStarted() {
CacheManager.this.clusterRejoinStarted();
}public void clusterRejoinComplete() { CacheManager.this.clusterRejoinComplete(); }
}, localConfiguration.getTerracottaConfiguration());
Map
cacheConfigs = localConfiguration.getCacheConfigurations();
if (localConfiguration.getDefaultCacheConfiguration() != null
&& localConfiguration.getDefaultCacheConfiguration().isTerracottaClustered()) {
terracottaClient.createClusteredInstanceFactory(cacheConfigs);
} else {
for (CacheConfiguration config : cacheConfigs.values()) {
if (config.isTerracottaClustered()) {
terracottaClient.createClusteredInstanceFactory(cacheConfigs);
break;
}
}
}if (terracottaClient.getClusteredInstanceFactory() != null && this.name == null) {
this.name = CacheManager.DEFAULT_NAME;
}TransactionIDFactory transactionIDFactory = createTransactionIDFactory();
this.transactionController = new TransactionController(transactionIDFactory, configuration.getDefaultTransactionTimeoutInSeconds());ConfigurationHelper configurationHelper = new ConfigurationHelper(this, localConfiguration);
configure(configurationHelper);
status = Status.STATUS_ALIVE;for (CacheManagerPeerProvider cacheManagerPeerProvider : cacheManagerPeerProviders.values()) {
cacheManagerPeerProvider.init();
}cacheManagerEventListenerRegistry.init();
addShutdownHookIfRequired();cacheManagerTimer = new FailSafeTimer(getName());
checkForUpdateIfNeeded(localConfiguration.getUpdateCheck());mbeanRegistrationProvider = MBEAN_REGISTRATION_PROVIDER_FACTORY.createMBeanRegistrationProvider(localConfiguration);
// do this last
addConfiguredCaches(configurationHelper);try {
mbeanRegistrationProvider.initialize(this, terracottaClient.getClusteredInstanceFactory());
} catch (MBeanRegistrationProviderException e) {
LOG.warn("Failed to initialize the MBeanRegistrationProvider - " + mbeanRegistrationProvider.getClass().getName(), e);
}
}
private boolean isTerracottaRejoinEnabled() {
TerracottaClientConfiguration terracottaConfiguration = configuration.getTerracottaConfiguration();
return terracottaConfiguration != null && terracottaConfiguration.isRejoin();
}private void validateConfiguration() {
if (isTerracottaRejoinEnabled()) {
validateCacheConfigs(configuration.getCacheConfigurations().values());
}
}private void validateCacheConfigs(Collection
cacheConfigs) {
boolean invalid = false;
final StringBuilder error = new StringBuilder();
final ListinvalidCaches = new ArrayList ();
for (CacheConfiguration config : cacheConfigs) {
if (config.isTerracottaClustered()) {
if (config.getTerracottaConfiguration().getStorageStrategy().equals(StorageStrategy.CLASSIC)) {
if (config.getTerracottaConfiguration().isNonstopEnabled()) {
invalid = true;
error.append("\n").append(
"NONSTOP can't be enabled with " + StorageStrategy.CLASSIC.name() + " strategy. Invalid Cache: "
+ config.getName());
}if (isTerracottaRejoinEnabled()) { invalid = true; error.append("\n").append( "REJOIN can't be enabled with " + StorageStrategy.CLASSIC.name() + " strategy. Invalid Cache: " + config.getName()); } if (config.getTerracottaConsistency().equals(Consistency.EVENTUAL)) { invalid = true; error.append("\n").append( Consistency.EVENTUAL.name() + " consistency can't be enabled with " + StorageStrategy.CLASSIC.name() + " strategy. Invalid Cache: " + config.getName()); } } if (isTerracottaRejoinEnabled() && !config.getTerracottaConfiguration().isNonstopEnabled()) { invalid = true; error.append("\n").append( "Terracotta clustered caches must be nonstop when rejoin is enabled. Invalid cache: " + config.getName()); } } } if (invalid) { String errorMessage = "Errors:" + error.toString(); throw new InvalidConfigurationException(errorMessage); }
/**
- Returns unique cluster-wide id for this cache-manager. Only applicable when running in "cluster" mode, e.g. when this cache-manager
- contains caches clustered with Terracotta. Otherwise returns blank string.
- @return Returns unique cluster-wide id for this cache-manager when it contains clustered caches (e.g. Terracotta clustered caches).
-
Otherwise returns blank string.
*/
public String getClusterUUID() {
if (terracottaClient.getClusteredInstanceFactory() != null) {
return getClientUUID(terracottaClient.getClusteredInstanceFactory());
} else {
return "";
}
}private static String getClientUUID(ClusteredInstanceFactory clusteredInstanceFactory) {
return clusteredInstanceFactory.getUUID();
}/**
- Create/access the appropriate terracotta clustered store for the given cache
- @param cache The cache for which the Store should be created
- @return a new (or existing) clustered store
*/
public Store createTerracottaStore(Ehcache cache) {
return getClusteredInstanceFactory(cache).createStore(cache);
}
/**
- Create/access the appropriate clustered write behind queue for the given cache
- @param cache The cache for which the write behind queue should be created
- @return a new (or existing) write behind queue
*/
public WriteBehind createTerracottaWriteBehind(Ehcache cache) {
return getClusteredInstanceFactory(cache).createWriteBehind(cache);
}
/**
- Create/access the appropriate clustered cache event replicator for the given cache
- @param cache The cache for which the clustered event replicator should be created
- @return a new cache event replicator
*/
public CacheEventListener createTerracottaEventReplicator(Ehcache cache) {
return getClusteredInstanceFactory(cache).createEventReplicator(cache);
}
/**
-
Return the clustered instance factory for a cache of this cache manager.
-
@param cache the cache the clustered instance factory has to be returned for
-
@return the clustered instance factory
*/
private ClusteredInstanceFactory getClusteredInstanceFactory(Ehcache cache) {
ClusteredInstanceFactory clusteredInstanceFactory = terracottaClient.getClusteredInstanceFactory();
if (null == clusteredInstanceFactory) {
// adding a cache programmatically when there is no clustered store defined in the configuration
// at the time this cacheManager was created
Mapmap = new HashMap (1);
map.put(cache.getName(), cache.getCacheConfiguration());
final boolean created = terracottaClient.createClusteredInstanceFactory(map);
clusteredInstanceFactory = terracottaClient.getClusteredInstanceFactory();if (created) { try { mbeanRegistrationProvider.reinitialize(clusteredInstanceFactory); } catch (MBeanRegistrationProviderException e) { LOG.warn("Failed to initialize the MBeanRegistrationProvider - " + mbeanRegistrationProvider.getClass().getName(), e); } }
}
return clusteredInstanceFactory;
}
private void checkForUpdateIfNeeded(boolean updateCheckNeeded) {
try {
if (updateCheckNeeded) {
UpdateChecker updateChecker = new UpdateChecker();
cacheManagerTimer.scheduleAtFixedRate(updateChecker, DELAY_UPDATE_CHECK, EVERY_WEEK);
}
} catch (Throwable t) {
LOG.debug("Failed to set up update checker", t);
}
}/**
- 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.
- 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 parsedConfig;
if (configurationFileName != null) {LOG.debug("Configuring CacheManager from {}", configurationFileName); parsedConfig = ConfigurationFactory.parseConfiguration(new File(configurationFileName)); } else if (configurationURL != null) { parsedConfig = ConfigurationFactory.parseConfiguration(configurationURL); } else if (configurationInputStream != null) { parsedConfig = ConfigurationFactory.parseConfiguration(configurationInputStream); } else { LOG.debug("Configuring ehcache from classpath."); parsedConfig = ConfigurationFactory.parseConfiguration(); } return parsedConfig;
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."); } FactoryConfiguration lookupConfiguration = configuration.getTransactionManagerLookupConfiguration(); try { Properties properties = PropertyUtil.parseProperties(lookupConfiguration.getProperties(), lookupConfiguration .getPropertySeparator()); Class
transactionManagerLookupClass = (Class ) Class .forName(lookupConfiguration.getFullyQualifiedClassPath()); this.transactionManagerLookup = transactionManagerLookupClass.newInstance(); this.transactionManagerLookup.setProperties(properties); } catch (Exception e) { LOG.error("could not instantiate transaction manager lookup class: {}", lookupConfiguration.getFullyQualifiedClassPath(), e); } detectAndFixDiskStorePathConflict(configurationHelper); cacheManagerEventListenerRegistry.registerListener(configurationHelper.createCacheManagerEventListener()); cacheManagerPeerListeners.putAll(configurationHelper.createCachePeerListeners()); for (CacheManagerPeerListener cacheManagerPeerListener : cacheManagerPeerListeners.values()) { cacheManagerEventListenerRegistry.registerListener(cacheManagerPeerListener); } detectAndFixCacheManagerPeerListenerConflict(configurationHelper); ALL_CACHE_MANAGERS.add(this); cacheManagerPeerProviders.putAll(configurationHelper.createCachePeerProviders()); defaultCache = configurationHelper.createDefaultCache(); private void detectAndFixDiskStorePathConflict(ConfigurationHelper configurationHelper) {
if (diskStorePath == null) {
LOG.debug("No disk store path defined. Skipping disk store path conflict test.");
return;
}for (CacheManager cacheManager : ALL_CACHE_MANAGERS) { 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 (cacheManagerPeerListeners == null) {
return;
}
for (CacheManagerPeerListener cacheManagerPeerListener : cacheManagerPeerListeners.values()) {
String uniqueResourceIdentifier = cacheManagerPeerListener.getUniqueResourceIdentifier();
for (CacheManager cacheManager : ALL_CACHE_MANAGERS) {
for (CacheManagerPeerListener otherCacheManagerPeerListener : cacheManager.cacheManagerPeerListeners.values()) {
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, true);// add the cache decorators for the cache, if any List
cacheDecorators = configurationHelper.createCacheDecorators(unitialisedCache); for (Ehcache decoratedCache : cacheDecorators) { addOrReplaceDecoratedCache(unitialisedCache, decoratedCache); } } private void addOrReplaceDecoratedCache(final Ehcache underlyingCache, final Ehcache decoratedCache) {
if (decoratedCache.getName().equals(underlyingCache.getName())) {
this.replaceCacheWithDecoratedCache(underlyingCache, decoratedCache);
} else {
addDecoratedCache(decoratedCache);
}
}private void reinitialisationCheck() throws IllegalStateException {
if (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.
- 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 {
if (singleton != null) {
return singleton;
}
synchronized (CacheManager.class) {
if (singleton == null) {
LOG.debug("Creating new CacheManager with default config");
singleton = new CacheManager();
} else {
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.
- This has the same effect as {@link CacheManager#create}
- 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
-
-
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 {
if (singleton != null) {
return singleton;
}
synchronized (CacheManager.class) {
if (singleton == null) {
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.
- 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":
- URL url = this.getClass().getResource("/ehcache-2.xml");
- 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.
- 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
-
-
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 {
if (singleton != null) {
return singleton;
}
synchronized (CacheManager.class) {
if (singleton == null) {
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.
- This method makes it possible to use an inputstream for configuration. Note: it is the clients responsibility to close the
- inputstream.
- @param inputStream
-
InputStream of xml compliant with the ehcache.xsd schema
-
-
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 {
if (singleton != null) {
return singleton;
}
synchronized (CacheManager.class) {
if (singleton == null) {
LOG.debug("Creating new CacheManager with InputStream");
singleton = new CacheManager(inputStream);
}
return singleton;
}
}/**
- A factory method to create a singleton CacheManager from a net.sf.ehcache.config.Configuration.
- This method makes it possible to use an inputstream for configuration. Note: it is the clients responsibility to close the
- inputstream.
- @param config
*/
public static CacheManager create(Configuration config) throws CacheException {
if (singleton != null) {
return singleton;
}
synchronized (CacheManager.class) {
if (singleton == null) {
LOG.debug("Creating new CacheManager with InputStream");
singleton = new CacheManager(config);
}
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.
- If a decorated ehcache is registered in CacheManager, an undecorated Cache with the same name may also exist.
- Since version ehcache-core-2.1.0, when an {@link Ehcache} decorator is present in the CacheManager, its not necessary that a
- {@link Cache} instance is also present for the same name. Decorators can have different names other than the name of the cache its
- decorating.
- @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 Cache getCache(String name) throws IllegalStateException, ClassCastException {
checkStatus();
return ehcaches.get(name) instanceof Cache ? (Cache) ehcaches.get(name) : null;
}
/**
- Gets an Ehcache
- @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 Ehcache getEhcache(String name) throws IllegalStateException {
checkStatus();
return ehcaches.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 {} is set to true.", ENABLE_SHUTDOWN_HOOK_PROPERTY);Thread localShutdownHook = new Thread() { @Override 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; 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.
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.
- 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.
- 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 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 clonedDefaultCache = cloneDefaultCache(cacheName); if (clonedDefaultCache == null) { throw new CacheException(NO_DEFAULT_CACHE_ERROR_MSG); } addCache(clonedDefaultCache); for (Ehcache ehcache : createDefaultCacheDecorators(clonedDefaultCache)) { addOrReplaceDecoratedCache(clonedDefaultCache, ehcache); }
/**
- Adds a {@link Cache} to the CacheManager.
- 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 void addCache(Cache cache) throws IllegalStateException, ObjectExistsException, CacheException {
checkStatus();
if (cache == null) {
return;
}
addCache((Ehcache) cache);
}/**
- Adds an {@link Ehcache} to the CacheManager.
- 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 void addCache(Ehcache cache) throws IllegalStateException, ObjectExistsException, CacheException {
checkStatus();
if (cache == null) {
return;
}
addCacheNoCheck(cache, true);
}/**
- Adds a decorated {@link Ehcache} to the CacheManager. This method neither creates the memory/disk store
- nor initializes the cache. It only adds the cache reference to the map of caches held by this
- cacheManager.
- 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 either add it to the cacheManager with a different name or substitute the original cache with the decorated one.
- This method adds the decorated cache assuming it has a different name. If another cache (decorated or not) with the same name already
- exists, it will throw {@link ObjectExistsException}. For replacing existing cache with another decorated cache having same name,
- please use {@link #replaceCacheWithDecoratedCache(Ehcache, Ehcache)}
- Note that any overridden Ehcache methods by the decorator 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 decoratedCache
- @throws ObjectExistsException
-
if another cache with the same name already exists.
*/
public void addDecoratedCache(Ehcache decoratedCache) throws ObjectExistsException {
internalAddDecoratedCache(decoratedCache, true);
}/**
- Same as {@link #addDecoratedCache(Ehcache)} but does not throw exception if another cache with same name already exists.
- @param decoratedCache
- @throws ObjectExistsException
*/
public void addDecoratedCacheIfAbsent(Ehcache decoratedCache) throws ObjectExistsException {
internalAddDecoratedCache(decoratedCache, false);
}
private void internalAddDecoratedCache(final Ehcache decoratedCache, final boolean strict) {
Ehcache old = ehcaches.putIfAbsent(decoratedCache.getName(), decoratedCache);
if (strict && old != null) {
throw new ObjectExistsException("Cache " + decoratedCache.getName() + " already exists in the CacheManager");
}
}private Ehcache addCacheNoCheck(final Ehcache cache, final boolean strict) throws IllegalStateException, ObjectExistsException,
CacheException {if (isTerracottaRejoinEnabled()) { validateCacheConfigs(Collections.singletonList(cache.getCacheConfiguration())); } if (cache.getStatus() != Status.STATUS_UNINITIALISED) { throw new CacheException("Trying to add an already initialized cache." + " If you are adding a decorated cache, " + "use CacheManager.addDecoratedCache" + "(Ehcache decoratedCache) instead."); } Ehcache ehcache = ehcaches.get(cache.getName()); if (ehcache != null) { if (strict) { throw new ObjectExistsException("Cache " + cache.getName() + " already exists"); } else { return ehcache; } } cache.setCacheManager(this); if (cache.getCacheConfiguration().getDiskStorePath() == null) { cache.setDiskStorePath(diskStorePath); } cache.setTransactionManagerLookup(transactionManagerLookup); Map
configMap = configuration.getCacheConfigurations(); if (!configMap.containsKey(cache.getName())) { CacheConfiguration cacheConfig = cache.getCacheConfiguration(); if (cacheConfig != null) { configuration.addCache(cacheConfig); } } if (isTerracottaRejoinEnabled() && cache.getCacheConfiguration().isTerracottaClustered()) { final long timeoutMillis = cache.getCacheConfiguration().getTerracottaConfiguration().getNonstopConfiguration() .getTimeoutMillis(); try { getNonstopExecutorService().execute(new Callable () { public Void call() throws Exception { cache.initialise(); return null; } }, timeoutMillis); } catch (TimeoutException e) { throw new NonStopCacheException("Unable to add cache [" + cache.getCacheConfiguration().getName() + "] within " + timeoutMillis + " msecs", e); } catch (InterruptedException e) { throw new CacheException(e); } } else { cache.initialise(); } if (!allowsDynamicCacheConfig) { cache.disableDynamicFeatures(); } try { cache.bootstrap(); } catch (CacheException e) { LOG.warn("Cache " + cache.getName() + "requested bootstrap but a CacheException occured. " + e.getMessage(), e); } ehcache = ehcaches.putIfAbsent(cache.getName(), cache); if (ehcache != null) { if (strict) { throw new ObjectExistsException("Cache " + cache.getName() + " already exists"); } else { return ehcache; } } // 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()); } return cache; /**
- Checks whether a cache of type ehcache exists.
- @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 boolean cacheExists(String cacheName) throws IllegalStateException {
checkStatus();
return (ehcaches.get(cacheName) != null);
}/**
- Removes all caches using {@link #removeCache} for each cache.
*/
public void removalAll() {
String[] cacheNames = getCacheNames();
for (String cacheName : cacheNames) {
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 void removeCache(String cacheName) throws IllegalStateException {
checkStatus();// NPE guard if (cacheName == null || cacheName.length() == 0) { return; } Ehcache cache = ehcaches.remove(cacheName); if (cache != null && cache.getStatus().equals(Status.STATUS_ALIVE)) { cache.dispose(); configuration.getCacheConfigurations().remove(cacheName); cacheManagerEventListenerRegistry.notifyCacheRemoved(cache.getName()); }
/**
-
Shuts down the CacheManager.
-
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.
-
By default there is no shutdown hook (ehcache-1.3-beta2 and higher).
-
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)) {
LOG.debug("CacheManager already shutdown");
return;
}
for (CacheManagerPeerProvider cacheManagerPeerProvider : cacheManagerPeerProviders.values()) {
if (cacheManagerPeerProvider != null) {
cacheManagerPeerProvider.dispose();
}
}// cancel the cacheManager timer and all tasks if (cacheManagerTimer != null) { cacheManagerTimer.cancel(); cacheManagerTimer.purge(); } cacheManagerEventListenerRegistry.dispose(); synchronized (CacheManager.class) { ALL_CACHE_MANAGERS.remove(this); for (Ehcache cache : ehcaches.values()) { if (cache != null) { cache.dispose(); } } if (defaultCache != null) { defaultCache.dispose(); } status = Status.STATUS_SHUTDOWN; XARequestProcessor.shutdown(); // only delete singleton if the singleton is shutting down. if (this == singleton) { singleton = null; } terracottaClient.shutdown(); transactionController = null; removeShutdownHook(); nonstopExecutorServiceFactory.shutdown(this); }
}
}
/**
- 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 String[] getCacheNames() throws IllegalStateException {
checkStatus();
String[] list = new String[ehcaches.size()];
return ehcaches.keySet().toArray(list);
}/**
- Checks the state of the CacheManager for legal operation
*/
protected void checkStatus() {
if (!(status.equals(Status.STATUS_ALIVE))) {
if (status.equals(Status.STATUS_UNINITIALISED)) {
throw new IllegalStateException("The CacheManager has not yet been initialised. It cannot be used yet.");
} else if (status.equals(Status.STATUS_SHUTDOWN)) {
throw new IllegalStateException("The CacheManager has been shut down. It can no longer be used.");
}
}
}
/**
- 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.
-
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();LOG.debug("Clearing all caches");
for (String cacheName : cacheNames) {
Ehcache cache = getEhcache(cacheName);
cache.removeAll();
}
}
/**
-
Clears the contents of all caches in the CacheManager with a name starting with the prefix,
-
but without removing them.
-
This method is not synchronized. It only guarantees to clear those elements in a cache at the time that the
-
{@link Ehcache#removeAll()} method on each cache is called.
-
@param prefix
-
The prefix the cache name should start with
-
@throws CacheException
-
@since 1.7.2
*/
public void clearAllStartingWith(String prefix) throws CacheException {
// NPE guard
if (prefix == null || prefix.length() == 0) {
return;
}for (Object o : ehcaches.entrySet()) {
Map.Entry entry = (Map.Entry) o;
String cacheName = (String) entry.getKey();
if (cacheName.startsWith(prefix)) {
if (LOG.isDebugEnabled()) {
LOG.debug("Clearing cache named '" + cacheName + "' (matches '" + prefix + "' prefix");
}
((Ehcache) entry.getValue()).removeAll();
}
}
}
/**
- Gets the
CacheManagerPeerProvider
, matching the given scheme - For distributed caches, the peer provider finds other cache managers and their caches in the same cluster
- @param scheme
-
the replication scheme to use. Schemes shipped with ehcache are RMI, JGROUPS, JMS
- @return the provider, or null if one does not exist
*/
public CacheManagerPeerProvider getCacheManagerPeerProvider(String scheme) {
return cacheManagerPeerProviders.get(scheme);
}
/**
- @return Read-only map of the registered {@link CacheManagerPeerProvider}s keyed by scheme.
*/
public MapgetCacheManagerPeerProviders() {
return Collections.unmodifiableMap(this.cacheManagerPeerProviders);
}
/**
- When CacheManage is configured as part of a cluster, a CacheManagerPeerListener will
- be registered in it. Use this to access the individual cache listeners
- @param scheme
-
the replication scheme to use. Schemes shipped with ehcache are RMI, JGROUPS, JMS
- @return the listener, or null if one does not exist
*/
public CacheManagerPeerListener getCachePeerListener(String scheme) {
return cacheManagerPeerListeners.get(scheme);
}
/**
- 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"
*/
public void setCacheManagerEventListener(CacheManagerEventListener cacheManagerEventListener) {
getCacheManagerEventListenerRegistry().registerListener(cacheManagerEventListener);
}
/**
- Gets the CacheManagerEventListenerRegistry. Add and remove listeners here.
*/
public CacheManagerEventListenerRegistry getCacheManagerEventListenerRegistry() {
return cacheManagerEventListenerRegistry;
}
/**
- 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.
- Ehcache Decorators can be used to obtain different behaviour from an Ehcache in a very flexible way. Some examples in ehcache are:
-
- {@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.
- {@link net.sf.ehcache.constructs.blocking.SelfPopulatingCache} - A BlockingCache that has the additional property of knowing how
- to load its own entries.
- Many other kinds are possible.
- 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.
- 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 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.");
}String cacheName = ehcache.getName(); if (!ehcaches.replace(cacheName, ehcache, decoratedCache)) { if (cacheExists(cacheName)) { throw new CacheException("Cache '" + ehcache.getName() + "' managed with this CacheManager doesn't match!"); } else { throw new CacheException("Cache '" + cacheName + "' isn't associated with this manager (anymore?)"); } }
/**
- 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();
}
}
/**
- Indicate whether the CacheManager is named or not.
- @return True if named
*/
public boolean isNamed() {
return name != null;
}
/**
- 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;
try {
mbeanRegistrationProvider.reinitialize(terracottaClient.getClusteredInstanceFactory());
} catch (MBeanRegistrationProviderException e) {
throw new CacheException("Problem in reinitializing MBeanRegistrationProvider - "
+ mbeanRegistrationProvider.getClass().getName(), e);
}
}/**
- @return either the name of this CacheManager, or if unset, Object.toString()
*/
@Override
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;
}
/**
- Returns a {@link FailSafeTimer} associated with this {@link CacheManager}
- @return The {@link FailSafeTimer} associated with this cache manager
- @since 1.7
*/
public FailSafeTimer getTimer() {
return cacheManagerTimer;
}
/**
- Returns access to information about the cache cluster.
- @param scheme The clustering scheme to retrieve information about (such as "Terracotta")
- @return Cluster API (never null, but possibly a simple single node implementation)
- @throws ClusterSchemeNotAvailableException If the CacheCluster specified by scheme is not available.
- @see ClusterScheme
- @since 2.0
*/
public CacheCluster getCluster(ClusterScheme scheme) throws ClusterSchemeNotAvailableException {
switch (scheme) {
case TERRACOTTA:
if (null == terracottaClient.getClusteredInstanceFactory()) {
throw new ClusterSchemeNotAvailableException(ClusterScheme.TERRACOTTA, "Terracotta cluster scheme is not available");
}
return terracottaClient.getCacheCluster();
default:
return NoopCacheCluster.INSTANCE;
}
}
/**
- Returns the original configuration text for this {@link CacheManager}
- @return Returns the original configuration text for this {@link CacheManager}
*/
public String getOriginalConfigurationText() {
if (configuration.getConfigurationSource() == null) {
return "Originally configured programmatically. No original configuration source text.";
} else {
Configuration originalConfiguration = configuration.getConfigurationSource().createConfiguration();
return ConfigurationUtil.generateCacheManagerConfigurationText(originalConfiguration);
}
}
/**
- Returns the active configuration text for this {@link CacheManager}
- @return Returns the active configuration text for this {@link CacheManager}
*/
public String getActiveConfigurationText() {
return ConfigurationUtil.generateCacheManagerConfigurationText(configuration);
}
/**
- Returns the original configuration text for the input cacheName
- @param cacheName
- @return Returns the original configuration text for the input cacheName
- @throws CacheException if the cache with
cacheName
does not exist in the original config
*/
public String getOriginalConfigurationText(String cacheName) throws CacheException {
if (configuration.getConfigurationSource() == null) {
return "Originally configured programmatically. No original configuration source text.";
} else {
Configuration originalConfiguration = configuration.getConfigurationSource().createConfiguration();
CacheConfiguration cacheConfiguration = originalConfiguration.getCacheConfigurations().get(cacheName);
if (cacheConfiguration == null) {
throw new CacheException("Cache with name '" + cacheName + "' does not exist in the original configuration");
}
return ConfigurationUtil.generateCacheConfigurationText(cacheConfiguration);
}
}
/**
- Returns the active configuration text for the input cacheName
- @param cacheName
- @return Returns the active configuration text for the input cacheName
- @throws CacheException if the cache with
cacheName
does not exist
*/
public String getActiveConfigurationText(String cacheName) throws CacheException {
CacheConfiguration config = configuration.getCacheConfigurations().get(cacheName);
if (config == null) {
throw new CacheException("Cache with name '" + cacheName + "' does not exist");
}
return ConfigurationUtil.generateCacheConfigurationText(config);
}
/**
- Get the CacheManager configuration
- @return the configuration
*/
Configuration getConfiguration() {
return configuration;
}
/**
- {@inheritDoc}
*/
@Override
public int hashCode() {
if (name != null) {
return name.hashCode();
} else {
return super.hashCode();
}
}
/**
- Only adds the cache to the CacheManager should not one with the same name already be present
- @param cache The Ehcache to be added
- @return the instance registered with the CacheManager, the cache instance passed in if it was added; or null if Ehcache is null
*/
public Ehcache addCacheIfAbsent(final Ehcache cache) {
checkStatus();
return cache == null ? null : addCacheNoCheck(cache, false);
}
/**
-
Only creates and adds the cache to the CacheManager should not one with the same name already be present
-
@param cacheName the name of the Cache to be created
-
@return the Ehcache instance created and registered; null if cacheName was null or of length 0
*/
public Ehcache addCacheIfAbsent(final String cacheName) {
checkStatus();// NPE guard
if (cacheName == null || cacheName.length() == 0) {
return null;
}Ehcache ehcache = ehcaches.get(cacheName);
if (ehcache == null) {
Ehcache clonedDefaultCache = cloneDefaultCache(cacheName);
if (clonedDefaultCache == null) {
throw new CacheException(NO_DEFAULT_CACHE_ERROR_MSG);
}
addCacheIfAbsent(clonedDefaultCache);
for (Ehcache createdCache : createDefaultCacheDecorators(clonedDefaultCache)) {
addOrReplaceDecoratedCache(clonedDefaultCache, createdCache);
}
}
return ehcaches.get(cacheName);
}
private Ehcache cloneDefaultCache(final String cacheName) {
if (defaultCache == null) {
return null;
}
Ehcache cache;
try {
cache = (Ehcache) defaultCache.clone();
} catch (CloneNotSupportedException e) {
throw new CacheException("Failure cloning default cache. Initial cause was " + e.getMessage(), e);
}
if (cache != null) {
cache.setName(cacheName);
}
return cache;
}private List
createDefaultCacheDecorators(Ehcache underlyingCache) {
return ConfigurationHelper.createDefaultCacheDecorators(underlyingCache, configuration.getDefaultCacheConfiguration());
}/**
- Get the TransactionController
- @return the TransactionController
*/
public TransactionController getTransactionController() {
return transactionController;
}
/**
- Create a TransactionIDFactory
- @return a TransactionIDFactory
*/
TransactionIDFactory createTransactionIDFactory() {
TransactionIDFactory transactionIDFactory;
if (terracottaClient.getClusteredInstanceFactory() != null) {
transactionIDFactory = terracottaClient.getClusteredInstanceFactory().createTransactionIDFactory(getClusterUUID());
} else {
transactionIDFactory = new TransactionIDFactoryImpl();
}
return transactionIDFactory;
}
/**
- Create a soft lock factory for a specific cache
- @param cache the cache to create the soft lock factory for
- @return a SoftLockFactory
*/
SoftLockFactory createSoftLockFactory(Ehcache cache) {
SoftLockFactory softLockFactory;
if (cache.getCacheConfiguration().isTerracottaClustered()) {
softLockFactory = getClusteredInstanceFactory(cache).getOrCreateSoftLockFactory(cache.getName());
} else {
softLockFactory = softLockFactories.get(cache.getName());
if (softLockFactory == null) {
softLockFactory = new ReadCommittedSoftLockFactoryImpl(cache.getName());
SoftLockFactory old = softLockFactories.putIfAbsent(cache.getName(), softLockFactory);
if (old != null) {
softLockFactory = old;
}
}
}
return softLockFactory;
}
private void clusterRejoinStarted() {
for (Ehcache cache : ehcaches.values()) {
if (cache instanceof Cache) {
if (cache.getCacheConfiguration().isTerracottaClustered()) {
((Cache) cache).clusterRejoinStarted();
}
}
}
// shutdown the current nonstop executor service
nonstopExecutorServiceFactory.shutdown(this);
}/**
- This method is called when the Terracotta Cluster is rejoined. Reinitializes all terracotta clustered caches in this cache manager
*/
private void clusterRejoinComplete() {
// restart nonstop executor service
nonstopExecutorServiceFactory.getOrCreateNonstopExecutorService(this);
for (Ehcache cache : ehcaches.values()) {
if (cache instanceof Cache) {
if (cache.getCacheConfiguration().isTerracottaClustered()) {
((Cache) cache).clusterRejoinComplete();
}
}
}
if (mbeanRegistrationProvider.isInitialized()) {
// re-register mbeans
try {
mbeanRegistrationProvider.reinitialize(terracottaClient.getClusteredInstanceFactory());
} catch (MBeanRegistrationProviderException e) {
throw new CacheException("Problem in reinitializing MBeanRegistrationProvider - "
+ mbeanRegistrationProvider.getClass().getName(), e);
}
}
// recreate TransactionController with fresh TransactionIDFactory
transactionController = new TransactionController(createTransactionIDFactory(), configuration
.getDefaultTransactionTimeoutInSeconds());
}
/**
- Return the {@link NonstopExecutorService} associated with this cacheManager
- @return the {@link NonstopExecutorService} associated with this cacheManager
*/
protected NonstopExecutorService getNonstopExecutorService() {
return nonstopExecutorServiceFactory.getOrCreateNonstopExecutorService(this);
}
}
- Default name if not specified in the configuration/