net.sf.ehcache.config.Configuration Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of ehcache Show documentation
Show all versions of ehcache Show documentation
Ehcache is an open source, standards-based cache used to boost performance,
offload the database and simplify scalability. Ehcache is robust, proven and full-featured and
this has made it the most widely-used Java-based cache.
/**
* Copyright 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.config;
import net.sf.ehcache.Cache;
import net.sf.ehcache.CacheException;
import net.sf.ehcache.CacheManager;
import net.sf.ehcache.EhcacheDefaultClassLoader;
import net.sf.ehcache.FeaturesManager;
import net.sf.ehcache.ObjectExistsException;
import net.sf.ehcache.Status;
import net.sf.ehcache.config.generator.ConfigurationSource;
import net.sf.ehcache.store.Store;
import net.sf.ehcache.transaction.manager.DefaultTransactionManagerLookup;
import net.sf.ehcache.transaction.manager.TransactionManagerLookup;
import net.sf.ehcache.util.PropertyUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
/**
* A bean, used by BeanUtils, to set configuration from an XML configuration file.
*
* @author Greg Luck
* @version $Id: Configuration.java 10376 2016-06-15 10:30:07Z rism $
*/
public final class Configuration {
/**
* Default value for dynamicConfig
*/
public static final boolean DEFAULT_DYNAMIC_CONFIG = true;
/**
* Default value for defaultTransactionTimeoutInSeconds
*/
public static final int DEFAULT_TRANSACTION_TIMEOUT = 15;
/**
* Default value for maxBytesLocalHeap when not explicitly set
*/
public static final long DEFAULT_MAX_BYTES_ON_HEAP = 0;
/**
* Default value for maxBytesLocalOffHeap when not explicitly set
*/
public static final long DEFAULT_MAX_BYTES_OFF_HEAP = 0;
/**
* Default value for maxBytesLocalDisk when not explicitly set
*/
public static final long DEFAULT_MAX_BYTES_ON_DISK = 0;
/**
* Default value for monitoring
*/
public static final Monitoring DEFAULT_MONITORING = Monitoring.AUTODETECT;
/**
* Default sizeOfPolicy configuration
*/
public static final SizeOfPolicyConfiguration DEFAULT_SIZEOF_POLICY_CONFIGURATION = new SizeOfPolicyConfiguration();
/**
* Default transactionManagerLookupConfiguration
*/
public static final FactoryConfiguration DEFAULT_TRANSACTION_MANAGER_LOOKUP_CONFIG = getDefaultTransactionManagerLookupConfiguration();
private static final int HUNDRED = 100;
private static final Logger LOG = LoggerFactory.getLogger(Configuration.class);
private volatile RuntimeCfg cfg;
private final List propertyChangeListeners = new CopyOnWriteArrayList();
/**
* Represents whether monitoring should be enabled or not.
*
* @author amiller
*/
public enum Monitoring {
/** When possible, notice the use of Terracotta and auto register the SampledCacheMBean. */
AUTODETECT,
/** Always auto register the SampledCacheMBean */
ON,
/** Never auto register the SampledCacheMBean */
OFF;
}
/**
* Enum of all properties that can change once the Configuration is being used by a CacheManager
*/
private static enum DynamicProperty {
defaultCacheConfiguration {
@Override
void applyChange(final PropertyChangeEvent evt, final RuntimeCfg config) {
LOG.debug("Default Cache Configuration has changed, previously created caches remain untouched");
}
},
maxBytesLocalHeap {
@Override
void applyChange(final PropertyChangeEvent evt, final RuntimeCfg config) {
Long newValue = (Long)evt.getNewValue();
Long oldValue = (Long) evt.getOldValue();
if (oldValue > newValue) {
// Double check for over-allocation again
validateOverAllocation(config, newValue);
}
// Recalculate % based caches
long cacheAllocated = 0;
for (Cache cache : getAllActiveCaches(config.cacheManager)) {
cache.getCacheConfiguration().configCachePools(config.getConfiguration());
long bytesLocalHeap = cache.getCacheConfiguration().getMaxBytesLocalHeap();
cacheAllocated += bytesLocalHeap;
}
config.cacheManager.getOnHeapPool().setMaxSize(newValue - cacheAllocated);
}
},
maxBytesLocalDisk {
@Override
void applyChange(final PropertyChangeEvent evt, final RuntimeCfg config) {
Long newValue = (Long) evt.getNewValue();
Long oldValue = (Long) evt.getOldValue();
if (oldValue > newValue) {
// Double check for over-allocation again
validateOverAllocation(config, newValue);
}
long diskAllocated = 0;
//Recalculating final free space available at global level
for (Cache cache : getAllActiveCaches(config.cacheManager)) {
cache.getCacheConfiguration().configCachePools(config.getConfiguration());
long bytesOnDiskPool = cache.getCacheConfiguration().getMaxBytesLocalDisk();
diskAllocated += bytesOnDiskPool;
}
config.cacheManager.getOnDiskPool().setMaxSize(newValue - diskAllocated);
}
};
private static void validateOverAllocation(RuntimeCfg config, Long newValue) {
ArrayList errors = new ArrayList();
for (Cache cache : getAllActiveCaches(config.cacheManager)) {
CacheConfiguration cacheConfiguration = cache.getCacheConfiguration();
errors.addAll(cacheConfiguration.validateCachePools(config.getConfiguration()));
errors.addAll(cacheConfiguration.verifyPoolAllocationsBeforeAddingTo(config.cacheManager,
newValue, config.getConfiguration().getMaxBytesLocalOffHeap(),
config.getConfiguration().getMaxBytesLocalDisk(), null));
}
if (!errors.isEmpty()) {
throw new InvalidConfigurationException("Can't reduce CacheManager byte tuning by so much", errors);
}
}
abstract void applyChange(PropertyChangeEvent evt, RuntimeCfg config);
}
private String cacheManagerName;
private int defaultTransactionTimeoutInSeconds = DEFAULT_TRANSACTION_TIMEOUT;
private Monitoring monitoring = DEFAULT_MONITORING;
private DiskStoreConfiguration diskStoreConfiguration;
private CacheConfiguration defaultCacheConfiguration;
private final List cacheManagerPeerProviderFactoryConfiguration = new ArrayList();
private final List cacheManagerPeerListenerFactoryConfiguration = new ArrayList();
private SizeOfPolicyConfiguration sizeOfPolicyConfiguration;
private FactoryConfiguration transactionManagerLookupConfiguration;
private FactoryConfiguration cacheManagerEventListenerFactoryConfiguration;
private TerracottaClientConfiguration terracottaConfigConfiguration;
private ManagementRESTServiceConfiguration managementRESTService;
private final Map cacheConfigurations = new ConcurrentHashMap();
private ConfigurationSource configurationSource;
private boolean dynamicConfig = DEFAULT_DYNAMIC_CONFIG;
private Long maxBytesLocalHeap;
private String maxBytesLocalHeapInput;
private Long maxBytesLocalOffHeap;
private String maxBytesLocalOffHeapInput;
private Long maxBytesLocalDisk;
private String maxBytesLocalDiskInput;
private volatile ClassLoader classLoader = EhcacheDefaultClassLoader.getInstance();
/**
* Empty constructor, which is used by {@link ConfigurationFactory}, and can be also used programmatically.
*
* If you are using it programmtically you need to call the relevant add and setter methods in this class to populate everything.
*/
public Configuration() {
}
/**
* Returns all active caches managed by the Manager
* @param cacheManager The cacheManager
* @return the Set of all active caches
*/
static Set getAllActiveCaches(CacheManager cacheManager) {
final Set caches = new HashSet();
for (String cacheName : cacheManager.getCacheNames()) {
final Cache cache = cacheManager.getCache(cacheName);
if (cache != null) {
caches.add(cache);
}
}
return caches;
}
/**
* Freezes part of the configuration that need to be, and runs validation checks on the Configuration.
*
* @param cacheManager the CacheManager instance being configured
* @throws InvalidConfigurationException With all the associated errors
*/
public RuntimeCfg setupFor(final CacheManager cacheManager, final String fallbackName) throws InvalidConfigurationException {
if (cfg != null) {
if (cfg.cacheManager == cacheManager) {
return cfg;
} else if (cfg.cacheManager.getStatus() != Status.STATUS_SHUTDOWN) {
throw new IllegalStateException("You cannot share a Configuration instance across multiple running CacheManager instances");
}
}
final Collection errors = validate();
if (!errors.isEmpty()) {
throw new InvalidConfigurationException(errors);
}
cfg = new Configuration.RuntimeCfg(cacheManager, fallbackName);
return cfg;
}
/**
* Validates the current configuration
* @return the list of errors withing that configuration
*/
public Collection validate() {
final Collection errors = new ArrayList();
for (CacheConfiguration cacheConfiguration : cacheConfigurations.values()) {
errors.addAll(cacheConfiguration.validate(this));
}
return errors;
}
/**
* Checks whether the user explicitly set the maxBytesOnDisk
* @return true if set by user, false otherwise
* @see #setMaxBytesLocalDisk(Long)
*/
public boolean isMaxBytesLocalDiskSet() {
return maxBytesLocalDisk != null;
}
/**
* Checks whether the user explicitly set the maxBytesOffHeat
* @return true if set by user, false otherwise
* @see #setMaxBytesLocalOffHeap(Long)
*/
public boolean isMaxBytesLocalOffHeapSet() {
return maxBytesLocalOffHeap != null;
}
/**
* Checks whether the user explicitly set the maxBytesOnHeap
* @return true if set by user, false otherwise
* @see #setMaxBytesLocalHeap(Long)
*/
public boolean isMaxBytesLocalHeapSet() {
return maxBytesLocalHeap != null;
}
private static FactoryConfiguration getDefaultTransactionManagerLookupConfiguration() {
FactoryConfiguration configuration = new FactoryConfiguration();
configuration.setClass(DefaultTransactionManagerLookup.class.getName());
return configuration;
}
/**
* Builder to set the cache manager name.
*
* Cache manager names have constraints on the characters they can use:
*
* - cache managers that are registered as MBeans must obey the {@link javax.management.ObjectName} rules for unquoted value.
* This means the following characters are illegal: ',', '=', ':', '"', '*' and '?'.
*
* Note that a clustered cache manager is by default registered as MBean.
*
* @see #setName(String)
* @param name
* the name to set
* @return this configuration instance
*/
public final Configuration name(String name) {
setName(name);
return this;
}
/**
* Allows BeanHandler to set the CacheManager name.
*
* Cache manager names have constraints on the characters they can use:
*
* - cache managers that are registered as MBeans must obey the {@link javax.management.ObjectName} rules for unquoted value.
* This means the following characters are illegal: ',', '=', ':', '"', '*' and '?'.
*
* Note that a clustered cache manager is by default registered as MBean.
*/
public final void setName(String name) {
assertArgumentNotNull("name", name);
final String prop = "cacheManagerName";
final boolean publishChange = checkDynChange(prop);
String oldValue = this.cacheManagerName;
this.cacheManagerName = name;
if (publishChange) {
firePropertyChange(prop, oldValue, name);
}
}
private void assertArgumentNotNull(String name, Object object) {
if (object == null) {
throw new IllegalArgumentException(name + " cannot be null");
}
}
/**
* CacheManager name
*/
public final String getName() {
return this.cacheManagerName;
}
/**
* Builder to set the state of the automated update check.
*
* @param updateCheck
* {@code true} if the update check should be turned on; or {@code false} otherwise
* @return this configuration instance
*/
@Deprecated
public final Configuration updateCheck(boolean updateCheck) {
return this;
}
/**
* Allows BeanHandler to set the updateCheck flag.
*/
@Deprecated
public final void setUpdateCheck(boolean updateCheck) {
// no-op
}
/**
* Get flag for updateCheck
*/
@Deprecated
public final boolean getUpdateCheck() {
return false;
}
/**
* Builder to set the default transaction timeout.
*
* @param defaultTransactionTimeoutInSeconds the default transaction timeout in seconds
* @return this configuration instance
*/
public final Configuration defaultTransactionTimeoutInSeconds(int defaultTransactionTimeoutInSeconds) {
setDefaultTransactionTimeoutInSeconds(defaultTransactionTimeoutInSeconds);
return this;
}
/**
* Allows BeanHandler to set the default transaction timeout.
*/
public final void setDefaultTransactionTimeoutInSeconds(int defaultTransactionTimeoutInSeconds) {
final String prop = "defaultTransactionTimeoutInSeconds";
final boolean publish = checkDynChange(prop);
final int oldValue = this.defaultTransactionTimeoutInSeconds;
this.defaultTransactionTimeoutInSeconds = defaultTransactionTimeoutInSeconds;
if (publish) {
firePropertyChange(prop, oldValue, defaultTransactionTimeoutInSeconds);
}
}
/**
* Get default transaction timeout
* @return default transaction timeout in seconds
*/
public final int getDefaultTransactionTimeoutInSeconds() {
return defaultTransactionTimeoutInSeconds;
}
/**
* Builder to set the monitoring approach
*
* @param monitoring
* an non-null instance of {@link Monitoring}
* @return this configuration instance
*/
public final Configuration monitoring(Monitoring monitoring) {
if (null == monitoring) {
throw new IllegalArgumentException("Monitoring value must be non-null");
}
final String prop = "monitoring";
final boolean publish = checkDynChange(prop);
final Monitoring oldValue = this.monitoring;
this.monitoring = monitoring;
if (publish) {
firePropertyChange(prop, oldValue, monitoring);
}
return this;
}
/**
* Allows BeanHandler to set the monitoring flag
*/
public final void setMonitoring(String monitoring) {
assertArgumentNotNull("Monitoring", monitoring);
monitoring(Monitoring.valueOf(Monitoring.class, monitoring.toUpperCase()));
}
/**
* Get monitoring type, should not be null
*/
public final Monitoring getMonitoring() {
return this.monitoring;
}
/**
* Builder to set the dynamic config capability
*
* @param dynamicConfig
* {@code true} if dynamic config should be enabled; or {@code false} otherwise.
* @return this configuration instance
*/
public final Configuration dynamicConfig(boolean dynamicConfig) {
setDynamicConfig(dynamicConfig);
return this;
}
/**
* Allows BeanHandler to set the dynamic configuration flag
*/
public final void setDynamicConfig(boolean dynamicConfig) {
final String prop = "dynamicConfig";
final boolean publish = checkDynChange(prop);
final boolean oldValue = this.dynamicConfig;
this.dynamicConfig = dynamicConfig;
if (publish) {
firePropertyChange(prop, oldValue, dynamicConfig);
}
}
/**
* Get flag for dynamicConfig
*/
public final boolean getDynamicConfig() {
return this.dynamicConfig;
}
/**
* Maximum amount of bytes the CacheManager will use on the heap
* @return amount of bytes, 0 is unbound
*/
public long getMaxBytesLocalHeap() {
return maxBytesLocalHeap == null ? DEFAULT_MAX_BYTES_ON_HEAP : maxBytesLocalHeap;
}
/**
* Sets maximum amount of bytes the CacheManager will use on the Disk Tier.
* @param maxBytesOnHeap String representation of the size.
* @see MemoryUnit#parseSizeInBytes(String)
*/
public void setMaxBytesLocalHeap(final String maxBytesOnHeap) {
assertArgumentNotNull("MaxBytesLocalHeap", maxBytesOnHeap);
final String origInput = maxBytesLocalHeapInput;
try {
maxBytesLocalHeapInput = maxBytesOnHeap;
if (isPercentage(maxBytesOnHeap)) {
long maxMemory = Runtime.getRuntime().maxMemory();
long mem = maxMemory / HUNDRED * parsePercentage(maxBytesOnHeap);
setMaxBytesLocalHeap(mem);
} else {
setMaxBytesLocalHeap(MemoryUnit.parseSizeInBytes(maxBytesOnHeap));
}
} catch (RuntimeException rte) {
maxBytesLocalHeapInput = origInput;
throw rte;
}
}
/**
* @return Original input for maxBytesLocalHeap
*/
public String getMaxBytesLocalHeapAsString() {
return maxBytesLocalHeapInput != null ? maxBytesLocalHeapInput : Long.toString(getMaxBytesLocalHeap());
}
private int parsePercentage(final String stringValue) {
String trimmed = stringValue.trim();
int percentage = Integer.parseInt(trimmed.substring(0, trimmed.length() - 1));
if (percentage > HUNDRED || percentage < 0) {
throw new IllegalArgumentException("Percentage need values need to be between 0 and 100 inclusive, but got : " + percentage);
}
return percentage;
}
private boolean isPercentage(final String stringValue) {
String trimmed = stringValue.trim();
return trimmed.charAt(trimmed.length() - 1) == '%';
}
/**
* Sets the maximum amount of bytes the cache manager being configured will use on the OnHeap tier
* @param maxBytesOnHeap amount of bytes
*/
public void setMaxBytesLocalHeap(final Long maxBytesOnHeap) {
final String prop = "maxBytesLocalHeap";
verifyGreaterThanZero(maxBytesOnHeap, prop);
final boolean publish = checkDynChange(prop);
Long oldValue = this.maxBytesLocalHeap;
this.maxBytesLocalHeap = maxBytesOnHeap;
if (publish) {
firePropertyChange(prop, oldValue, maxBytesOnHeap);
}
}
/**
* Sets the maxOnHeap size for the cache being configured
* @param amount the amount of unit
* @param memoryUnit the actual unit
* @return this
* @see #setMaxBytesLocalHeap(Long)
*/
public Configuration maxBytesLocalHeap(final long amount, final MemoryUnit memoryUnit) {
setMaxBytesLocalHeap(memoryUnit.toBytes(amount));
return this;
}
/**
* Maximum amount of bytes the CacheManager will use on the OffHeap Tier.
* @return amount in bytes
*/
public long getMaxBytesLocalOffHeap() {
return maxBytesLocalOffHeap == null ? DEFAULT_MAX_BYTES_OFF_HEAP : maxBytesLocalOffHeap;
}
/**
* Sets maximum amount of bytes the CacheManager will use on the OffHeap Tier.
* @param maxBytesOffHeap String representation of the size.
* @see MemoryUnit#parseSizeInBytes(String)
*/
public void setMaxBytesLocalOffHeap(final String maxBytesOffHeap) {
assertArgumentNotNull("MaxBytesLocalOffHeap", maxBytesOffHeap);
final String origInput = maxBytesLocalOffHeapInput;
try {
maxBytesLocalOffHeapInput = maxBytesOffHeap;
if (isPercentage(maxBytesOffHeap)) {
long maxMemory = getOffHeapLimit();
long mem = maxMemory / HUNDRED * parsePercentage(maxBytesOffHeap);
setMaxBytesLocalOffHeap(mem);
} else {
setMaxBytesLocalOffHeap(MemoryUnit.parseSizeInBytes(maxBytesOffHeap));
}
} catch (RuntimeException rte) {
maxBytesLocalOffHeapInput = origInput;
throw rte;
}
}
/**
* @return Original input for maxBytesLocalOffHeap
*/
public String getMaxBytesLocalOffHeapAsString() {
return maxBytesLocalOffHeapInput != null ? maxBytesLocalOffHeapInput : Long.toString(getMaxBytesLocalOffHeap());
}
/**
* @return Total amount offheap configured by current caches
*/
public long getTotalConfiguredOffheap() {
long total = getMaxBytesLocalOffHeap();
for (String cacheName : getCacheConfigurationsKeySet()) {
CacheConfiguration config = getCacheConfigurations().get(cacheName);
total += config.getMaxBytesLocalOffHeap();
}
return total;
}
private long getOffHeapLimit() {
try {
Class enterpriseFmClass = (Class) Class.forName(FeaturesManager.ENTERPRISE_FM_CLASSNAME);
try {
return (Long)enterpriseFmClass.getMethod("getMaxBytesAllocatable").invoke(null);
} catch (NoSuchMethodException e) {
throw new CacheException("Cache: " + getName() + " cannot find static factory"
+ " method create(Ehcache, String)" + " in store class " + FeaturesManager.ENTERPRISE_FM_CLASSNAME, e);
} catch (InvocationTargetException e) {
Throwable cause = e.getCause();
throw new CacheException("Cache: " + getName() + " cannot instantiate store "
+ FeaturesManager.ENTERPRISE_FM_CLASSNAME, cause);
} catch (IllegalAccessException e) {
throw new CacheException("Cache: " + getName() + " cannot instantiate store "
+ FeaturesManager.ENTERPRISE_FM_CLASSNAME, e);
}
} catch (ClassNotFoundException e) {
throw new CacheException("Cache " + getName()
+ " cannot be configured because the off-heap store class could not be found. "
+ "You must use an enterprise version of Ehcache to successfully enable overflowToOffHeap.");
}
}
/**
* Sets maximum amount of bytes the CacheManager will use on the OffHeap Tier.
* @param maxBytesOffHeap max bytes on disk in bytes. Needs be be greater than 0
*/
public void setMaxBytesLocalOffHeap(final Long maxBytesOffHeap) {
String prop = "maxBytesLocalOffHeap";
verifyGreaterThanZero(maxBytesOffHeap, prop);
boolean publish = checkDynChange(prop);
Long oldValue = this.maxBytesLocalOffHeap;
this.maxBytesLocalOffHeap = maxBytesOffHeap;
if (publish) {
firePropertyChange(prop, oldValue, maxBytesOffHeap);
}
}
/**
* Sets the maximum size for the OffHeap tier for all the caches this CacheManagers holds.
* @param amount the amount of unit
* @param memoryUnit the actual unit
* @return this
*/
public Configuration maxBytesLocalOffHeap(final long amount, final MemoryUnit memoryUnit) {
setMaxBytesLocalOffHeap(memoryUnit.toBytes(amount));
return this;
}
/**
* Maximum amount of bytes the CacheManager will use on the Disk Tier.
* @return amount in bytes
*/
public long getMaxBytesLocalDisk() {
return maxBytesLocalDisk == null ? DEFAULT_MAX_BYTES_ON_DISK : maxBytesLocalDisk;
}
/**
* Sets maximum amount of bytes the CacheManager will use on the Disk Tier.
* @param maxBytesOnDisk String representation of the size.
* @see MemoryUnit#parseSizeInBytes(String)
*/
public void setMaxBytesLocalDisk(final String maxBytesOnDisk) {
assertArgumentNotNull("MaxBytesLocalDisk", maxBytesOnDisk);
final String origInput = maxBytesLocalDiskInput;
try {
maxBytesLocalDiskInput = maxBytesOnDisk;
setMaxBytesLocalDisk(MemoryUnit.parseSizeInBytes(maxBytesOnDisk));
} catch (RuntimeException rte) {
maxBytesLocalDiskInput = origInput;
throw rte;
}
}
/**
* @return Original input for maxBytesLocalDisk
*/
public String getMaxBytesLocalDiskAsString() {
return maxBytesLocalDiskInput != null ? maxBytesLocalDiskInput : Long.toString(getMaxBytesLocalDisk());
}
/**
* Sets maximum amount of bytes the CacheManager will use on the Disk Tier.
* @param maxBytesOnDisk max bytes on disk in bytes. Needs be be greater than 0
*/
public void setMaxBytesLocalDisk(final Long maxBytesOnDisk) {
String prop = "maxBytesLocalDisk";
verifyGreaterThanZero(maxBytesOnDisk, prop);
boolean publish = checkDynChange(prop);
Long oldValue = this.maxBytesLocalDisk;
this.maxBytesLocalDisk = maxBytesOnDisk;
if (publish) {
firePropertyChange(prop, oldValue, maxBytesOnDisk);
}
}
/**
* Sets the maxOnDisk size
* @param amount the amount of unit
* @param memoryUnit the actual unit
* @return this
* @see #setMaxBytesLocalDisk(Long)
*/
public Configuration maxBytesLocalDisk(final long amount, final MemoryUnit memoryUnit) {
setMaxBytesLocalDisk(memoryUnit.toBytes(amount));
return this;
}
private void verifyGreaterThanZero(final Long maxBytesOnHeap, final String field) {
if (maxBytesOnHeap != null && maxBytesOnHeap < 1) {
throw new IllegalArgumentException(field + " has to be larger than 0");
}
}
/**
* Builder to add a disk store to the cache manager, only one disk store can be added.
*
* @param diskStoreConfigurationParameter
* the disk store configuration to use
* @return this configuration instance
* @throws ObjectExistsException
* if the disk store has already been configured
*/
public final Configuration diskStore(DiskStoreConfiguration diskStoreConfigurationParameter) throws ObjectExistsException {
addDiskStore(diskStoreConfigurationParameter);
return this;
}
/**
* Allows BeanHandler to add disk store location to the configuration.
*/
public final void addDiskStore(DiskStoreConfiguration diskStoreConfigurationParameter) throws ObjectExistsException {
if (diskStoreConfiguration != null) {
throw new ObjectExistsException("The Disk Store has already been configured");
}
final String prop = "diskStoreConfiguration";
boolean publish = checkDynChange(prop);
DiskStoreConfiguration oldValue = diskStoreConfiguration;
diskStoreConfiguration = diskStoreConfigurationParameter;
if (publish) {
firePropertyChange(prop, oldValue, diskStoreConfiguration);
}
}
/**
* Builder to set the default SizeOfPolicyConfiguration for this cache manager.
*
* @param sizeOfPolicyConfiguration the SizeOfPolicy Configuration
* @return this configuration instance
*/
public final Configuration sizeOfPolicy(SizeOfPolicyConfiguration sizeOfPolicyConfiguration) {
addSizeOfPolicy(sizeOfPolicyConfiguration);
return this;
}
/**
* Sets the default SizeOfPolicyConfiguration for this cache manager.
*
* @param sizeOfPolicy the SizeOfPolicy Configuration
*/
public final void addSizeOfPolicy(SizeOfPolicyConfiguration sizeOfPolicy) {
if (sizeOfPolicyConfiguration != null) {
throw new ObjectExistsException("The SizeOfPolicy class has already been configured");
}
sizeOfPolicyConfiguration = sizeOfPolicy;
}
/**
* Builder to add a transaction manager lookup class to the cache manager, only one of these can be added.
*
* @param transactionManagerLookupParameter
* the transaction manager lookup class to use
* @return this configuration instance
* @throws ObjectExistsException
* if the transaction manager lookup has already been configured
*/
public final Configuration transactionManagerLookup(FactoryConfiguration transactionManagerLookupParameter)
throws ObjectExistsException {
addTransactionManagerLookup(transactionManagerLookupParameter);
return this;
}
/**
* Allows BeanHandler to add transaction manager lookup to the configuration.
*/
public final void addTransactionManagerLookup(FactoryConfiguration transactionManagerLookupParameter) throws ObjectExistsException {
if (transactionManagerLookupConfiguration != null) {
throw new ObjectExistsException("The TransactionManagerLookup class has already been configured");
}
final String prop = "transactionManagerLookupConfiguration";
boolean publish = checkDynChange(prop);
FactoryConfiguration oldValue = this.transactionManagerLookupConfiguration;
transactionManagerLookupConfiguration = transactionManagerLookupParameter;
if (publish) {
firePropertyChange(prop, oldValue, transactionManagerLookupParameter);
}
}
/**
* Builder to set the event lister through a factory, only one of these can be added and subsequent calls are ignored.
*
* @return this configuration instance
*/
public final Configuration cacheManagerEventListenerFactory(FactoryConfiguration cacheManagerEventListenerFactoryConfiguration) {
addCacheManagerEventListenerFactory(cacheManagerEventListenerFactoryConfiguration);
return this;
}
/**
* Allows BeanHandler to add the CacheManagerEventListener to the configuration.
*/
public final void addCacheManagerEventListenerFactory(FactoryConfiguration cacheManagerEventListenerFactoryConfiguration) {
final String prop = "cacheManagerEventListenerFactoryConfiguration";
boolean publish = checkDynChange(prop);
if (this.cacheManagerEventListenerFactoryConfiguration == null) {
this.cacheManagerEventListenerFactoryConfiguration = cacheManagerEventListenerFactoryConfiguration;
if (publish) {
firePropertyChange(prop, null, cacheManagerEventListenerFactoryConfiguration);
}
}
}
/**
* Builder method to add a peer provider through a factory.
*
* @return this configuration instance
*/
public final Configuration cacheManagerPeerProviderFactory(FactoryConfiguration factory) {
addCacheManagerPeerProviderFactory(factory);
return this;
}
/**
* Adds a CacheManagerPeerProvider through FactoryConfiguration.
*/
public final void addCacheManagerPeerProviderFactory(FactoryConfiguration factory) {
final String prop = "cacheManagerPeerProviderFactoryConfiguration";
boolean publish = checkDynChange(prop);
List oldValue = null;
if (publish) {
oldValue = new ArrayList(cacheManagerPeerProviderFactoryConfiguration);
}
cacheManagerPeerProviderFactoryConfiguration.add(factory);
if (publish) {
firePropertyChange(prop, oldValue, cacheManagerPeerProviderFactoryConfiguration);
}
}
/**
* Builder method to add a peer listener through a factory.
*
* @return this configuration instance
*/
public final Configuration cacheManagerPeerListenerFactory(FactoryConfiguration factory) {
addCacheManagerPeerListenerFactory(factory);
return this;
}
/**
* Adds a CacheManagerPeerListener through FactoryConfiguration.
*/
public final void addCacheManagerPeerListenerFactory(FactoryConfiguration factory) {
final String prop = "cacheManagerPeerListenerFactoryConfiguration";
boolean publish = checkDynChange(prop);
List oldValue = null;
if (publish) {
oldValue = new ArrayList(cacheManagerPeerListenerFactoryConfiguration);
}
cacheManagerPeerListenerFactoryConfiguration.add(factory);
if (publish) {
firePropertyChange(prop, oldValue, cacheManagerPeerListenerFactoryConfiguration);
}
}
/**
* Builder method to Terracotta capabilities to the cache manager through a dedicated configuration, this can only be used once.
*
* @return this configuration instance
* @throws ObjectExistsException
* if the Terracotta config has already been configured
*/
public final Configuration terracotta(TerracottaClientConfiguration terracottaConfiguration) throws ObjectExistsException {
addTerracottaConfig(terracottaConfiguration);
return this;
}
/**
* Allows BeanHandler to add a Terracotta configuration to the configuration
*/
public final void addTerracottaConfig(TerracottaClientConfiguration terracottaConfiguration) throws ObjectExistsException {
if (this.terracottaConfigConfiguration != null && terracottaConfiguration != null) {
throw new ObjectExistsException("The TerracottaConfig has already been configured");
}
final String prop = "terracottaConfigConfiguration";
final boolean publish = checkDynChange(prop);
final TerracottaClientConfiguration oldValue = this.terracottaConfigConfiguration;
this.terracottaConfigConfiguration = terracottaConfiguration;
if (publish) {
firePropertyChange(prop, oldValue, terracottaConfiguration);
}
}
/**
* Builder method to REST management capabilities to the cache manager through a dedicated configuration, this can only be used once.
*
* @return this configuration instance
* @throws ObjectExistsException
* if the REST management config has already been configured
*/
public final Configuration managementRESTService(ManagementRESTServiceConfiguration cfg) throws ObjectExistsException {
addManagementRESTService(cfg);
return this;
}
/**
* Allows BeanHandler to add a ManagementRESTService configuration to the configuration
*/
public final void addManagementRESTService(ManagementRESTServiceConfiguration managementRESTServiceConfiguration) throws ObjectExistsException {
if (this.managementRESTService != null) {
throw new ObjectExistsException("The ManagementRESTService has already been configured");
}
final String prop = "managementRESTService";
final boolean publish = checkDynChange(prop);
final ManagementRESTServiceConfiguration oldValue = this.managementRESTService;
this.managementRESTService = managementRESTServiceConfiguration;
if (publish) {
firePropertyChange(prop, oldValue, managementRESTServiceConfiguration);
}
}
/**
* Builder method to set the default cache configuration, this can only be used once.
*
* @return this configuration instance
* @throws ObjectExistsException
* if the default cache config has already been configured
*/
public final Configuration defaultCache(CacheConfiguration defaultCacheConfiguration) throws ObjectExistsException {
setDefaultCacheConfiguration(defaultCacheConfiguration);
return this;
}
/**
* Allows BeanHandler to add a default configuration to the configuration.
*/
public final void addDefaultCache(CacheConfiguration defaultCacheConfiguration) throws ObjectExistsException {
if (this.defaultCacheConfiguration != null) {
throw new ObjectExistsException("The Default Cache has already been configured");
}
setDefaultCacheConfiguration(defaultCacheConfiguration);
}
/**
* Builder to add a new cache through its config
*
* @return this configuration instance
* @throws ObjectExistsException
* if a cache with the same name already exists, or if the name conflicts with the name of the default cache
*/
public final Configuration cache(CacheConfiguration cacheConfiguration) throws ObjectExistsException {
addCache(cacheConfiguration);
return this;
}
/**
* Allows BeanHandler to add Cache Configurations to the configuration.
*/
public final void addCache(CacheConfiguration cacheConfiguration) throws ObjectExistsException {
addCache(cacheConfiguration, true);
}
/**
* Maintains the known Cache's configuration map in this Configuration
* @param cacheConfiguration the CacheConfiguration
* @param strict true if added regularly, validation dyn config constraints, false if added through the cache being added
*/
void addCache(CacheConfiguration cacheConfiguration, final boolean strict) throws ObjectExistsException {
final String prop = "cacheConfigurations";
Object oldValue = null;
boolean publishChange = strict && checkDynChange(prop);
if (publishChange) {
oldValue = new HashMap(cacheConfigurations);
}
if (cacheConfigurations.get(cacheConfiguration.name) != null) {
throw new ObjectExistsException("Cannot create cache: " + cacheConfiguration.name + " with the same name as an existing one.");
}
if (cacheConfiguration.name.equalsIgnoreCase(net.sf.ehcache.Cache.DEFAULT_CACHE_NAME)) {
throw new ObjectExistsException("The Default Cache has already been configured");
}
cacheConfigurations.put(cacheConfiguration.name, cacheConfiguration);
if (publishChange) {
firePropertyChange(prop, oldValue, cacheConfigurations);
}
}
private boolean checkDynChange(final String prop) {
if (!propertyChangeListeners.isEmpty()) {
try {
if (cfg != null) {
DynamicProperty.valueOf(prop);
}
} catch (IllegalArgumentException e) {
throw new IllegalStateException(this.getClass().getName() + "." + prop + " can't be changed dynamically");
}
return true;
} else {
return false;
}
}
/**
* Gets a Map of cacheConfigurations.
*/
public final Set getCacheConfigurationsKeySet() {
return cacheConfigurations.keySet();
}
/**
* @return the configuration's default cache configuration
*/
public final CacheConfiguration getDefaultCacheConfiguration() {
return defaultCacheConfiguration;
}
/**
* @param defaultCacheConfiguration
*/
public final void setDefaultCacheConfiguration(CacheConfiguration defaultCacheConfiguration) {
final String prop = "defaultCacheConfiguration";
final boolean publish = checkDynChange(prop);
final CacheConfiguration oldValue = this.defaultCacheConfiguration;
this.defaultCacheConfiguration = defaultCacheConfiguration;
if (publish) {
firePropertyChange(prop, oldValue, defaultCacheConfiguration);
}
}
/**
* Gets the disk store configuration.
*/
public final DiskStoreConfiguration getDiskStoreConfiguration() {
return diskStoreConfiguration;
}
/**
* Gets the SizeOf policy configuration.
*/
public final SizeOfPolicyConfiguration getSizeOfPolicyConfiguration() {
if (sizeOfPolicyConfiguration == null) {
return DEFAULT_SIZEOF_POLICY_CONFIGURATION;
}
return sizeOfPolicyConfiguration;
}
/**
* Gets the transaction manager lookup configuration.
*/
public final FactoryConfiguration getTransactionManagerLookupConfiguration() {
if (transactionManagerLookupConfiguration == null) {
return getDefaultTransactionManagerLookupConfiguration();
}
return transactionManagerLookupConfiguration;
}
/**
* Gets the CacheManagerPeerProvider factory configuration.
*/
public final List getCacheManagerPeerProviderFactoryConfiguration() {
return cacheManagerPeerProviderFactoryConfiguration;
}
/**
* Gets the CacheManagerPeerListener factory configuration.
*/
public final List getCacheManagerPeerListenerFactoryConfigurations() {
return cacheManagerPeerListenerFactoryConfiguration;
}
/**
* Gets the ManagementRESTServiceConfiguration
*/
public final ManagementRESTServiceConfiguration getManagementRESTService() {
return managementRESTService;
}
/**
* Gets the CacheManagerEventListener factory configuration.
*/
public final FactoryConfiguration getCacheManagerEventListenerFactoryConfiguration() {
return cacheManagerEventListenerFactoryConfiguration;
}
/**
* Gets the TerracottaClientConfiguration
*/
public final TerracottaClientConfiguration getTerracottaConfiguration() {
return this.terracottaConfigConfiguration;
}
/**
* Gets a Map of cache configurations, keyed by name.
*/
public final Map getCacheConfigurations() {
return cacheConfigurations;
}
/**
* Builder to set the configuration source.
*
* @return this configuration instance
*/
public final Configuration source(ConfigurationSource configurationSource) {
setSource(configurationSource);
return this;
}
/**
* Sets the configuration source.
*
* @param configurationSource
* an informative description of the source, preferably
* including the resource name and location.
*/
public final void setSource(ConfigurationSource configurationSource) {
final String prop = "configurationSource";
final boolean publish = checkDynChange(prop);
final ConfigurationSource oldValue = this.configurationSource;
this.configurationSource = configurationSource;
if (publish) {
firePropertyChange(prop, oldValue, configurationSource);
}
}
/**
* Gets a description of the source from which this configuration was created.
*/
public final ConfigurationSource getConfigurationSource() {
return configurationSource;
}
/**
* Adds a {@link PropertyChangeListener} for this configuration
* @param listener the listener instance
* @return true if added, false otherwise
*/
public boolean addPropertyChangeListener(final PropertyChangeListener listener) {
return this.propertyChangeListeners.add(listener);
}
/**
* Removes a {@link PropertyChangeListener} for this configuration
* @param listener the listener to be removed
* @return true if removed, false otherwise
*/
public boolean removePropertyChangeListener(final PropertyChangeListener listener) {
return this.propertyChangeListeners.remove(listener);
}
private void firePropertyChange(final String prop, final T oldValue, final T newValue) {
if ((oldValue != null && !oldValue.equals(newValue)) || newValue != null) {
for (PropertyChangeListener propertyChangeListener : propertyChangeListeners) {
propertyChangeListener.propertyChange(new PropertyChangeEvent(Configuration.this, prop, oldValue, newValue));
}
}
}
/**
* Runtime configuration as being used by the CacheManager
*/
public class RuntimeCfg implements PropertyChangeListener {
private final CacheManager cacheManager;
private volatile String cacheManagerName;
private final boolean named;
private TransactionManagerLookup transactionManagerLookup;
private boolean allowsSizeBasedTunings;
/**
* Constructor
* @param cacheManager the cacheManager instance using this config
* @param fallbackName the fallbackName in case the configuration doesn't declare an explicit name
*/
public RuntimeCfg(final CacheManager cacheManager, final String fallbackName) {
if (Configuration.this.cacheManagerName != null) {
this.cacheManagerName = Configuration.this.cacheManagerName;
named = true;
} else if (hasTerracottaClusteredCaches()) {
this.cacheManagerName = CacheManager.DEFAULT_NAME;
named = false;
} else {
this.cacheManagerName = fallbackName;
named = false;
}
FactoryConfiguration lookupConfiguration = getTransactionManagerLookupConfiguration();
try {
Properties properties = PropertyUtil.parseProperties(lookupConfiguration.getProperties(),
lookupConfiguration.getPropertySeparator());
ClassLoader loader = getClassLoader();
// when loading the default impl use the same loader as ehcache itself
if (DEFAULT_TRANSACTION_MANAGER_LOOKUP_CONFIG.getFullyQualifiedClassPath().equals(lookupConfiguration.getFullyQualifiedClassPath())) {
loader = getClass().getClassLoader();
}
Class extends TransactionManagerLookup> transactionManagerLookupClass = (Class extends TransactionManagerLookup>) loader
.loadClass(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);
}
this.cacheManager = cacheManager;
propertyChangeListeners.add(this);
allowsSizeBasedTunings = defaultCacheConfiguration == null || !defaultCacheConfiguration.isCountBasedTuned();
for (CacheConfiguration cacheConfiguration : cacheConfigurations.values()) {
if (cacheConfiguration.isCountBasedTuned()) {
allowsSizeBasedTunings = false;
break;
}
}
}
/**
* @return the CacheManager's name
*/
public String getCacheManagerName() {
return cacheManagerName;
}
/**
* @return Whether dynamic config changes are available
*/
public boolean allowsDynamicCacheConfig() {
return getDynamicConfig();
}
/**
* @return Whether the CacheManager is explicitly named
*/
public boolean isNamed() {
return named;
}
/**
* @return the underlying Configuration instance
*/
public Configuration getConfiguration() {
return Configuration.this;
}
/**
* @return Whether terracotta clustering is being used and rejoin is enabled
*/
public boolean isTerracottaRejoin() {
TerracottaClientConfiguration terracottaConfiguration = getTerracottaConfiguration();
return terracottaConfiguration != null && terracottaConfiguration.isRejoin();
}
private boolean hasTerracottaClusteredCaches() {
if (defaultCacheConfiguration != null
&& defaultCacheConfiguration.isTerracottaClustered()) {
return true;
} else {
for (CacheConfiguration config : cacheConfigurations.values()) {
if (config.isTerracottaClustered()) {
return true;
}
}
}
return false;
}
/**
* @return The transactionManagerLookup instance
*/
public TransactionManagerLookup getTransactionManagerLookup() {
return transactionManagerLookup;
}
/**
* Removes a cache from the known list
* @param cacheConfiguration the cacheConfiguration to be removed
*/
public void removeCache(final CacheConfiguration cacheConfiguration) {
if (cacheManager.getOnHeapPool() != null) {
cacheManager.getOnHeapPool().setMaxSize(cacheManager.getOnHeapPool()
.getMaxSize() + cacheConfiguration.getMaxBytesLocalHeap());
}
if (cacheManager.getOnDiskPool() != null) {
cacheManager.getOnDiskPool().setMaxSize(cacheManager.getOnDiskPool()
.getMaxSize() + cacheConfiguration.getMaxBytesLocalDisk());
}
getConfiguration().getCacheConfigurations().remove(cacheConfiguration.getName());
}
/**
* Handles changes to the Configuration this RuntimeCfg backs
* @param evt the PropertyChangeEvent
*/
public void propertyChange(final PropertyChangeEvent evt) {
try {
DynamicProperty.valueOf(evt.getPropertyName()).applyChange(evt, this);
} catch (IllegalArgumentException e) {
throw new IllegalStateException(evt.getPropertyName() + " can't be changed dynamically");
}
}
/**
* Checks whether the CacheManager uses a OffHeapPool
* @return true if using one, false otherwise
*/
public boolean hasOffHeapPool() {
return isMaxBytesLocalOffHeapSet();
}
}
public ClassLoader getClassLoader() {
return this.classLoader;
}
/**
* Set the classloader for the cache manager (and it's associated caches) to use when creating application objects (eg. cache values,
* event listeners, etc). The default classloading behavior is to prefer Thread.currentThread().getContextClassLoader() and fallback
* to the classloader that loaded ehcache itself.
*
* @param loader the classloader to use
*/
public void setClassLoader(ClassLoader loader) {
this.classLoader = loader;
}
public void cleanup() {
propertyChangeListeners.remove(cfg);
cfg = null;
}
}