com.hazelcast.config.AbstractCacheConfig Maven / Gradle / Ivy
/*
* Copyright (c) 2008-2021, Hazelcast, Inc. All Rights Reserved.
*
* 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 com.hazelcast.config;
import com.hazelcast.cache.impl.CacheDataSerializerHook;
import com.hazelcast.cache.impl.DeferredValue;
import com.hazelcast.core.HazelcastException;
import com.hazelcast.internal.nio.ClassLoaderUtil;
import com.hazelcast.internal.serialization.SerializationService;
import com.hazelcast.nio.serialization.IdentifiedDataSerializable;
import javax.annotation.Nonnull;
import javax.cache.configuration.CacheEntryListenerConfiguration;
import javax.cache.configuration.CompleteConfiguration;
import javax.cache.configuration.Factory;
import javax.cache.expiry.EternalExpiryPolicy;
import javax.cache.expiry.ExpiryPolicy;
import javax.cache.integration.CacheLoader;
import javax.cache.integration.CacheWriter;
import java.util.Collections;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import static com.hazelcast.internal.util.Preconditions.checkNotNull;
/**
* Base class for {@link CacheConfig}
*
* @param the key type
* @param the value type
*/
@SuppressWarnings("checkstyle:methodcount")
public abstract class AbstractCacheConfig implements CacheConfiguration, IdentifiedDataSerializable {
private static final String DEFAULT_KEY_VALUE_TYPE = "java.lang.Object";
/**
* The {@link javax.cache.configuration.Factory} for the {@link javax.cache.integration.CacheLoader}.
*/
protected DeferredValue>> cacheLoaderFactory;
/**
* The {@link Factory} for the {@link javax.cache.integration.CacheWriter}.
*/
protected DeferredValue>> cacheWriterFactory;
/**
* The {@link Factory} for the {@link javax.cache.expiry.ExpiryPolicy}.
*/
protected DeferredValue> expiryPolicyFactory;
/**
* A flag indicating if "read-through" mode is required.
*/
protected boolean isReadThrough;
/**
* A flag indicating if "write-through" mode is required.
*/
protected boolean isWriteThrough;
/**
* A flag indicating if statistics gathering is enabled.
*/
protected boolean isStatisticsEnabled;
/**
* A flag indicating if the cache will be store-by-value or store-by-reference.
*/
protected boolean isStoreByValue;
/**
* Whether management is enabled
*/
protected boolean isManagementEnabled;
protected HotRestartConfig hotRestartConfig = new HotRestartConfig();
protected EventJournalConfig eventJournalConfig = new EventJournalConfig();
/**
* The ClassLoader to be used to resolve key & value types, if set
*/
protected transient ClassLoader classLoader;
protected transient SerializationService serializationService;
/**
* The {@link CacheEntryListenerConfiguration}s for the {@link javax.cache.configuration.Configuration}.
*/
protected Set>> listenerConfigurations;
/**
* The type of keys for {@link javax.cache.Cache}s configured with this
* {@link javax.cache.configuration.Configuration}.
*/
private Class keyType;
private String keyClassName = DEFAULT_KEY_VALUE_TYPE;
/**
* The type of values for {@link javax.cache.Cache}s configured with this
* {@link javax.cache.configuration.Configuration}.
*/
private Class valueType;
private String valueClassName = DEFAULT_KEY_VALUE_TYPE;
public AbstractCacheConfig() {
this.listenerConfigurations = createConcurrentSet();
this.cacheLoaderFactory = DeferredValue.withNullValue();
this.cacheWriterFactory = DeferredValue.withNullValue();
this.expiryPolicyFactory = DeferredValue.withValue(EternalExpiryPolicy.factoryOf());
this.isReadThrough = false;
this.isWriteThrough = false;
this.isStatisticsEnabled = false;
this.isStoreByValue = true;
this.isManagementEnabled = false;
}
public AbstractCacheConfig(CompleteConfiguration configuration) {
setKeyType(configuration.getKeyType());
setValueType(configuration.getValueType());
this.listenerConfigurations = createConcurrentSet();
for (CacheEntryListenerConfiguration listenerConf : configuration.getCacheEntryListenerConfigurations()) {
listenerConfigurations.add(DeferredValue.withValue(listenerConf));
}
this.cacheLoaderFactory = DeferredValue.withValue(configuration.getCacheLoaderFactory());
this.cacheWriterFactory = DeferredValue.withValue(configuration.getCacheWriterFactory());
Factory factory = configuration.getExpiryPolicyFactory();
factory = (factory == null) ? EternalExpiryPolicy.factoryOf() : factory;
this.expiryPolicyFactory = DeferredValue.withValue(factory);
this.isReadThrough = configuration.isReadThrough();
this.isWriteThrough = configuration.isWriteThrough();
this.isStatisticsEnabled = configuration.isStatisticsEnabled();
this.isStoreByValue = configuration.isStoreByValue();
this.isManagementEnabled = configuration.isManagementEnabled();
}
/**
* Add a configuration for a {@link javax.cache.event.CacheEntryListener}.
*
* @param cacheEntryListenerConfiguration the {@link CacheEntryListenerConfiguration}
* @return the {@link CacheConfig}
* @throws IllegalArgumentException if the same CacheEntryListenerConfiguration
* is used more than once
*/
@Override
public CacheConfiguration addCacheEntryListenerConfiguration(
CacheEntryListenerConfiguration cacheEntryListenerConfiguration) {
checkNotNull(cacheEntryListenerConfiguration, "CacheEntryListenerConfiguration can't be null");
if (!getListenerConfigurations().add(cacheEntryListenerConfiguration)) {
throw new IllegalArgumentException("A CacheEntryListenerConfiguration can "
+ "be registered only once");
}
return this;
}
/**
* Remove a configuration for a {@link javax.cache.event.CacheEntryListener}.
*
* @param cacheEntryListenerConfiguration the {@link CacheEntryListenerConfiguration} to remove
* @return the {@link CacheConfig}
*/
@Override
public CacheConfiguration removeCacheEntryListenerConfiguration(
CacheEntryListenerConfiguration cacheEntryListenerConfiguration) {
checkNotNull(cacheEntryListenerConfiguration, "CacheEntryListenerConfiguration can't be null");
DeferredValue> lazyConfig =
DeferredValue.withValue(cacheEntryListenerConfiguration);
listenerConfigurations.remove(lazyConfig);
return this;
}
@Override
public Iterable> getCacheEntryListenerConfigurations() {
return getListenerConfigurations();
}
@Override
public boolean isReadThrough() {
return isReadThrough;
}
@Override
public CacheConfiguration setReadThrough(boolean isReadThrough) {
this.isReadThrough = isReadThrough;
return this;
}
@Override
public boolean isWriteThrough() {
return isWriteThrough;
}
@Override
public CacheConfiguration setWriteThrough(boolean isWriteThrough) {
this.isWriteThrough = isWriteThrough;
return this;
}
@Override
public boolean isStatisticsEnabled() {
return isStatisticsEnabled;
}
/**
* Sets whether or not statistics gathering is enabled on this cache.
*
* Statistics may be enabled or disabled at runtime via {@link javax.cache.CacheManager#enableStatistics(String, boolean)}.
*
* @param enabled {@code true} to enable statistics, {@code false} to disable
* @return the {@link CacheConfig}
*/
@Override
public CacheConfiguration setStatisticsEnabled(boolean enabled) {
this.isStatisticsEnabled = enabled;
return this;
}
@Override
public boolean isManagementEnabled() {
return isManagementEnabled;
}
/**
* Sets whether or not management is enabled on this cache.
*
* Management may be enabled or disabled at runtime via {@link javax.cache.CacheManager#enableManagement(String, boolean)}.
*
* @param enabled {@code true} to enable statistics, {@code false} to disable
* @return the {@link CacheConfig}
*/
@Override
public CacheConfiguration setManagementEnabled(boolean enabled) {
this.isManagementEnabled = enabled;
return this;
}
/**
* Gets the {@code HotRestartConfig} for this {@code CacheConfiguration}
*
* @return hot restart config
*/
public @Nonnull HotRestartConfig getHotRestartConfig() {
return hotRestartConfig;
}
/**
* Sets the {@code HotRestartConfig} for this {@code CacheConfiguration}
*
* @param hotRestartConfig hot restart config
* @return this {@code CacheConfiguration} instance
*/
public CacheConfiguration setHotRestartConfig(@Nonnull HotRestartConfig hotRestartConfig) {
this.hotRestartConfig = checkNotNull(hotRestartConfig, "HotRestartConfig can't be null");
return this;
}
/**
* Gets the {@code EventJournalConfig} for this {@code CacheConfiguration}
*
* @return event journal config
*/
public @Nonnull EventJournalConfig getEventJournalConfig() {
return eventJournalConfig;
}
/**
* Sets the {@code EventJournalConfig} for this {@code CacheConfiguration}
*
* @param eventJournalConfig event journal config
* @return this {@code CacheConfiguration} instance
*/
public CacheConfiguration setEventJournalConfig(@Nonnull EventJournalConfig eventJournalConfig) {
this.eventJournalConfig = checkNotNull(eventJournalConfig, "eventJournalConfig cannot be null!");
return this;
}
@Override
public Factory> getCacheLoaderFactory() {
return cacheLoaderFactory.get(serializationService);
}
@Override
public CacheConfiguration setCacheLoaderFactory(Factory extends CacheLoader> cacheLoaderFactory) {
this.cacheLoaderFactory = DeferredValue.withValue((Factory>) cacheLoaderFactory);
return this;
}
@Override
public CacheConfiguration setExpiryPolicyFactory(Factory extends ExpiryPolicy> expiryPolicyFactory) {
this.expiryPolicyFactory = DeferredValue.withValue((Factory) expiryPolicyFactory);
return this;
}
@Override
public CacheConfiguration setCacheWriterFactory(
Factory extends CacheWriter super K, ? super V>> cacheWriterFactory) {
this.cacheWriterFactory = DeferredValue.withValue((Factory>) cacheWriterFactory);
return this;
}
@Override
public Factory> getCacheWriterFactory() {
return cacheWriterFactory.get(serializationService);
}
@Override
public Factory getExpiryPolicyFactory() {
return expiryPolicyFactory.get(serializationService);
}
@Override
public Class getKeyType() {
return keyType != null ? keyType : resolveKeyType();
}
public String getKeyClassName() {
return keyClassName;
}
public CacheConfiguration setKeyClassName(String keyClassName) {
this.keyClassName = keyClassName;
return this;
}
@Override
public Class getValueType() {
return valueType != null ? valueType : resolveValueType();
}
public String getValueClassName() {
return valueClassName;
}
public CacheConfiguration setValueClassName(String valueClassName) {
this.valueClassName = valueClassName;
return this;
}
private Class resolveKeyType() {
keyType = resolve(keyClassName);
return keyType;
}
private Class resolveValueType() {
valueType = resolve(valueClassName);
return valueType;
}
private Class resolve(String className) {
Class type = null;
if (className != null) {
try {
type = ClassLoaderUtil.loadClass(classLoader, className);
} catch (ClassNotFoundException e) {
throw new HazelcastException("Could not resolve type " + className, e);
}
}
if (type == null) {
type = Object.class;
}
return type;
}
/**
* Sets the expected type of keys and values for a {@link javax.cache.Cache}
* configured with this {@link javax.cache.configuration.Configuration}.
* Setting both to {@code Object.class} means type-safety checks are not required.
*
* This is used by {@link javax.cache.CacheManager} to ensure that the key and value
* types are the same as those configured for the {@link javax.cache.Cache} prior to
* returning a requested cache from this method.
*
* Implementations may further perform type checking on mutative cache operations
* and throw a {@link ClassCastException} if these checks fail.
*
* @param keyType the expected key type
* @param valueType the expected value type
* @return the {@link CacheConfig}
* @throws NullPointerException should the key or value type be null
* @see javax.cache.CacheManager#getCache(String, Class, Class)
*/
@Override
public CacheConfiguration setTypes(Class keyType, Class valueType) {
if (keyType == null || valueType == null) {
throw new NullPointerException("keyType and/or valueType can't be null");
}
setKeyType(keyType);
setValueType(valueType);
return this;
}
@Override
public boolean isStoreByValue() {
return isStoreByValue;
}
/**
* Set if a configured cache should use store-by-value or store-by-reference
* semantics.
*
* @param storeByValue {@code true} if store-by-value is required,
* {@code false} for store-by-reference
* @return the {@link CacheConfig}
*/
@Override
public CacheConfiguration setStoreByValue(boolean storeByValue) {
this.isStoreByValue = storeByValue;
return this;
}
@Override
public int getFactoryId() {
return CacheDataSerializerHook.F_ID;
}
protected Set>> createConcurrentSet() {
return Collections.newSetFromMap(new ConcurrentHashMap>, Boolean>());
}
public CacheConfiguration setKeyType(Class keyType) {
this.keyType = keyType;
if (keyType != null) {
this.keyClassName = keyType.getName();
}
return this;
}
public CacheConfiguration setValueType(Class valueType) {
this.valueType = valueType;
if (valueType != null) {
this.valueClassName = valueType.getName();
}
return this;
}
public CacheConfiguration setListenerConfigurations() {
this.listenerConfigurations = createConcurrentSet();
return this;
}
protected CacheConfiguration setListenerConfigurations(Set> listeners) {
this.listenerConfigurations = DeferredValue.concurrentSetOfValues(listeners);
return this;
}
public Set> getListenerConfigurations() {
return DeferredValue.asPassThroughSet(listenerConfigurations, serializationService);
}
protected boolean hasListenerConfiguration() {
return listenerConfigurations != null && !listenerConfigurations.isEmpty();
}
@Override
@SuppressWarnings({"checkstyle:npathcomplexity"})
public int hashCode() {
int result = cacheLoaderFactory != null ? cacheLoaderFactory.hashCode() : 0;
result = 31 * result + listenerConfigurations.hashCode();
result = 31 * result + keyType.hashCode();
result = 31 * result + valueType.hashCode();
result = 31 * result + (cacheWriterFactory != null ? cacheWriterFactory.hashCode() : 0);
result = 31 * result + (expiryPolicyFactory != null ? expiryPolicyFactory.hashCode() : 0);
result = 31 * result + (isReadThrough ? 1 : 0);
result = 31 * result + (isWriteThrough ? 1 : 0);
result = 31 * result + (isStatisticsEnabled ? 1 : 0);
result = 31 * result + (isStoreByValue ? 1 : 0);
result = 31 * result + (isManagementEnabled ? 1 : 0);
result = 31 * result + hotRestartConfig.hashCode();
result = 31 * result + eventJournalConfig.hashCode();
return result;
}
@Override
@SuppressWarnings({"checkstyle:cyclomaticcomplexity", "checkstyle:npathcomplexity"})
public boolean equals(final Object o) {
if (this == o) {
return true;
}
if (o == null || !(o instanceof AbstractCacheConfig)) {
return false;
}
AbstractCacheConfig that = (AbstractCacheConfig) o;
if (isManagementEnabled != that.isManagementEnabled) {
return false;
}
if (isReadThrough != that.isReadThrough) {
return false;
}
if (isStatisticsEnabled != that.isStatisticsEnabled) {
return false;
}
if (isStoreByValue != that.isStoreByValue) {
return false;
}
if (isWriteThrough != that.isWriteThrough) {
return false;
}
Factory> thisCacheLoaderFactory = this.getCacheLoaderFactory();
Factory> thatCacheLoaderFactory = that.getCacheLoaderFactory();
if (thisCacheLoaderFactory != null ? !thisCacheLoaderFactory.equals(thatCacheLoaderFactory)
: thatCacheLoaderFactory != null) {
return false;
}
Factory> thisCacheWriterFactory = this.getCacheWriterFactory();
Factory> thatCacheWriterFactory = that.getCacheWriterFactory();
if (thisCacheWriterFactory != null ? !thisCacheWriterFactory.equals(thatCacheWriterFactory)
: thatCacheWriterFactory != null) {
return false;
}
Factory thisExpiryPolicyFactory = this.getExpiryPolicyFactory();
Factory thatExpiryPolicyFactory = that.getExpiryPolicyFactory();
if (thisExpiryPolicyFactory != null
? !thisExpiryPolicyFactory.equals(thatExpiryPolicyFactory) : thatExpiryPolicyFactory != null) {
return false;
}
Set> thisListenerConfigs = this.getListenerConfigurations();
Set> thatListenerConfigs = that.getListenerConfigurations();
if (!thisListenerConfigs.equals(thatListenerConfigs)) {
return false;
}
if (!eventJournalConfig.equals(that.eventJournalConfig)) {
return false;
}
if (!hotRestartConfig.equals(that.hotRestartConfig)) {
return false;
}
return keyValueTypesEqual(that);
}
protected void setClassLoader(ClassLoader classLoader) {
this.classLoader = classLoader;
}
@SuppressWarnings("checkstyle:illegaltype")
protected boolean keyValueTypesEqual(AbstractCacheConfig that) {
if (!getKeyType().equals(that.getKeyType())) {
return false;
}
if (!getValueType().equals(that.getValueType())) {
return false;
}
return true;
}
void setSerializationService(SerializationService serializationService) {
this.serializationService = serializationService;
}
}