org.ehcache.jsr107.ConfigurationMerger 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
End-user ehcache3 jar artifact
/*
* 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.jsr107;
import org.ehcache.config.CacheConfiguration;
import org.ehcache.config.builders.CacheConfigurationBuilder;
import org.ehcache.core.InternalCache;
import org.ehcache.core.spi.service.ServiceUtils;
import org.ehcache.impl.config.copy.DefaultCopierConfiguration;
import org.ehcache.impl.config.copy.DefaultCopyProviderConfiguration;
import org.ehcache.impl.config.loaderwriter.DefaultCacheLoaderWriterConfiguration;
import org.ehcache.impl.internal.classes.ClassInstanceConfiguration;
import org.ehcache.impl.copy.SerializingCopier;
import org.ehcache.jsr107.config.ConfigurationElementState;
import org.ehcache.jsr107.config.Jsr107CacheConfiguration;
import org.ehcache.jsr107.config.Jsr107Service;
import org.ehcache.jsr107.internal.Jsr107CacheLoaderWriter;
import org.ehcache.spi.copy.Copier;
import org.ehcache.xml.XmlConfiguration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import javax.cache.configuration.CacheEntryListenerConfiguration;
import javax.cache.configuration.CompleteConfiguration;
import javax.cache.configuration.Configuration;
import javax.cache.configuration.Factory;
import javax.cache.integration.CacheLoader;
import javax.cache.integration.CacheWriter;
import static org.ehcache.config.builders.CacheConfigurationBuilder.newCacheConfigurationBuilder;
import static org.ehcache.config.builders.ResourcePoolsBuilder.heap;
import static org.ehcache.core.spi.service.ServiceUtils.findSingletonAmongst;
/**
* ConfigurationMerger
*/
class ConfigurationMerger {
private static final Logger LOG = LoggerFactory.getLogger(ConfigurationMerger.class);
private final XmlConfiguration xmlConfiguration;
private final Jsr107Service jsr107Service;
private final Eh107CacheLoaderWriterProvider cacheLoaderWriterFactory;
ConfigurationMerger(org.ehcache.config.Configuration ehConfig, Jsr107Service jsr107Service, Eh107CacheLoaderWriterProvider cacheLoaderWriterFactory) {
if (ehConfig instanceof XmlConfiguration) {
xmlConfiguration = (XmlConfiguration) ehConfig;
} else {
xmlConfiguration = null;
}
this.jsr107Service = jsr107Service;
this.cacheLoaderWriterFactory = cacheLoaderWriterFactory;
}
ConfigHolder mergeConfigurations(String cacheName, Configuration configuration) {
final Eh107CompleteConfiguration jsr107Configuration = new Eh107CompleteConfiguration<>(configuration);
Eh107Expiry expiryPolicy = null;
Jsr107CacheLoaderWriter super K, V> loaderWriter = null;
try {
CacheConfigurationBuilder builder = newCacheConfigurationBuilder(configuration.getKeyType(), configuration.getValueType(), heap(Long.MAX_VALUE));
String templateName = jsr107Service.getTemplateNameForCache(cacheName);
if (xmlConfiguration != null && templateName != null) {
CacheConfigurationBuilder templateBuilder;
try {
templateBuilder = xmlConfiguration.newCacheConfigurationBuilderFromTemplate(templateName,
jsr107Configuration.getKeyType(), jsr107Configuration.getValueType());
} catch (IllegalStateException e) {
templateBuilder = xmlConfiguration.newCacheConfigurationBuilderFromTemplate(templateName,
jsr107Configuration.getKeyType(), jsr107Configuration.getValueType(), heap(Long.MAX_VALUE));
}
if (templateBuilder != null) {
builder = templateBuilder;
LOG.info("Configuration of cache {} will be supplemented by template {}", cacheName, templateName);
}
}
builder = handleStoreByValue(jsr107Configuration, builder, cacheName);
final boolean hasConfiguredExpiry = builder.hasConfiguredExpiry();
if (hasConfiguredExpiry) {
LOG.info("Cache {} will use expiry configuration from template {}", cacheName, templateName);
} else {
expiryPolicy = initExpiryPolicy(jsr107Configuration);
builder = builder.withExpiry(expiryPolicy);
}
boolean useEhcacheLoaderWriter;
DefaultCacheLoaderWriterConfiguration ehcacheLoaderWriterConfiguration = builder.getExistingServiceConfiguration(DefaultCacheLoaderWriterConfiguration.class);
if (ehcacheLoaderWriterConfiguration == null) {
useEhcacheLoaderWriter = false;
// No template loader/writer - let's activate the JSR-107 one if any
loaderWriter = initCacheLoaderWriter(jsr107Configuration, new MultiCacheException());
if (loaderWriter != null && (jsr107Configuration.isReadThrough() || jsr107Configuration.isWriteThrough())) {
cacheLoaderWriterFactory.registerJsr107Loader(cacheName, loaderWriter);
}
} else {
useEhcacheLoaderWriter = true;
if (!jsr107Configuration.isReadThrough() && !jsr107Configuration.isWriteThrough()) {
LOG.warn("Activating Ehcache loader/writer for JSR-107 cache {} which was neither read-through nor write-through", cacheName);
}
LOG.info("Cache {} will use loader/writer configuration from template {}", cacheName, templateName);
}
CacheConfiguration cacheConfiguration = builder.build();
setupManagementAndStatsInternal(jsr107Configuration, findSingletonAmongst(Jsr107CacheConfiguration.class, cacheConfiguration.getServiceConfigurations()));
if (hasConfiguredExpiry) {
expiryPolicy = new EhcacheExpiryWrapper<>(cacheConfiguration.getExpiryPolicy());
}
return new ConfigHolder<>(
new CacheResources<>(cacheName, loaderWriter, expiryPolicy, initCacheEventListeners(jsr107Configuration)),
new Eh107CompleteConfiguration<>(jsr107Configuration, cacheConfiguration, hasConfiguredExpiry, useEhcacheLoaderWriter),
cacheConfiguration, useEhcacheLoaderWriter);
} catch (Throwable throwable) {
MultiCacheException mce = new MultiCacheException();
CacheResources.close(expiryPolicy, mce);
CacheResources.close(loaderWriter, mce);
if (throwable instanceof IllegalArgumentException) {
String message = throwable.getMessage();
if (mce.getMessage() != null) {
message = message + "\nSuppressed " + mce.getMessage();
}
throw new IllegalArgumentException(message, throwable);
}
mce.addFirstThrowable(throwable);
throw mce;
}
}
private CacheConfigurationBuilder handleStoreByValue(Eh107CompleteConfiguration jsr107Configuration, CacheConfigurationBuilder builder, String cacheName) {
DefaultCopierConfiguration copierConfig = builder.getExistingServiceConfiguration(DefaultCopierConfiguration.class);
if(copierConfig == null) {
if(jsr107Configuration.isStoreByValue()) {
if (xmlConfiguration != null) {
DefaultCopyProviderConfiguration defaultCopyProviderConfiguration = findSingletonAmongst(DefaultCopyProviderConfiguration.class,
xmlConfiguration.getServiceCreationConfigurations().toArray());
if (defaultCopyProviderConfiguration != null) {
Map, ClassInstanceConfiguration>> defaults = defaultCopyProviderConfiguration.getDefaults();
handleCopierDefaultsforImmutableTypes(defaults);
boolean matchingDefault = false;
if (defaults.containsKey(jsr107Configuration.getKeyType())) {
matchingDefault = true;
} else {
builder = builder.add(new DefaultCopierConfiguration<>(SerializingCopier.asCopierClass(), DefaultCopierConfiguration.Type.KEY));
}
if (defaults.containsKey(jsr107Configuration.getValueType())) {
matchingDefault = true;
} else {
builder = builder.add(new DefaultCopierConfiguration<>(SerializingCopier.asCopierClass(), DefaultCopierConfiguration.Type.VALUE));
}
if (matchingDefault) {
LOG.info("CacheManager level copier configuration overwriting JSR-107 by-value semantics for cache {}", cacheName);
}
return builder;
}
}
builder = addDefaultCopiers(builder, jsr107Configuration.getKeyType(), jsr107Configuration.getValueType());
LOG.debug("Using default Copier for JSR-107 store-by-value cache {}", cacheName);
}
} else {
LOG.info("Cache level copier configuration overwriting JSR-107 by-value semantics for cache {}", cacheName);
}
return builder;
}
@SuppressWarnings("unchecked")
private static CacheConfigurationBuilder addDefaultCopiers(CacheConfigurationBuilder builder, Class keyType, Class valueType ) {
Set immutableTypes = new HashSet<>();
immutableTypes.add(String.class);
immutableTypes.add(Long.class);
immutableTypes.add(Float.class);
immutableTypes.add(Double.class);
immutableTypes.add(Character.class);
immutableTypes.add(Integer.class);
if (immutableTypes.contains(keyType)) {
builder = builder.add(new DefaultCopierConfiguration((Class)Eh107IdentityCopier.class, DefaultCopierConfiguration.Type.KEY));
} else {
builder = builder.add(new DefaultCopierConfiguration<>(SerializingCopier.asCopierClass(), DefaultCopierConfiguration.Type.KEY));
}
if (immutableTypes.contains(valueType)) {
builder = builder.add(new DefaultCopierConfiguration((Class)Eh107IdentityCopier.class, DefaultCopierConfiguration.Type.VALUE));
} else {
builder = builder.add(new DefaultCopierConfiguration<>(SerializingCopier.asCopierClass(), DefaultCopierConfiguration.Type.VALUE));
}
return builder;
}
private static void handleCopierDefaultsforImmutableTypes(Map, ClassInstanceConfiguration>> defaults) {
addIdentityCopierIfNoneRegistered(defaults, Long.class);
addIdentityCopierIfNoneRegistered(defaults, Integer.class);
addIdentityCopierIfNoneRegistered(defaults, String.class);
addIdentityCopierIfNoneRegistered(defaults, Float.class);
addIdentityCopierIfNoneRegistered(defaults, Double.class);
addIdentityCopierIfNoneRegistered(defaults, Character.class);
}
@SuppressWarnings("unchecked")
private static void addIdentityCopierIfNoneRegistered(Map, ClassInstanceConfiguration>> defaults, Class> clazz) {
if (!defaults.containsKey(clazz)) {
defaults.put(clazz, new DefaultCopierConfiguration(Eh107IdentityCopier.class, DefaultCopierConfiguration.Type.VALUE));
}
}
private Map, ListenerResources> initCacheEventListeners(CompleteConfiguration config) {
Map, ListenerResources> listenerResources = new ConcurrentHashMap<>();
MultiCacheException mce = new MultiCacheException();
for (CacheEntryListenerConfiguration listenerConfig : config.getCacheEntryListenerConfigurations()) {
listenerResources.put(listenerConfig, ListenerResources.createListenerResources(listenerConfig, mce));
}
return listenerResources;
}
private Eh107Expiry initExpiryPolicy(CompleteConfiguration config) {
return new ExpiryPolicyToEhcacheExpiry<>(config.getExpiryPolicyFactory().create());
}
private Jsr107CacheLoaderWriter initCacheLoaderWriter(CompleteConfiguration config, MultiCacheException mce) {
Factory> cacheLoaderFactory = config.getCacheLoaderFactory();
@SuppressWarnings("unchecked")
Factory> cacheWriterFactory = (Factory>) (Object) config.getCacheWriterFactory();
if (config.isReadThrough() && cacheLoaderFactory == null) {
throw new IllegalArgumentException("read-through enabled without a CacheLoader factory provided");
}
if (config.isWriteThrough() && cacheWriterFactory == null) {
throw new IllegalArgumentException("write-through enabled without a CacheWriter factory provided");
}
CacheLoader cacheLoader = cacheLoaderFactory == null ? null : cacheLoaderFactory.create();
CacheWriter cacheWriter;
try {
cacheWriter = cacheWriterFactory == null ? null : cacheWriterFactory.create();
} catch (Throwable t) {
if (t != mce) {
mce.addThrowable(t);
}
CacheResources.close(cacheLoader, mce);
throw mce;
}
if (cacheLoader == null && cacheWriter == null) {
return null;
} else {
return new Eh107CacheLoaderWriter<>(cacheLoader, config.isReadThrough(), cacheWriter, config.isWriteThrough());
}
}
void setUpManagementAndStats(InternalCache, ?> cache, Eh107Configuration, ?> configuration) {
Jsr107CacheConfiguration cacheConfiguration = ServiceUtils.findSingletonAmongst(Jsr107CacheConfiguration.class, cache
.getRuntimeConfiguration().getServiceConfigurations());
setupManagementAndStatsInternal(configuration, cacheConfiguration);
}
private void setupManagementAndStatsInternal(Eh107Configuration, ?> configuration, Jsr107CacheConfiguration cacheConfiguration) {
ConfigurationElementState enableManagement = jsr107Service.isManagementEnabledOnAllCaches();
ConfigurationElementState enableStatistics = jsr107Service.isStatisticsEnabledOnAllCaches();
if (cacheConfiguration != null) {
ConfigurationElementState managementEnabled = cacheConfiguration.isManagementEnabled();
if (managementEnabled != null && managementEnabled != ConfigurationElementState.UNSPECIFIED) {
enableManagement = managementEnabled;
}
ConfigurationElementState statisticsEnabled = cacheConfiguration.isStatisticsEnabled();
if (statisticsEnabled != null && statisticsEnabled != ConfigurationElementState.UNSPECIFIED) {
enableStatistics = statisticsEnabled;
}
}
if (enableManagement != null && enableManagement != ConfigurationElementState.UNSPECIFIED) {
configuration.setManagementEnabled(enableManagement.asBoolean());
}
if (enableStatistics != null && enableStatistics != ConfigurationElementState.UNSPECIFIED) {
configuration.setStatisticsEnabled(enableStatistics.asBoolean());
}
}
static class ConfigHolder {
final CacheResources cacheResources;
final CacheConfiguration cacheConfiguration;
final Eh107CompleteConfiguration jsr107Configuration;
final boolean useEhcacheLoaderWriter;
public ConfigHolder(CacheResources cacheResources, Eh107CompleteConfiguration jsr107Configuration, CacheConfiguration cacheConfiguration, boolean useEhcacheLoaderWriter) {
this.cacheResources = cacheResources;
this.jsr107Configuration = jsr107Configuration;
this.cacheConfiguration = cacheConfiguration;
this.useEhcacheLoaderWriter = useEhcacheLoaderWriter;
}
}
}