/*
* 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 org.ehcache.xml;
import org.ehcache.config.CacheConfiguration;
import org.ehcache.config.Configuration;
import org.ehcache.config.EvictionAdvisor;
import org.ehcache.config.ResourcePool;
import org.ehcache.config.ResourcePools;
import org.ehcache.config.Builder;
import org.ehcache.config.builders.CacheConfigurationBuilder;
import org.ehcache.config.builders.CacheEventListenerConfigurationBuilder;
import org.ehcache.config.builders.ResourcePoolsBuilder;
import org.ehcache.config.builders.WriteBehindConfigurationBuilder;
import org.ehcache.config.builders.WriteBehindConfigurationBuilder.BatchedWriteBehindConfigurationBuilder;
import org.ehcache.core.internal.util.ClassLoading;
import org.ehcache.event.CacheEventListener;
import org.ehcache.event.EventFiring;
import org.ehcache.event.EventOrdering;
import org.ehcache.expiry.Duration;
import org.ehcache.expiry.Expirations;
import org.ehcache.expiry.Expiry;
import org.ehcache.impl.config.copy.DefaultCopierConfiguration;
import org.ehcache.impl.config.copy.DefaultCopyProviderConfiguration;
import org.ehcache.impl.config.event.CacheEventDispatcherFactoryConfiguration;
import org.ehcache.impl.config.event.DefaultCacheEventDispatcherConfiguration;
import org.ehcache.impl.config.executor.PooledExecutionServiceConfiguration;
import org.ehcache.impl.config.loaderwriter.DefaultCacheLoaderWriterConfiguration;
import org.ehcache.impl.config.loaderwriter.writebehind.WriteBehindProviderConfiguration;
import org.ehcache.impl.config.persistence.CacheManagerPersistenceConfiguration;
import org.ehcache.impl.config.serializer.DefaultSerializationProviderConfiguration;
import org.ehcache.impl.config.serializer.DefaultSerializerConfiguration;
import org.ehcache.impl.config.store.heap.DefaultSizeOfEngineConfiguration;
import org.ehcache.impl.config.store.heap.DefaultSizeOfEngineProviderConfiguration;
import org.ehcache.impl.config.store.disk.OffHeapDiskStoreConfiguration;
import org.ehcache.impl.config.store.disk.OffHeapDiskStoreProviderConfiguration;
import org.ehcache.spi.copy.Copier;
import org.ehcache.spi.loaderwriter.CacheLoaderWriter;
import org.ehcache.spi.serialization.Serializer;
import org.ehcache.spi.service.ServiceConfiguration;
import org.ehcache.spi.service.ServiceCreationConfiguration;
import org.ehcache.xml.ConfigurationParser.Batching;
import org.ehcache.xml.ConfigurationParser.WriteBehind;
import org.ehcache.xml.exceptions.XmlConfigurationException;
import org.ehcache.xml.model.CopierType;
import org.ehcache.xml.model.EventType;
import org.ehcache.xml.model.SerializerType;
import org.ehcache.xml.model.ServiceType;
import org.ehcache.xml.model.ThreadPoolReferenceType;
import org.ehcache.xml.model.ThreadPoolsType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xml.sax.SAXException;
import javax.xml.bind.JAXBException;
import javax.xml.parsers.ParserConfigurationException;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import static org.ehcache.config.builders.CacheConfigurationBuilder.newCacheConfigurationBuilder;
import static org.ehcache.config.builders.ResourcePoolsBuilder.newResourcePoolsBuilder;
/**
* Exposes {@link org.ehcache.config.Configuration} and {@link CacheConfigurationBuilder} expressed
* in a XML file that obeys the <a href="http://www.ehcache.org/v3" target="_blank">core Ehcache schema</a>.
* <p>
* Instances of this class are not thread-safe.
*/
public class XmlConfiguration implements Configuration {
private static final Logger LOGGER = LoggerFactory.getLogger(XmlConfiguration.class);
private final URL xml;
private final ClassLoader classLoader;
private final Map<String, ClassLoader> cacheClassLoaders;
private final Collection<ServiceCreationConfiguration<?>> serviceConfigurations = new ArrayList<ServiceCreationConfiguration<?>>();
private final Map<String, CacheConfiguration<?, ?>> cacheConfigurations = new HashMap<String, CacheConfiguration<?, ?>>();
private final Map<String, ConfigurationParser.CacheTemplate> templates = new HashMap<String, ConfigurationParser.CacheTemplate>();
/**
* Constructs an instance of XmlConfiguration mapping to the XML file located at {@code url}
* <p>
* Parses the XML file at the {@code url} provided.
*
* @param url URL pointing to the XML file's location
*
* @throws XmlConfigurationException if anything went wrong parsing the XML
*/
public XmlConfiguration(URL url)
throws XmlConfigurationException {
this(url, ClassLoading.getDefaultClassLoader());
}
/**
* Constructs an instance of XmlConfiguration mapping to the XML file located at {@code url} and using the provided
* {@code classLoader} to load user types (e.g. key and value Class instances).
* <p>
* Parses the XML file at the {@code url} provided.
*
* @param url URL pointing to the XML file's location
* @param classLoader ClassLoader to use to load user types.
*
* @throws XmlConfigurationException if anything went wrong parsing the XML
*/
public XmlConfiguration(URL url, final ClassLoader classLoader)
throws XmlConfigurationException {
this(url, classLoader, Collections.<String, ClassLoader>emptyMap());
}
/**
* Constructs an instance of XmlConfiguration mapping to the XML file located at {@code url} and using the provided
* {@code classLoader} to load user types (e.g. key and value Class instances). The {@code cacheClassLoaders} will
* let you specify a different {@link java.lang.ClassLoader} to use for each {@link org.ehcache.Cache} managed by
* the {@link org.ehcache.CacheManager} configured using this {@link org.ehcache.xml.XmlConfiguration}
* <p>
* Parses the XML file at the {@code url} provided.
*
* @param url URL pointing to the XML file's location
* @param classLoader ClassLoader to use to load user types.
* @param cacheClassLoaders the map with mappings between cache names and the corresponding class loaders
*
* @throws XmlConfigurationException if anything went wrong parsing the XML
*/
public XmlConfiguration(URL url, final ClassLoader classLoader, final Map<String, ClassLoader> cacheClassLoaders)
throws XmlConfigurationException {
if(url == null) {
throw new NullPointerException("The url can not be null");
}
if(classLoader == null) {
throw new NullPointerException("The classLoader can not be null");
}
if(cacheClassLoaders == null) {
throw new NullPointerException("The cacheClassLoaders map can not be null");
}
this.xml = url;
this.classLoader = classLoader;
this.cacheClassLoaders = new HashMap<String, ClassLoader>(cacheClassLoaders);
try {
parseConfiguration();
} catch (XmlConfigurationException e) {
throw e;
} catch (Exception e) {
throw new XmlConfigurationException("Error parsing XML configuration at " + url, e);
}
}
@SuppressWarnings({ "rawtypes", "unchecked" })
private void parseConfiguration()
throws ClassNotFoundException, IOException, SAXException, InstantiationException, IllegalAccessException, JAXBException, ParserConfigurationException {
LOGGER.info("Loading Ehcache XML configuration from {}.", xml.getPath());
ConfigurationParser configurationParser = new ConfigurationParser(xml.toExternalForm());
final ArrayList<ServiceCreationConfiguration<?>> serviceConfigs = new ArrayList<ServiceCreationConfiguration<?>>();
for (ServiceType serviceType : configurationParser.getServiceElements()) {
final ServiceCreationConfiguration<?> serviceConfiguration = configurationParser.parseExtension(serviceType.getServiceCreationConfiguration());
serviceConfigs.add(serviceConfiguration);
}
if (configurationParser.getDefaultSerializers() != null) {
DefaultSerializationProviderConfiguration configuration = new DefaultSerializationProviderConfiguration();
for (SerializerType.Serializer serializer : configurationParser.getDefaultSerializers().getSerializer()) {
configuration.addSerializerFor(getClassForName(serializer.getType(), classLoader), (Class) getClassForName(serializer.getValue(), classLoader));
}
serviceConfigs.add(configuration);
}
if (configurationParser.getDefaultCopiers() != null) {
DefaultCopyProviderConfiguration configuration = new DefaultCopyProviderConfiguration();
for (CopierType.Copier copier : configurationParser.getDefaultCopiers().getCopier()) {
configuration.addCopierFor(getClassForName(copier.getType(), classLoader), (Class)getClassForName(copier.getValue(), classLoader));
}
serviceConfigs.add(configuration);
}
if (configurationParser.getHeapStore() != null) {
DefaultSizeOfEngineProviderConfiguration configuration = new DefaultSizeOfEngineProviderConfiguration(
configurationParser.getHeapStore().getMaxObjectSize(), configurationParser.getHeapStore().getUnit(),
configurationParser.getHeapStore().getMaxObjectGraphSize());
serviceConfigs.add(configuration);
}
if (configurationParser.getPersistence() != null) {
serviceConfigs.add(new CacheManagerPersistenceConfiguration(new File(configurationParser.getPersistence().getDirectory())));
}
if (configurationParser.getThreadPools() != null) {
PooledExecutionServiceConfiguration poolsConfiguration = new PooledExecutionServiceConfiguration();
for (ThreadPoolsType.ThreadPool pool : configurationParser.getThreadPools().getThreadPool()) {
if (pool.isDefault()) {
poolsConfiguration.addDefaultPool(pool.getAlias(), pool.getMinSize().intValue(), pool.getMaxSize().intValue());
} else {
poolsConfiguration.addPool(pool.getAlias(), pool.getMinSize().intValue(), pool.getMaxSize().intValue());
}
}
serviceConfigs.add(poolsConfiguration);
}
if (configurationParser.getEventDispatch() != null) {
ThreadPoolReferenceType eventDispatchThreading = configurationParser.getEventDispatch();
serviceConfigs.add(new CacheEventDispatcherFactoryConfiguration(eventDispatchThreading.getThreadPool()));
}
if (configurationParser.getWriteBehind() != null) {
ThreadPoolReferenceType writeBehindThreading = configurationParser.getWriteBehind();
serviceConfigs.add(new WriteBehindProviderConfiguration(writeBehindThreading.getThreadPool()));
}
if (configurationParser.getDiskStore() != null) {
ThreadPoolReferenceType diskStoreThreading = configurationParser.getDiskStore();
serviceConfigs.add(new OffHeapDiskStoreProviderConfiguration(diskStoreThreading.getThreadPool()));
}
for (ServiceCreationConfiguration<?> serviceConfiguration : Collections.unmodifiableList(serviceConfigs)) {
serviceConfigurations.add(serviceConfiguration);
}
for (ConfigurationParser.CacheDefinition cacheDefinition : configurationParser.getCacheElements()) {
String alias = cacheDefinition.id();
if(cacheConfigurations.containsKey(alias)) {
throw new XmlConfigurationException("Two caches defined with the same alias: " + alias);
}
ClassLoader cacheClassLoader = cacheClassLoaders.get(alias);
boolean classLoaderConfigured = false;
if (cacheClassLoader != null) {
classLoaderConfigured = true;
}
if (cacheClassLoader == null) {
if (classLoader != null) {
cacheClassLoader = classLoader;
} else {
cacheClassLoader = ClassLoading.getDefaultClassLoader();
}
}
Class keyType = getClassForName(cacheDefinition.keyType(), cacheClassLoader);
Class valueType = getClassForName(cacheDefinition.valueType(), cacheClassLoader);
ResourcePoolsBuilder resourcePoolsBuilder = newResourcePoolsBuilder();
for (ResourcePool resourcePool : cacheDefinition.resourcePools()) {
resourcePoolsBuilder = resourcePoolsBuilder.with(resourcePool);
}
CacheConfigurationBuilder<Object, Object> builder = newCacheConfigurationBuilder(keyType, valueType, resourcePoolsBuilder);
if (classLoaderConfigured) {
builder = builder.withClassLoader(cacheClassLoader);
}
if (cacheDefinition.keySerializer() != null) {
Class keySerializer = getClassForName(cacheDefinition.keySerializer(), cacheClassLoader);
builder = builder.add(new DefaultSerializerConfiguration(keySerializer, DefaultSerializerConfiguration.Type.KEY));
}
if (cacheDefinition.keyCopier() != null) {
Class keyCopier = getClassForName(cacheDefinition.keyCopier(), cacheClassLoader);
builder = builder.add(new DefaultCopierConfiguration(keyCopier, DefaultCopierConfiguration.Type.KEY));
}
if (cacheDefinition.valueSerializer() != null) {
Class valueSerializer = getClassForName(cacheDefinition.valueSerializer(), cacheClassLoader);
builder = builder.add(new DefaultSerializerConfiguration(valueSerializer, DefaultSerializerConfiguration.Type.VALUE));
}
if (cacheDefinition.valueCopier() != null) {
Class valueCopier = getClassForName(cacheDefinition.valueCopier(), cacheClassLoader);
builder = builder.add(new DefaultCopierConfiguration(valueCopier, DefaultCopierConfiguration.Type.VALUE));
}
if (cacheDefinition.heapStoreSettings() != null) {
builder = builder.add(new DefaultSizeOfEngineConfiguration(cacheDefinition.heapStoreSettings().getMaxObjectSize(), cacheDefinition.heapStoreSettings().getUnit(),
cacheDefinition.heapStoreSettings().getMaxObjectGraphSize()));
}
EvictionAdvisor evictionAdvisor = getInstanceOfName(cacheDefinition.evictionAdvisor(), cacheClassLoader, EvictionAdvisor.class);
builder = builder.withEvictionAdvisor(evictionAdvisor);
final ConfigurationParser.Expiry parsedExpiry = cacheDefinition.expiry();
if (parsedExpiry != null) {
builder = builder.withExpiry(getExpiry(cacheClassLoader, parsedExpiry));
}
final ConfigurationParser.DiskStoreSettings parsedDiskStoreSettings = cacheDefinition.diskStoreSettings();
if (parsedDiskStoreSettings != null) {
builder = builder.add(new OffHeapDiskStoreConfiguration(parsedDiskStoreSettings.threadPool(), parsedDiskStoreSettings.writerConcurrency(), parsedDiskStoreSettings.diskSegments()));
}
for (ServiceConfiguration<?> serviceConfig : cacheDefinition.serviceConfigs()) {
builder = builder.add(serviceConfig);
}
if(cacheDefinition.loaderWriter()!= null) {
final Class<CacheLoaderWriter<?, ?>> cacheLoaderWriterClass = (Class<CacheLoaderWriter<?,?>>)getClassForName(cacheDefinition.loaderWriter(), cacheClassLoader);
builder = builder.add(new DefaultCacheLoaderWriterConfiguration(cacheLoaderWriterClass));
if(cacheDefinition.writeBehind() != null) {
WriteBehind writeBehind = cacheDefinition.writeBehind();
WriteBehindConfigurationBuilder writeBehindConfigurationBuilder;
if (writeBehind.batching() == null) {
writeBehindConfigurationBuilder = WriteBehindConfigurationBuilder.newUnBatchedWriteBehindConfiguration();
} else {
Batching batching = writeBehind.batching();
writeBehindConfigurationBuilder = WriteBehindConfigurationBuilder
.newBatchedWriteBehindConfiguration(batching.maxDelay(), batching.maxDelayUnit(), batching.batchSize());
if (batching.isCoalesced()) {
writeBehindConfigurationBuilder = ((BatchedWriteBehindConfigurationBuilder) writeBehindConfigurationBuilder).enableCoalescing();
}
}
builder = builder.add(writeBehindConfigurationBuilder
.useThreadPool(writeBehind.threadPool())
.concurrencyLevel(writeBehind.concurrency())
.queueSize(writeBehind.maxQueueSize()));
}
}
builder = handleListenersConfig(cacheDefinition.listenersConfig(), cacheClassLoader, builder);
final CacheConfiguration<?, ?> config = builder.build();
cacheConfigurations.put(alias, config);
}
templates.putAll(configurationParser.getTemplates());
}
@SuppressWarnings("unchecked")
private Expiry<? super Object, ? super Object> getExpiry(ClassLoader cacheClassLoader, ConfigurationParser.Expiry parsedExpiry)
throws ClassNotFoundException, InstantiationException, IllegalAccessException {
final Expiry<? super Object, ? super Object> expiry;
if (parsedExpiry.isUserDef()) {
expiry = getInstanceOfName(parsedExpiry.type(), cacheClassLoader, Expiry.class);
} else if (parsedExpiry.isTTL()) {
expiry = Expirations.timeToLiveExpiration(new Duration(parsedExpiry.value(), parsedExpiry.unit()));
} else if (parsedExpiry.isTTI()) {
expiry = Expirations.timeToIdleExpiration(new Duration(parsedExpiry.value(), parsedExpiry.unit()));
} else {
expiry = Expirations.noExpiration();
}
return expiry;
}
private static <T> T getInstanceOfName(String name, ClassLoader classLoader, Class<T> type) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
if (name == null) {
return null;
}
Class<?> klazz = getClassForName(name, classLoader);
return klazz.asSubclass(type).newInstance();
}
private static Class<?> getClassForName(String name, ClassLoader classLoader) throws ClassNotFoundException {
return Class.forName(name, true, classLoader);
}
/**
* Exposes the URL where the XML file parsed or yet to be parsed was or will be sourced from.
* @return The URL provided at object instantiation
*/
public URL getURL() {
return xml;
}
/**
* Creates a new {@link CacheConfigurationBuilder} seeded with the cache-template configuration
* by the given {@code name} in the XML configuration parsed using {@link #parseConfiguration()}.
* <p>
* Note that this version does not specify resources, which are mandatory to create a
* {@link CacheConfigurationBuilder}. So if the template does not define resources, this will throw.
*
* @param name the unique name identifying the cache-template element in the XML
* @param keyType the type of keys for the {@link CacheConfigurationBuilder} to use, must
* match the {@code key-type} declared in the template if declared in XML
* @param valueType the type of values for the {@link CacheConfigurationBuilder} to use, must
* match the {@code value-type} declared in the template if declared in XML
* @param <K> type of keys
* @param <V> type of values
*
* @return the preconfigured {@link CacheConfigurationBuilder}
* or {@code null} if no cache-template for the provided {@code name}
*
* @throws IllegalStateException if {@link #parseConfiguration()} hasn't yet been successfully invoked or the template
* does not configure resources.
* @throws IllegalArgumentException if {@code keyType} or {@code valueType} don't match the declared type(s) of the template
* @throws ClassNotFoundException if a {@link java.lang.Class} declared in the XML couldn't be found
* @throws InstantiationException if a user provided {@link java.lang.Class} couldn't get instantiated
* @throws IllegalAccessException if a method (including constructor) couldn't be invoked on a user provided type
*/
@SuppressWarnings("unchecked")
public <K, V> CacheConfigurationBuilder<K, V> newCacheConfigurationBuilderFromTemplate(final String name,
final Class<K> keyType,
final Class<V> valueType)
throws InstantiationException, IllegalAccessException, ClassNotFoundException {
return internalCacheConfigurationBuilderFromTemplate(name, keyType, valueType, null);
}
/**
* Creates a new {@link CacheConfigurationBuilder} seeded with the cache-template configuration
* by the given {@code name} in the XML configuration parsed using {@link #parseConfiguration()}.
*
* @param name the unique name identifying the cache-template element in the XML
* @param keyType the type of keys for the {@link CacheConfigurationBuilder} to use, must
* match the {@code key-type} declared in the template if declared in XML
* @param valueType the type of values for the {@link CacheConfigurationBuilder} to use, must
* match the {@code value-type} declared in the template if declared in XML
* @param resourcePools Resources definitions that will be used
* @param <K> type of keys
* @param <V> type of values
*
* @return the preconfigured {@link CacheConfigurationBuilder}
* or {@code null} if no cache-template for the provided {@code name}
*
* @throws IllegalStateException if {@link #parseConfiguration()} hasn't yet been successfully invoked
* @throws IllegalArgumentException if {@code keyType} or {@code valueType} don't match the declared type(s) of the template
* @throws ClassNotFoundException if a {@link java.lang.Class} declared in the XML couldn't be found
* @throws InstantiationException if a user provided {@link java.lang.Class} couldn't get instantiated
* @throws IllegalAccessException if a method (including constructor) couldn't be invoked on a user provided type
*/
@SuppressWarnings("unchecked")
public <K, V> CacheConfigurationBuilder<K, V> newCacheConfigurationBuilderFromTemplate(final String name,
final Class<K> keyType,
final Class<V> valueType,
final ResourcePools resourcePools)
throws InstantiationException, IllegalAccessException, ClassNotFoundException {
if (resourcePools == null || resourcePools.getResourceTypeSet().isEmpty()) {
throw new IllegalArgumentException("ResourcePools parameter must define at least one resource");
}
return internalCacheConfigurationBuilderFromTemplate(name, keyType, valueType, resourcePools);
}
/**
* Creates a new {@link CacheConfigurationBuilder} seeded with the cache-template configuration
* by the given {@code name} in the XML configuration parsed using {@link #parseConfiguration()}.
*
* @param name the unique name identifying the cache-template element in the XML
* @param keyType the type of keys for the {@link CacheConfigurationBuilder} to use, must
* match the {@code key-type} declared in the template if declared in XML
* @param valueType the type of values for the {@link CacheConfigurationBuilder} to use, must
* match the {@code value-type} declared in the template if declared in XML
* @param resourcePoolsBuilder Resources definitions that will be used
* @param <K> type of keys
* @param <V> type of values
*
* @return the preconfigured {@link CacheConfigurationBuilder}
* or {@code null} if no cache-template for the provided {@code name}
*
* @throws IllegalStateException if {@link #parseConfiguration()} hasn't yet been successfully invoked
* @throws IllegalArgumentException if {@code keyType} or {@code valueType} don't match the declared type(s) of the template
* @throws ClassNotFoundException if a {@link java.lang.Class} declared in the XML couldn't be found
* @throws InstantiationException if a user provided {@link java.lang.Class} couldn't get instantiated
* @throws IllegalAccessException if a method (including constructor) couldn't be invoked on a user provided type
*/
@SuppressWarnings("unchecked")
public <K, V> CacheConfigurationBuilder<K, V> newCacheConfigurationBuilderFromTemplate(final String name,
final Class<K> keyType,
final Class<V> valueType,
final Builder<? extends ResourcePools> resourcePoolsBuilder)
throws InstantiationException, IllegalAccessException, ClassNotFoundException {
return internalCacheConfigurationBuilderFromTemplate(name, keyType, valueType, resourcePoolsBuilder.build());
}
@SuppressWarnings("unchecked")
private <K, V> CacheConfigurationBuilder<K, V> internalCacheConfigurationBuilderFromTemplate(final String name,
final Class<K> keyType,
final Class<V> valueType,
final ResourcePools resourcePools)
throws InstantiationException, IllegalAccessException, ClassNotFoundException {
final ConfigurationParser.CacheTemplate cacheTemplate = templates.get(name);
if (cacheTemplate == null) {
return null;
}
final ClassLoader defaultClassLoader = ClassLoading.getDefaultClassLoader();
Class keyClass = getClassForName(cacheTemplate.keyType(), defaultClassLoader);
Class valueClass = getClassForName(cacheTemplate.valueType(), defaultClassLoader);
if(keyType != null && cacheTemplate.keyType() != null && !keyClass.isAssignableFrom(keyType)) {
throw new IllegalArgumentException("CacheTemplate '" + name + "' declares key type of " + cacheTemplate.keyType());
}
if(valueType != null && cacheTemplate.valueType() != null && !valueClass.isAssignableFrom(valueType)) {
throw new IllegalArgumentException("CacheTemplate '" + name + "' declares value type of " + cacheTemplate.valueType());
}
if ((resourcePools == null || resourcePools.getResourceTypeSet().isEmpty()) && cacheTemplate.resourcePools().isEmpty()) {
throw new IllegalStateException("Template defines no resources, and none were provided");
}
CacheConfigurationBuilder<K, V> builder;
if (resourcePools != null) {
builder = newCacheConfigurationBuilder(keyType, valueType, resourcePools);
} else {
ResourcePoolsBuilder resourcePoolsBuilder = newResourcePoolsBuilder();
for (ResourcePool resourcePool : cacheTemplate.resourcePools()) {
resourcePoolsBuilder = resourcePoolsBuilder.with(resourcePool);
}
builder = newCacheConfigurationBuilder(keyType, valueType, resourcePoolsBuilder);
}
builder = builder
.withEvictionAdvisor(getInstanceOfName(cacheTemplate.evictionAdvisor(), defaultClassLoader, EvictionAdvisor.class));
final ConfigurationParser.Expiry parsedExpiry = cacheTemplate.expiry();
if (parsedExpiry != null) {
builder = builder.withExpiry(getExpiry(defaultClassLoader, parsedExpiry));
}
if (cacheTemplate.keySerializer() != null) {
final Class<Serializer<?>> keySerializer = (Class<Serializer<?>>) getClassForName(cacheTemplate.keySerializer(), defaultClassLoader);
builder = builder.add(new DefaultSerializerConfiguration(keySerializer, DefaultSerializerConfiguration.Type.KEY));
}
if (cacheTemplate.keyCopier() != null) {
final Class<Copier<?>> keyCopier = (Class<Copier<?>>) getClassForName(cacheTemplate.keyCopier(), defaultClassLoader);
builder = builder.add(new DefaultCopierConfiguration(keyCopier, DefaultCopierConfiguration.Type.KEY));
}
if (cacheTemplate.valueSerializer() != null) {
final Class<Serializer<?>> valueSerializer = (Class<Serializer<?>>) getClassForName(cacheTemplate.valueSerializer(), defaultClassLoader);
builder = builder.add(new DefaultSerializerConfiguration(valueSerializer, DefaultSerializerConfiguration.Type.VALUE));
}
if (cacheTemplate.valueCopier() != null) {
final Class<Copier<?>> valueCopier = (Class<Copier<?>>) getClassForName(cacheTemplate.valueCopier(), defaultClassLoader);
builder = builder.add(new DefaultCopierConfiguration(valueCopier, DefaultCopierConfiguration.Type.VALUE));
}
if (cacheTemplate.heapStoreSettings() != null) {
builder = builder.add(new DefaultSizeOfEngineConfiguration(cacheTemplate.heapStoreSettings().getMaxObjectSize(), cacheTemplate.heapStoreSettings().getUnit(),
cacheTemplate.heapStoreSettings().getMaxObjectGraphSize()));
}
final String loaderWriter = cacheTemplate.loaderWriter();
if(loaderWriter!= null) {
final Class<CacheLoaderWriter<?, ?>> cacheLoaderWriterClass = (Class<CacheLoaderWriter<?,?>>)getClassForName(loaderWriter, defaultClassLoader);
builder = builder.add(new DefaultCacheLoaderWriterConfiguration(cacheLoaderWriterClass));
if(cacheTemplate.writeBehind() != null) {
WriteBehind writeBehind = cacheTemplate.writeBehind();
WriteBehindConfigurationBuilder writeBehindConfigurationBuilder;
if (writeBehind.batching() == null) {
writeBehindConfigurationBuilder = WriteBehindConfigurationBuilder.newUnBatchedWriteBehindConfiguration();
} else {
Batching batching = writeBehind.batching();
writeBehindConfigurationBuilder = WriteBehindConfigurationBuilder.newBatchedWriteBehindConfiguration(batching.maxDelay(), batching.maxDelayUnit(), batching.batchSize());
if (batching.isCoalesced()) {
writeBehindConfigurationBuilder = ((BatchedWriteBehindConfigurationBuilder) writeBehindConfigurationBuilder).enableCoalescing();
}
}
builder = builder.add(writeBehindConfigurationBuilder
.concurrencyLevel(writeBehind.concurrency())
.queueSize(writeBehind.maxQueueSize()));
}
}
builder = handleListenersConfig(cacheTemplate.listenersConfig(), defaultClassLoader, builder);
for (ServiceConfiguration<?> serviceConfiguration : cacheTemplate.serviceConfigs()) {
builder = builder.add(serviceConfiguration);
}
return builder;
}
private <K, V> CacheConfigurationBuilder<K, V> handleListenersConfig(ConfigurationParser.ListenersConfig listenersConfig, ClassLoader defaultClassLoader, CacheConfigurationBuilder<K, V> builder) throws ClassNotFoundException {
if(listenersConfig != null) {
if (listenersConfig.threadPool() != null) {
builder = builder.add(new DefaultCacheEventDispatcherConfiguration(listenersConfig.threadPool()));
}
if (listenersConfig.listeners() != null) {
for (ConfigurationParser.Listener listener : listenersConfig.listeners()) {
@SuppressWarnings("unchecked")
final Class<CacheEventListener<?, ?>> cacheEventListenerClass = (Class<CacheEventListener<?, ?>>)getClassForName(listener.className(), defaultClassLoader);
final List<EventType> eventListToFireOn = listener.fireOn();
Set<org.ehcache.event.EventType> eventSetToFireOn = new HashSet<org.ehcache.event.EventType>();
for (EventType events : eventListToFireOn) {
switch (events) {
case CREATED:
eventSetToFireOn.add(org.ehcache.event.EventType.CREATED);
break;
case EVICTED:
eventSetToFireOn.add(org.ehcache.event.EventType.EVICTED);
break;
case EXPIRED:
eventSetToFireOn.add(org.ehcache.event.EventType.EXPIRED);
break;
case UPDATED:
eventSetToFireOn.add(org.ehcache.event.EventType.UPDATED);
break;
case REMOVED:
eventSetToFireOn.add(org.ehcache.event.EventType.REMOVED);
break;
default:
throw new IllegalArgumentException("Invalid Event Type provided");
}
}
CacheEventListenerConfigurationBuilder listenerBuilder = CacheEventListenerConfigurationBuilder
.newEventListenerConfiguration(cacheEventListenerClass, eventSetToFireOn)
.firingMode(EventFiring.valueOf(listener.eventFiring().value()))
.eventOrdering(EventOrdering.valueOf(listener.eventOrdering().value()));
builder = builder.add(listenerBuilder);
}
}
}
return builder;
}
@Override
public Map<String, CacheConfiguration<?, ?>> getCacheConfigurations() {
return cacheConfigurations;
}
@Override
public Collection<ServiceCreationConfiguration<?>> getServiceCreationConfigurations() {
return serviceConfigurations;
}
@Override
public ClassLoader getClassLoader() {
return classLoader;
}
}