/* * 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; } }