/*
* Copyright (c) 2008-2017, 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.config.CacheSimpleConfig.ExpiryPolicyFactoryConfig;
import com.hazelcast.config.CacheSimpleConfig.ExpiryPolicyFactoryConfig.DurationConfig;
import com.hazelcast.config.CacheSimpleConfig.ExpiryPolicyFactoryConfig.TimedExpiryPolicyFactoryConfig;
import com.hazelcast.core.HazelcastException;
import com.hazelcast.util.CollectionUtil;
import org.apache.commons.lang3.ArrayUtils;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import static java.text.MessageFormat.format;
class ConfigCompatibilityChecker {
/**
* Checks if two {@link Config}'s are compatible. This mostly means that the config values will have the same
* impact on the behaviour of the system but are not necessarily the same (e.g. null value is sometimes the same
* as an empty collection or a disabled config).
* NOTE: This method checks MOST but NOT ALL configuration. As such it is best used in test scenarios to cover
* as much config checks as possible automatically.
*
* @param c1 the {@link Config} to check
* @param c2 the {@link Config} to check
* @return {@code true} if the configs are compatible
* @throws HazelcastException if configs are incompatible
* @throws IllegalArgumentException if one of the configs is {@code null}
*/
static boolean isCompatible(final Config c1, final Config c2) {
if (c1 == c2) {
return true;
}
if (c1 == null || c2 == null) {
throw new IllegalArgumentException("One of the two configs is null");
}
if (!nullSafeEqual(c1.getGroupConfig().getName(), c2.getGroupConfig().getName())) {
return false;
}
if (!nullSafeEqual(c1.getGroupConfig().getPassword(), c2.getGroupConfig().getPassword())) {
throw new HazelcastException("Incompatible group password");
}
checkWanConfigs(c1.getWanReplicationConfigs(), c2.getWanReplicationConfigs());
checkCompatibleConfigs("partition group", c1.getPartitionGroupConfig(), c2.getPartitionGroupConfig(), new PartitionGroupConfigChecker());
checkCompatibleConfigs("serialization", c1.getSerializationConfig(), c2.getSerializationConfig(), new SerializationConfigChecker());
checkCompatibleConfigs("services", c1.getServicesConfig(), c2.getServicesConfig(), new ServicesConfigChecker());
checkCompatibleConfigs("management center", c1.getManagementCenterConfig(), c2.getManagementCenterConfig(), new ManagementCenterConfigChecker());
checkCompatibleConfigs("hot restart", c1.getHotRestartPersistenceConfig(), c2.getHotRestartPersistenceConfig(), new HotRestartConfigChecker());
checkCompatibleConfigs("network", c1.getNetworkConfig(), c2.getNetworkConfig(), new NetworkConfigChecker());
checkCompatibleConfigs("map", c1, c2, c1.getMapConfigs(), c2.getMapConfigs(), new MapConfigChecker());
checkCompatibleConfigs("ringbuffer", c1, c2, c1.getRingbufferConfigs(), c2.getRingbufferConfigs(), new RingbufferConfigChecker());
checkCompatibleConfigs("queue", c1, c2, c1.getQueueConfigs(), c2.getQueueConfigs(), new QueueConfigChecker());
checkCompatibleConfigs("semaphore", c1, c2, getSemaphoreConfigsByName(c1), getSemaphoreConfigsByName(c2), new SemaphoreConfigChecker());
checkCompatibleConfigs("lock", c1, c2, c1.getLockConfigs(), c2.getLockConfigs(), new LockConfigChecker());
checkCompatibleConfigs("topic", c1, c2, c1.getTopicConfigs(), c2.getTopicConfigs(), new TopicConfigChecker());
checkCompatibleConfigs("reliable topic", c1, c2, c1.getReliableTopicConfigs(), c2.getReliableTopicConfigs(), new ReliableTopicConfigChecker());
checkCompatibleConfigs("cache", c1, c2, c1.getCacheConfigs(), c2.getCacheConfigs(), new CacheSimpleConfigChecker());
checkCompatibleConfigs("executor", c1, c2, c1.getExecutorConfigs(), c2.getExecutorConfigs(), new ExecutorConfigChecker());
checkCompatibleConfigs("durable executor", c1, c2, c1.getDurableExecutorConfigs(), c2.getDurableExecutorConfigs(), new DurableExecutorConfigChecker());
checkCompatibleConfigs("scheduled executor", c1, c2, c1.getScheduledExecutorConfigs(), c2.getScheduledExecutorConfigs(), new ScheduledExecutorConfigChecker());
checkCompatibleConfigs("multimap", c1, c2, c1.getMultiMapConfigs(), c2.getMultiMapConfigs(), new MultimapConfigChecker());
checkCompatibleConfigs("list", c1, c2, c1.getListConfigs(), c2.getListConfigs(), new ListConfigChecker());
checkCompatibleConfigs("set", c1, c2, c1.getSetConfigs(), c2.getSetConfigs(), new SetConfigChecker());
checkCompatibleConfigs("job tracker", c1, c2, c1.getJobTrackerConfigs(), c2.getJobTrackerConfigs(), new JobTrackerConfigChecker());
return true;
}
public static void checkWanConfigs(Map<String, WanReplicationConfig> c1, Map<String, WanReplicationConfig> c2) {
if ((c1 != c2 && (c1 == null || c2 == null)) || c1.size() != c2.size()) {
throw new HazelcastException(format("Incompatible wan replication config :\n{0}\n vs \n{1}", c1, c2));
}
final WanReplicationConfigChecker checker = new WanReplicationConfigChecker();
for (Entry<String, WanReplicationConfig> entry : c1.entrySet()) {
checkCompatibleConfigs("wan replication", entry.getValue(), c2.get(entry.getKey()), checker);
}
}
private static Map<String, SemaphoreConfig> getSemaphoreConfigsByName(Config c) {
final Collection<SemaphoreConfig> semaphoreConfigs = c.getSemaphoreConfigs();
final HashMap<String, SemaphoreConfig> configsByName = new HashMap<String, SemaphoreConfig>(semaphoreConfigs.size());
for (SemaphoreConfig config : semaphoreConfigs) {
configsByName.put(config.getName(), config);
}
return configsByName;
}
private static <T> void checkCompatibleConfigs(String type, T c1, T c2, ConfigChecker<T> checker) {
if (!checker.check(c1, c2)) {
throw new HazelcastException(format("Incompatible " + type + " config :\n{0}\n vs \n{1}", c1, c2));
}
}
private static <T> void checkCompatibleConfigs(
String type, Config c1, Config c2,
Map<String, T> configs1, Map<String, T> configs2, ConfigChecker<T> checker) {
final Set<String> configNames = new HashSet<String>(configs1.keySet());
configNames.addAll(configs2.keySet());
for (final String name : configNames) {
final T config1 = c1.lookupByPattern(configs1, name);
final T config2 = c2.lookupByPattern(configs2, name);
if (config1 != null && config2 != null && !checker.check(config1, config2)) {
throw new HazelcastException(format("Incompatible " + type + " config :\n{0}\n vs \n{1}",
config1, config2));
}
}
final T config1 = checker.getDefault(c1);
final T config2 = checker.getDefault(c2);
if (!checker.check(config1, config2)) {
throw new HazelcastException(format("Incompatible default " + type + " config :\n{0}\n vs \n{1}",
config1, config2));
}
}
private abstract static class ConfigChecker<T> {
abstract boolean check(T t1, T t2);
T getDefault(Config c) {
return null;
}
}
private static boolean nullSafeEqual(Object a, Object b) {
return (a == b) || (a != null && a.equals(b));
}
private static <T> boolean isCollectionCompatible(Collection<T> c1, Collection<T> c2, ConfigChecker<T> checker) {
if (c1 == c2) {
return true;
}
if (c1 == null || c2 == null || c1.size() != c2.size()) {
return false;
}
final Iterator<T> i1 = c1.iterator();
final Iterator<T> i2 = c2.iterator();
while (i1.hasNext() && i2.hasNext()) {
final T config1 = i1.next();
final T config2 = i2.next();
if (!checker.check(config1, config2)) {
return false;
}
}
return !(i1.hasNext() || i2.hasNext());
}
private static boolean isCompatible(HotRestartConfig c1, HotRestartConfig c2) {
final boolean c1Disabled = c1 == null || !c1.isEnabled();
final boolean c2Disabled = c2 == null || !c2.isEnabled();
return c1 == c2 || (c1Disabled && c2Disabled) ||
(c1 != null && c2 != null && nullSafeEqual(c1.isFsync(), c2.isFsync()));
}
// CONFIG CHECKERS
private static class RingbufferConfigChecker extends ConfigChecker<RingbufferConfig> {
@Override
boolean check(RingbufferConfig c1, RingbufferConfig c2) {
return c1 == c2 || !(c1 == null || c2 == null)
&& nullSafeEqual(c1.getName(), c2.getName())
&& nullSafeEqual(c1.getBackupCount(), c2.getBackupCount())
&& nullSafeEqual(c1.getAsyncBackupCount(), c2.getAsyncBackupCount())
&& nullSafeEqual(c1.getCapacity(), c2.getCapacity())
&& nullSafeEqual(c1.getTimeToLiveSeconds(), c2.getTimeToLiveSeconds())
&& nullSafeEqual(c1.getInMemoryFormat(), c2.getInMemoryFormat())
&& isCompatible(c1.getRingbufferStoreConfig(), c2.getRingbufferStoreConfig());
}
private static boolean isCompatible(RingbufferStoreConfig c1, RingbufferStoreConfig c2) {
final boolean c1Disabled = c1 == null || !c1.isEnabled();
final boolean c2Disabled = c2 == null || !c2.isEnabled();
return c1 == c2 || (c1Disabled && c2Disabled) ||
(c1 != null && c2 != null
&& nullSafeEqual(c1.getClassName(), c2.getClassName())
&& nullSafeEqual(c1.getFactoryClassName(), c2.getFactoryClassName())
&& nullSafeEqual(c1.getProperties(), c2.getProperties()));
}
@Override
RingbufferConfig getDefault(Config c) {
return c.getRingbufferConfig("default");
}
}
private static class QueueConfigChecker extends ConfigChecker<QueueConfig> {
@Override
boolean check(QueueConfig c1, QueueConfig c2) {
return c1 == c2 || !(c1 == null || c2 == null)
&& nullSafeEqual(c1.getName(), c2.getName())
&& nullSafeEqual(c1.getItemListenerConfigs(), c2.getItemListenerConfigs())
&& nullSafeEqual(c1.getBackupCount(), c2.getBackupCount())
&& nullSafeEqual(c1.getAsyncBackupCount(), c2.getAsyncBackupCount())
&& nullSafeEqual(c1.getMaxSize(), c2.getMaxSize())
&& nullSafeEqual(c1.getEmptyQueueTtl(), c2.getEmptyQueueTtl())
&& isCompatible(c1.getQueueStoreConfig(), c2.getQueueStoreConfig())
&& nullSafeEqual(c1.isStatisticsEnabled(), c2.isStatisticsEnabled())
&& nullSafeEqual(c1.getQuorumName(), c2.getQuorumName());
}
private static boolean isCompatible(QueueStoreConfig c1, QueueStoreConfig c2) {
final boolean c1Disabled = c1 == null || !c1.isEnabled();
final boolean c2Disabled = c2 == null || !c2.isEnabled();
return c1 == c2 || (c1Disabled && c2Disabled) ||
(c1 != null && c2 != null
&& nullSafeEqual(c1.getClassName(), c2.getClassName())
&& nullSafeEqual(c1.getFactoryClassName(), c2.getFactoryClassName())
&& nullSafeEqual(c1.getProperties(), c2.getProperties()));
}
@Override
QueueConfig getDefault(Config c) {
return c.getQueueConfig("default");
}
}
private static class SemaphoreConfigChecker extends ConfigChecker<SemaphoreConfig> {
@Override
boolean check(SemaphoreConfig c1, SemaphoreConfig c2) {
return c1 == c2 || !(c1 == null || c2 == null)
&& nullSafeEqual(c1.getName(), c2.getName())
&& nullSafeEqual(c1.getBackupCount(), c2.getBackupCount())
&& nullSafeEqual(c1.getAsyncBackupCount(), c2.getAsyncBackupCount())
&& nullSafeEqual(c1.getInitialPermits(), c2.getInitialPermits());
}
@Override
SemaphoreConfig getDefault(Config c) {
return c.getSemaphoreConfig("default");
}
}
private static class LockConfigChecker extends ConfigChecker<LockConfig> {
@Override
boolean check(LockConfig c1, LockConfig c2) {
return c1 == c2 || !(c1 == null || c2 == null)
&& nullSafeEqual(c1.getName(), c2.getName())
&& nullSafeEqual(c1.getQuorumName(), c2.getQuorumName());
}
@Override
LockConfig getDefault(Config c) {
return c.getLockConfig("default");
}
}
private static class SetConfigChecker extends ConfigChecker<SetConfig> {
@Override
boolean check(SetConfig c1, SetConfig c2) {
return isCompatible(c1, c2);
}
@Override
SetConfig getDefault(Config c) {
return c.getSetConfig("default");
}
}
private static class ListConfigChecker extends ConfigChecker<ListConfig> {
@Override
boolean check(ListConfig c1, ListConfig c2) {
return isCompatible(c1, c2);
}
@Override
ListConfig getDefault(Config c) {
return c.getListConfig("default");
}
}
private static boolean isCompatible(CollectionConfig c1, CollectionConfig c2) {
return c1 == c2 || !(c1 == null || c2 == null)
&& nullSafeEqual(c1.getName(), c2.getName())
&& nullSafeEqual(c1.getItemListenerConfigs(), c2.getItemListenerConfigs())
&& nullSafeEqual(c1.getBackupCount(), c2.getBackupCount())
&& nullSafeEqual(c1.getAsyncBackupCount(), c2.getAsyncBackupCount())
&& nullSafeEqual(c1.getMaxSize(), c2.getMaxSize())
&& nullSafeEqual(c1.isStatisticsEnabled(), c2.isStatisticsEnabled());
}
private static class TopicConfigChecker extends ConfigChecker<TopicConfig> {
@Override
boolean check(TopicConfig c1, TopicConfig c2) {
return c1 == c2 || !(c1 == null || c2 == null)
&& nullSafeEqual(c1.getName(), c2.getName())
&& nullSafeEqual(c1.isGlobalOrderingEnabled(), c2.isGlobalOrderingEnabled())
&& nullSafeEqual(c1.isStatisticsEnabled(), c2.isStatisticsEnabled())
&& nullSafeEqual(c1.isMultiThreadingEnabled(), c2.isMultiThreadingEnabled())
&& nullSafeEqual(c1.getMessageListenerConfigs(), c2.getMessageListenerConfigs());
}
@Override
TopicConfig getDefault(Config c) {
return c.getTopicConfig("default");
}
}
private static class ReliableTopicConfigChecker extends ConfigChecker<ReliableTopicConfig> {
@Override
boolean check(ReliableTopicConfig c1, ReliableTopicConfig c2) {
return c1 == c2 || !(c1 == null || c2 == null)
&& nullSafeEqual(c1.getReadBatchSize(), c2.getReadBatchSize())
&& nullSafeEqual(c1.getName(), c2.getName())
&& nullSafeEqual(c1.isStatisticsEnabled(), c2.isStatisticsEnabled())
&& nullSafeEqual(c1.getMessageListenerConfigs(), c2.getMessageListenerConfigs())
&& nullSafeEqual(c1.getTopicOverloadPolicy(), c2.getTopicOverloadPolicy());
}
@Override
ReliableTopicConfig getDefault(Config c) {
return c.getReliableTopicConfig("default");
}
}
private static class ExecutorConfigChecker extends ConfigChecker<ExecutorConfig> {
@Override
boolean check(ExecutorConfig c1, ExecutorConfig c2) {
if (c1 == c2) {
return true;
}
if (c1 == null || c2 == null) {
return false;
}
final int cap1 = c1.getQueueCapacity();
final int cap2 = c2.getQueueCapacity();
return nullSafeEqual(c1.getName(), c2.getName())
&& nullSafeEqual(c1.getPoolSize(), c2.getPoolSize())
&& (nullSafeEqual(cap1, cap2) || (Math.min(cap1, cap2) == 0 && Math.max(cap1, cap2) == Integer.MAX_VALUE))
&& nullSafeEqual(c1.isStatisticsEnabled(), c2.isStatisticsEnabled());
}
@Override
ExecutorConfig getDefault(Config c) {
return c.getExecutorConfig("default");
}
}
private static class DurableExecutorConfigChecker extends ConfigChecker<DurableExecutorConfig> {
@Override
boolean check(DurableExecutorConfig c1, DurableExecutorConfig c2) {
return c1 == c2 || !(c1 == null || c2 == null)
&& nullSafeEqual(c1.getName(), c2.getName())
&& nullSafeEqual(c1.getPoolSize(), c2.getPoolSize())
&& nullSafeEqual(c1.getDurability(), c2.getDurability())
&& nullSafeEqual(c1.getCapacity(), c2.getCapacity());
}
@Override
DurableExecutorConfig getDefault(Config c) {
return c.getDurableExecutorConfig("default");
}
}
private static class ScheduledExecutorConfigChecker extends ConfigChecker<ScheduledExecutorConfig> {
@Override
boolean check(ScheduledExecutorConfig c1, ScheduledExecutorConfig c2) {
return c1 == c2 || !(c1 == null || c2 == null)
&& nullSafeEqual(c1.getName(), c2.getName())
&& nullSafeEqual(c1.getDurability(), c2.getDurability())
&& nullSafeEqual(c1.getPoolSize(), c2.getPoolSize());
}
@Override
ScheduledExecutorConfig getDefault(Config c) {
return c.getScheduledExecutorConfig("default");
}
}
private static class MultimapConfigChecker extends ConfigChecker<MultiMapConfig> {
@Override
boolean check(MultiMapConfig c1, MultiMapConfig c2) {
return c1 == c2 || !(c1 == null || c2 == null)
&& nullSafeEqual(c1.getName(), c2.getName())
&& nullSafeEqual(c1.getValueCollectionType(), c2.getValueCollectionType())
&& nullSafeEqual(c1.getEntryListenerConfigs(), c2.getEntryListenerConfigs())
&& nullSafeEqual(c1.isBinary(), c2.isBinary())
&& nullSafeEqual(c1.getBackupCount(), c2.getBackupCount())
&& nullSafeEqual(c1.getAsyncBackupCount(), c2.getAsyncBackupCount())
&& nullSafeEqual(c1.isStatisticsEnabled(), c2.isStatisticsEnabled());
}
@Override
MultiMapConfig getDefault(Config c) {
return c.getMultiMapConfig("default");
}
}
private static class JobTrackerConfigChecker extends ConfigChecker<JobTrackerConfig> {
@Override
boolean check(JobTrackerConfig c1, JobTrackerConfig c2) {
if (c1 == c2) {
return true;
}
if (c1 == null || c2 == null) {
return false;
}
final int max1 = c1.getMaxThreadSize();
final int max2 = c2.getMaxThreadSize();
return nullSafeEqual(c1.getName(), c2.getName())
&& (nullSafeEqual(max1, max2) || (Math.min(max1, max2) == 0 && Math.max(max1, max2) == Runtime.getRuntime().availableProcessors()))
&& nullSafeEqual(c1.getRetryCount(), c2.getRetryCount())
&& nullSafeEqual(c1.getChunkSize(), c2.getChunkSize())
&& nullSafeEqual(c1.getQueueSize(), c2.getQueueSize())
&& nullSafeEqual(c1.isCommunicateStats(), c2.isCommunicateStats())
&& nullSafeEqual(c1.getTopologyChangedStrategy(), c2.getTopologyChangedStrategy());
}
@Override
JobTrackerConfig getDefault(Config c) {
return c.getJobTrackerConfig("default");
}
}
private static class CacheSimpleConfigChecker extends ConfigChecker<CacheSimpleConfig> {
@Override
boolean check(CacheSimpleConfig c1, CacheSimpleConfig c2) {
return c1 == c2 || !(c1 == null || c2 == null)
&& nullSafeEqual(c1.getName(), c2.getName())
&& nullSafeEqual(c1.getKeyType(), c2.getKeyType())
&& nullSafeEqual(c1.getValueType(), c2.getValueType())
&& nullSafeEqual(c1.isStatisticsEnabled(), c2.isStatisticsEnabled())
&& nullSafeEqual(c1.isManagementEnabled(), c2.isManagementEnabled())
&& nullSafeEqual(c1.isReadThrough(), c2.isReadThrough())
&& nullSafeEqual(c1.isWriteThrough(), c2.isWriteThrough())
&& nullSafeEqual(c1.getCacheLoaderFactory(), c2.getCacheLoaderFactory())
&& nullSafeEqual(c1.getCacheWriterFactory(), c2.getCacheWriterFactory())
&& nullSafeEqual(c1.getCacheLoader(), c2.getCacheLoader())
&& nullSafeEqual(c1.getCacheWriter(), c2.getCacheWriter())
&& isCompatible(c1.getExpiryPolicyFactoryConfig(), c2.getExpiryPolicyFactoryConfig())
&& isCollectionCompatible(c1.getCacheEntryListeners(), c2.getCacheEntryListeners(), new CacheSimpleEntryListenerConfigChecker())
&& nullSafeEqual(c1.getAsyncBackupCount(), c2.getAsyncBackupCount())
&& nullSafeEqual(c1.getBackupCount(), c2.getBackupCount())
&& nullSafeEqual(c1.getInMemoryFormat(), c2.getInMemoryFormat())
&& isCompatible(c1.getEvictionConfig(), c2.getEvictionConfig())
&& isCompatible(c1.getWanReplicationRef(), c2.getWanReplicationRef())
&& nullSafeEqual(c1.getQuorumName(), c2.getQuorumName())
&& nullSafeEqual(c1.getPartitionLostListenerConfigs(), c2.getPartitionLostListenerConfigs())
&& nullSafeEqual(c1.getMergePolicy(), c2.getMergePolicy())
&& ConfigCompatibilityChecker.isCompatible(c1.getHotRestartConfig(), c2.getHotRestartConfig());
}
private static boolean isCompatible(ExpiryPolicyFactoryConfig c1, ExpiryPolicyFactoryConfig c2) {
return c1 == c2 || !(c1 == null || c2 == null)
&& nullSafeEqual(c1.getClassName(), c2.getClassName())
&& isCompatible(c1.getTimedExpiryPolicyFactoryConfig(), c2.getTimedExpiryPolicyFactoryConfig());
}
private static boolean isCompatible(TimedExpiryPolicyFactoryConfig c1, TimedExpiryPolicyFactoryConfig c2) {
return c1 == c2 || !(c1 == null || c2 == null)
&& nullSafeEqual(c1.getExpiryPolicyType(), c2.getExpiryPolicyType())
&& isCompatible(c1.getDurationConfig(), c2.getDurationConfig());
}
private static boolean isCompatible(DurationConfig c1, DurationConfig c2) {
return c1 == c2 || !(c1 == null || c2 == null)
&& nullSafeEqual(c1.getDurationAmount(), c2.getDurationAmount())
&& nullSafeEqual(c1.getTimeUnit(), c2.getTimeUnit());
}
private static boolean isCompatible(EvictionConfig c1, EvictionConfig c2) {
return c1 == c2 || !(c1 == null || c2 == null)
&& nullSafeEqual(c1.getSize(), c2.getSize())
&& nullSafeEqual(c1.getMaximumSizePolicy(), c2.getMaximumSizePolicy())
&& nullSafeEqual(c1.getEvictionPolicy(), c2.getEvictionPolicy())
&& nullSafeEqual(c1.getComparatorClassName(), c2.getComparatorClassName());
}
private static boolean isCompatible(WanReplicationRef c1, WanReplicationRef c2) {
return c1 == c2 || !(c1 == null || c2 == null)
&& nullSafeEqual(c1.getName(), c2.getName())
&& nullSafeEqual(c1.getMergePolicy(), c2.getMergePolicy())
&& nullSafeEqual(c1.getFilters(), c2.getFilters())
&& nullSafeEqual(c1.isRepublishingEnabled(), c2.isRepublishingEnabled());
}
@Override
CacheSimpleConfig getDefault(Config c) {
return c.getCacheConfig("default");
}
}
private static class MapConfigChecker extends ConfigChecker<MapConfig> {
@Override
boolean check(MapConfig c1, MapConfig c2) {
if (c1 == c2) {
return true;
}
if (c1 == null || c2 == null) {
return false;
}
final int maxSize1 = c1.getMaxSizeConfig().getSize();
final int maxSize2 = c2.getMaxSizeConfig().getSize();
return nullSafeEqual(c1.getName(), c2.getName())
&& nullSafeEqual(c1.getInMemoryFormat(), c2.getInMemoryFormat())
&& nullSafeEqual(c1.isStatisticsEnabled(), c2.isStatisticsEnabled())
&& nullSafeEqual(c1.isOptimizeQueries(), c2.isOptimizeQueries())
&& nullSafeEqual(c1.getCacheDeserializedValues(), c2.getCacheDeserializedValues())
&& nullSafeEqual(c1.getBackupCount(), c2.getBackupCount())
&& nullSafeEqual(c1.getAsyncBackupCount(), c2.getAsyncBackupCount())
&& nullSafeEqual(c1.getTimeToLiveSeconds(), c2.getTimeToLiveSeconds())
&& nullSafeEqual(c1.getMaxIdleSeconds(), c2.getMaxIdleSeconds())
&& nullSafeEqual(c1.getEvictionPolicy(), c2.getEvictionPolicy())
&& (nullSafeEqual(maxSize1, maxSize2) || (Math.min(maxSize1, maxSize2) == 0 && Math.max(maxSize1, maxSize2) == Integer.MAX_VALUE))
&& nullSafeEqual(c1.getEvictionPercentage(), c2.getEvictionPercentage())
&& nullSafeEqual(c1.getMinEvictionCheckMillis(), c2.getMinEvictionCheckMillis())
&& nullSafeEqual(c1.getMergePolicy(), c2.getMergePolicy())
&& nullSafeEqual(c1.isReadBackupData(), c2.isReadBackupData())
&& ConfigCompatibilityChecker.isCompatible(c1.getHotRestartConfig(), c2.getHotRestartConfig())
&& isCompatible(c1.getMapStoreConfig(), c2.getMapStoreConfig())
&& isCompatible(c1.getNearCacheConfig(), c2.getNearCacheConfig())
&& isCompatible(c1.getWanReplicationRef(), c2.getWanReplicationRef())
&& isCollectionCompatible(c1.getMapIndexConfigs(), c2.getMapIndexConfigs(), new MapIndexConfigChecker())
&& isCollectionCompatible(c1.getMapAttributeConfigs(), c2.getMapAttributeConfigs(), new MapAttributeConfigChecker())
&& isCollectionCompatible(c1.getEntryListenerConfigs(), c2.getEntryListenerConfigs(), new EntryListenerConfigChecker())
&& nullSafeEqual(c1.getPartitionLostListenerConfigs(), c2.getPartitionLostListenerConfigs())
&& nullSafeEqual(c1.getPartitioningStrategyConfig(), c2.getPartitioningStrategyConfig());
}
private static boolean isCompatible(WanReplicationRef c1, WanReplicationRef c2) {
return c1 == c2 || !(c1 == null || c2 == null)
&& nullSafeEqual(c1.getName(), c2.getName())
&& nullSafeEqual(c1.getMergePolicy(), c2.getMergePolicy())
&& nullSafeEqual(c1.getFilters(), c2.getFilters())
&& nullSafeEqual(c1.isRepublishingEnabled(), c2.isRepublishingEnabled());
}
private static boolean isCompatible(NearCacheConfig c1, NearCacheConfig c2) {
return c1 == c2 || !(c1 == null || c2 == null)
&& nullSafeEqual(c1.getName(), c2.getName())
&& nullSafeEqual(c1.getTimeToLiveSeconds(), c2.getTimeToLiveSeconds())
&& nullSafeEqual(c1.getMaxSize(), c2.getMaxSize())
&& nullSafeEqual(c1.getEvictionPolicy(), c2.getEvictionPolicy())
&& isCompatible(c1.getEvictionConfig(), c2.getEvictionConfig());
}
private static boolean isCompatible(EvictionConfig c1, EvictionConfig c2) {
return c1 == c2 || !(c1 == null || c2 == null)
&& nullSafeEqual(c1.getSize(), c2.getSize())
&& nullSafeEqual(c1.getMaximumSizePolicy(), c2.getMaximumSizePolicy())
&& nullSafeEqual(c1.getEvictionPolicy(), c2.getEvictionPolicy())
&& nullSafeEqual(c1.getEvictionPolicyType(), c2.getEvictionPolicyType())
&& nullSafeEqual(c1.getEvictionStrategyType(), c2.getEvictionStrategyType())
&& nullSafeEqual(c1.getComparatorClassName(), c2.getComparatorClassName());
}
private static boolean isCompatible(MapStoreConfig c1, MapStoreConfig c2) {
final boolean c1Disabled = c1 == null || !c1.isEnabled();
final boolean c2Disabled = c2 == null || !c2.isEnabled();
return c1 == c2 || (c1Disabled && c2Disabled) ||
(c1 != null && c2 != null
&& nullSafeEqual(c1.getClassName(), c2.getClassName())
&& nullSafeEqual(c1.getFactoryClassName(), c2.getFactoryClassName())
&& nullSafeEqual(c1.getProperties(), c2.getProperties()));
}
@Override
MapConfig getDefault(Config c) {
return c.getMapConfig("default");
}
}
private static class MapIndexConfigChecker extends ConfigChecker<MapIndexConfig> {
@Override
boolean check(MapIndexConfig c1, MapIndexConfig c2) {
return c1 == c2 || !(c1 == null || c2 == null)
&& nullSafeEqual(c1.getAttribute(), c2.getAttribute())
&& nullSafeEqual(c1.isOrdered(), c2.isOrdered());
}
}
private static class CacheSimpleEntryListenerConfigChecker extends ConfigChecker<CacheSimpleEntryListenerConfig> {
@Override
boolean check(CacheSimpleEntryListenerConfig c1, CacheSimpleEntryListenerConfig c2) {
return c1 == c2 || !(c1 == null || c2 == null)
&& nullSafeEqual(c1.getCacheEntryListenerFactory(), c2.getCacheEntryListenerFactory())
&& nullSafeEqual(c1.getCacheEntryEventFilterFactory(), c2.getCacheEntryEventFilterFactory())
&& nullSafeEqual(c1.isOldValueRequired(), c2.isOldValueRequired())
&& nullSafeEqual(c1.isSynchronous(), c2.isSynchronous());
}
}
private static class EntryListenerConfigChecker extends ConfigChecker<EntryListenerConfig> {
@Override
boolean check(EntryListenerConfig c1, EntryListenerConfig c2) {
return c1 == c2 || !(c1 == null || c2 == null)
&& nullSafeEqual(c1.isLocal(), c2.isLocal())
&& nullSafeEqual(c1.isIncludeValue(), c2.isIncludeValue())
&& nullSafeEqual(c1.getClassName(), c2.getClassName());
}
}
private static class MapAttributeConfigChecker extends ConfigChecker<MapAttributeConfig> {
@Override
boolean check(MapAttributeConfig c1, MapAttributeConfig c2) {
return c1 == c2 || !(c1 == null || c2 == null)
&& nullSafeEqual(c1.getName(), c2.getName())
&& nullSafeEqual(c1.getExtractor(), c2.getExtractor());
}
}
private static class DiscoveryStrategyConfigChecker extends ConfigChecker<DiscoveryStrategyConfig> {
@Override
boolean check(DiscoveryStrategyConfig c1, DiscoveryStrategyConfig c2) {
return c1 == c2 || !(c1 == null || c2 == null)
&& nullSafeEqual(c1.getClassName(), c2.getClassName())
&& nullSafeEqual(c1.getProperties(), c2.getProperties());
}
}
private static class MemberGroupConfigChecker extends ConfigChecker<MemberGroupConfig> {
@Override
boolean check(MemberGroupConfig c1, MemberGroupConfig c2) {
return c1 == c2 || !(c1 == null || c2 == null)
&& nullSafeEqual(new ArrayList<String>(c1.getInterfaces()),
new ArrayList<String>(c2.getInterfaces()));
}
}
private static class SerializerConfigChecker extends ConfigChecker<SerializerConfig> {
@Override
boolean check(SerializerConfig c1, SerializerConfig c2) {
return c1 == c2 || !(c1 == null || c2 == null)
&& nullSafeEqual(c1.getClassName(), c2.getClassName())
&& nullSafeEqual(c1.getTypeClass(), c2.getTypeClass())
&& nullSafeEqual(c1.getTypeClassName(), c2.getTypeClassName());
}
}
private static class NetworkConfigChecker extends ConfigChecker<NetworkConfig> {
@Override
boolean check(NetworkConfig c1, NetworkConfig c2) {
return c1 == c2 || !(c1 == null || c2 == null)
&& nullSafeEqual(c1.getPort(), c2.getPort())
&& nullSafeEqual(c1.getPortCount(), c2.getPortCount())
&& nullSafeEqual(c1.isPortAutoIncrement(), c2.isPortAutoIncrement())
&& nullSafeEqual(c1.isReuseAddress(), c2.isReuseAddress())
&& nullSafeEqual(c1.getPublicAddress(), c2.getPublicAddress())
&& isCompatible(c1.getOutboundPortDefinitions(), c2.getOutboundPortDefinitions())
&& nullSafeEqual(c1.getOutboundPorts(), c2.getOutboundPorts())
&& isCompatible(c1.getInterfaces(), c2.getInterfaces())
&& isCompatible(c1.getJoin(), c2.getJoin())
&& isCompatible(c1.getSymmetricEncryptionConfig(), c2.getSymmetricEncryptionConfig())
&& isCompatible(c1.getSocketInterceptorConfig(), c2.getSocketInterceptorConfig())
&& isCompatible(c1.getSSLConfig(), c2.getSSLConfig());
}
private static boolean isCompatible(Collection<String> portDefinitions1, Collection<String> portDefinitions2) {
final String[] defaultValues = {"0", "*"};
final boolean defaultDefinition1 = CollectionUtil.isEmpty(portDefinitions1) ||
(portDefinitions1.size() == 1 && ArrayUtils.contains(defaultValues, portDefinitions1.iterator().next()));
final boolean defaultDefinition2 = CollectionUtil.isEmpty(portDefinitions2) ||
(portDefinitions2.size() == 1 && ArrayUtils.contains(defaultValues, portDefinitions2.iterator().next()));
return (defaultDefinition1 && defaultDefinition2) || nullSafeEqual(portDefinitions1, portDefinitions2);
}
private static boolean isCompatible(JoinConfig c1, JoinConfig c2) {
return c1 == c2 || !(c1 == null || c2 == null)
&& isCompatible(c1.getMulticastConfig(), c2.getMulticastConfig())
&& isCompatible(c1.getTcpIpConfig(), c2.getTcpIpConfig())
&& new AwsConfigChecker().check(c1.getAwsConfig(), c2.getAwsConfig())
&& new DiscoveryConfigChecker().check(c1.getDiscoveryConfig(), c2.getDiscoveryConfig());
}
private static boolean isCompatible(TcpIpConfig c1, TcpIpConfig c2) {
final boolean c1Disabled = c1 == null || !c1.isEnabled();
final boolean c2Disabled = c2 == null || !c2.isEnabled();
return c1 == c2 || (c1Disabled && c2Disabled) ||
(c1 != null && c2 != null
&& nullSafeEqual(c1.getConnectionTimeoutSeconds(), c2.getConnectionTimeoutSeconds())
&& nullSafeEqual(c1.getMembers(), c2.getMembers()))
&& nullSafeEqual(c1.getRequiredMember(), c2.getRequiredMember());
}
private static boolean isCompatible(MulticastConfig c1, MulticastConfig c2) {
final boolean c1Disabled = c1 == null || !c1.isEnabled();
final boolean c2Disabled = c2 == null || !c2.isEnabled();
return c1 == c2 || (c1Disabled && c2Disabled) ||
(c1 != null && c2 != null
&& nullSafeEqual(c1.getMulticastGroup(), c2.getMulticastGroup())
&& nullSafeEqual(c1.getMulticastPort(), c2.getMulticastPort()))
&& nullSafeEqual(c1.getMulticastTimeoutSeconds(), c2.getMulticastTimeoutSeconds())
&& nullSafeEqual(c1.getMulticastTimeToLive(), c2.getMulticastTimeToLive())
&& nullSafeEqual(c1.getTrustedInterfaces(), c2.getTrustedInterfaces());
}
private static boolean isCompatible(InterfacesConfig c1, InterfacesConfig c2) {
final boolean c1Disabled = c1 == null || !c1.isEnabled();
final boolean c2Disabled = c2 == null || !c2.isEnabled();
return c1 == c2 || (c1Disabled && c2Disabled) ||
(c1 != null && c2 != null
&& nullSafeEqual(new ArrayList<String>(c1.getInterfaces()), new ArrayList<String>(c2.getInterfaces())));
}
private static boolean isCompatible(SymmetricEncryptionConfig c1, SymmetricEncryptionConfig c2) {
final boolean c1Disabled = c1 == null || !c1.isEnabled();
final boolean c2Disabled = c2 == null || !c2.isEnabled();
return c1 == c2 || (c1Disabled && c2Disabled) ||
(c1 != null && c2 != null
&& nullSafeEqual(c1.getSalt(), c2.getSalt())
&& nullSafeEqual(c1.getPassword(), c2.getPassword()))
&& nullSafeEqual(c1.getIterationCount(), c2.getIterationCount())
&& nullSafeEqual(c1.getAlgorithm(), c2.getAlgorithm())
&& nullSafeEqual(c1.getKey(), c2.getKey());
}
private static boolean isCompatible(SocketInterceptorConfig c1, SocketInterceptorConfig c2) {
final boolean c1Disabled = c1 == null || !c1.isEnabled();
final boolean c2Disabled = c2 == null || !c2.isEnabled();
return c1 == c2 || (c1Disabled && c2Disabled) ||
(c1 != null && c2 != null
&& nullSafeEqual(c1.getClassName(), c2.getClassName())
&& nullSafeEqual(c1.getImplementation(), c2.getImplementation()))
&& nullSafeEqual(c1.getProperties(), c2.getProperties());
}
private static boolean isCompatible(SSLConfig c1, SSLConfig c2) {
final boolean c1Disabled = c1 == null || !c1.isEnabled();
final boolean c2Disabled = c2 == null || !c2.isEnabled();
return c1 == c2 || (c1Disabled && c2Disabled) ||
(c1 != null && c2 != null
&& nullSafeEqual(c1.getFactoryClassName(), c2.getFactoryClassName())
&& nullSafeEqual(c1.getFactoryImplementation(), c2.getFactoryImplementation()))
&& nullSafeEqual(c1.getProperties(), c2.getProperties());
}
}
private static class DiscoveryConfigChecker extends ConfigChecker<DiscoveryConfig> {
@Override
boolean check(DiscoveryConfig c1, DiscoveryConfig c2) {
final boolean c1Disabled = c1 == null || !c1.isEnabled();
final boolean c2Disabled = c2 == null || !c2.isEnabled();
return c1 == c2 || (c1Disabled && c2Disabled) ||
(c1 != null && c2 != null
&& nullSafeEqual(c1.getNodeFilterClass(), c2.getNodeFilterClass())
&& nullSafeEqual(c1.getDiscoveryServiceProvider(), c2.getDiscoveryServiceProvider())
&& isCollectionCompatible(c1.getDiscoveryStrategyConfigs(), c2.getDiscoveryStrategyConfigs(), new DiscoveryStrategyConfigChecker()));
}
}
private static class AwsConfigChecker extends ConfigChecker<AwsConfig> {
@Override
boolean check(AwsConfig c1, AwsConfig c2) {
final boolean c1Disabled = c1 == null || !c1.isEnabled();
final boolean c2Disabled = c2 == null || !c2.isEnabled();
return c1 == c2 || (c1Disabled && c2Disabled) ||
(c1 != null && c2 != null
&& nullSafeEqual(c1.getAccessKey(), c2.getAccessKey())
&& nullSafeEqual(c1.getSecretKey(), c2.getSecretKey())
&& nullSafeEqual(c1.getRegion(), c2.getRegion())
&& nullSafeEqual(c1.getSecurityGroupName(), c2.getSecurityGroupName())
&& nullSafeEqual(c1.getTagKey(), c2.getTagKey())
&& nullSafeEqual(c1.getTagValue(), c2.getTagValue())
&& nullSafeEqual(c1.getHostHeader(), c2.getHostHeader())
&& nullSafeEqual(c1.getIamRole(), c2.getIamRole())
&& nullSafeEqual(c1.getConnectionTimeoutSeconds(), c2.getConnectionTimeoutSeconds()));
}
}
private static class WanReplicationConfigChecker extends ConfigChecker<WanReplicationConfig> {
@Override
boolean check(WanReplicationConfig c1, WanReplicationConfig c2) {
return c1 == c2 || !(c1 == null || c2 == null)
&& nullSafeEqual(c1.getName(), c2.getName())
&& isCompatible(c1.getWanConsumerConfig(), c2.getWanConsumerConfig())
&& isCollectionCompatible(c1.getWanPublisherConfigs(), c2.getWanPublisherConfigs(), new WanPublisherConfigChecker());
}
private boolean isCompatible(WanConsumerConfig c1, WanConsumerConfig c2) {
return c1 == c2 || !(c1 == null || c2 == null)
&& nullSafeEqual(c1.getClassName(), c2.getClassName())
&& nullSafeEqual(c1.getImplementation(), c2.getImplementation())
&& nullSafeEqual(c1.getProperties(), c2.getProperties());
}
}
private static class WanPublisherConfigChecker extends ConfigChecker<WanPublisherConfig> {
@Override
boolean check(WanPublisherConfig c1, WanPublisherConfig c2) {
return c1 == c2 || !(c1 == null || c2 == null)
&& nullSafeEqual(c1.getGroupName(), c2.getGroupName())
&& nullSafeEqual(c1.getQueueCapacity(), c2.getQueueCapacity())
&& nullSafeEqual(c1.getQueueFullBehavior(), c2.getQueueFullBehavior())
&& new AwsConfigChecker().check(c1.getAwsConfig(), c2.getAwsConfig())
&& new DiscoveryConfigChecker().check(c1.getDiscoveryConfig(), c2.getDiscoveryConfig())
&& nullSafeEqual(c1.getClassName(), c2.getClassName())
&& nullSafeEqual(c1.getImplementation(), c2.getImplementation())
&& nullSafeEqual(c1.getProperties(), c2.getProperties());
}
}
private static class PartitionGroupConfigChecker extends ConfigChecker<PartitionGroupConfig> {
@Override
boolean check(PartitionGroupConfig c1, PartitionGroupConfig c2) {
final boolean c1Disabled = c1 == null || !c1.isEnabled();
final boolean c2Disabled = c2 == null || !c2.isEnabled();
return c1 == c2 || (c1Disabled && c2Disabled) ||
(c1 != null && c2 != null
&& nullSafeEqual(c1.getGroupType(), c2.getGroupType())
&& isCollectionCompatible(c1.getMemberGroupConfigs(), c2.getMemberGroupConfigs(), new MemberGroupConfigChecker()));
}
}
private static class SerializationConfigChecker extends ConfigChecker<SerializationConfig> {
@Override
boolean check(SerializationConfig c1, SerializationConfig c2) {
return c1 == c2 || !(c1 == null || c2 == null)
&& nullSafeEqual(c1.getPortableVersion(), c2.getPortableVersion())
&& nullSafeEqual(c1.getDataSerializableFactoryClasses(), c2.getDataSerializableFactoryClasses())
&& nullSafeEqual(c1.getPortableFactoryClasses(), c2.getPortableFactoryClasses())
&& isCompatible(c1.getGlobalSerializerConfig(), c2.getGlobalSerializerConfig())
&& isCollectionCompatible(c1.getSerializerConfigs(), c2.getSerializerConfigs(), new SerializerConfigChecker())
&& nullSafeEqual(c1.isCheckClassDefErrors(), c2.isCheckClassDefErrors())
&& nullSafeEqual(c1.isUseNativeByteOrder(), c2.isUseNativeByteOrder())
&& nullSafeEqual(c1.getByteOrder(), c2.getByteOrder())
&& nullSafeEqual(c1.isEnableCompression(), c2.isEnableCompression())
&& nullSafeEqual(c1.isEnableSharedObject(), c2.isEnableSharedObject())
&& nullSafeEqual(c1.isAllowUnsafe(), c2.isAllowUnsafe());
}
private static boolean isCompatible(GlobalSerializerConfig c1, GlobalSerializerConfig c2) {
return c1 == c2 || !(c1 == null || c2 == null)
&& nullSafeEqual(c1.getClassName(), c2.getClassName())
&& nullSafeEqual(c1.isOverrideJavaSerialization(), c2.isOverrideJavaSerialization());
}
}
private static class ServicesConfigChecker extends ConfigChecker<ServicesConfig> {
@Override
boolean check(ServicesConfig c1, ServicesConfig c2) {
return c1 == c2 || !(c1 == null || c2 == null)
&& nullSafeEqual(c1.isEnableDefaults(), c2.isEnableDefaults())
&& isCompatible(c1.getServiceConfigs(), c2.getServiceConfigs());
}
private static boolean isCompatible(Collection<ServiceConfig> c1, Collection<ServiceConfig> c2) {
if (c1 == c2) {
return true;
}
if (c1 == null || c2 == null || c1.size() != c2.size()) {
return false;
}
final HashMap<String, ServiceConfig> config1 = new HashMap<String, ServiceConfig>();
final HashMap<String, ServiceConfig> config2 = new HashMap<String, ServiceConfig>();
for (ServiceConfig serviceConfig : c1) {
config1.put(serviceConfig.getName(), serviceConfig);
}
for (ServiceConfig serviceConfig : c2) {
config2.put(serviceConfig.getName(), serviceConfig);
}
if (!config1.keySet().equals(config2.keySet())) {
return false;
}
for (ServiceConfig serviceConfig : c1) {
if (!isCompatible(serviceConfig, config2.get(serviceConfig.getName()))) {
return false;
}
}
return true;
}
private static boolean isCompatible(ServiceConfig c1, ServiceConfig c2) {
final boolean c1Disabled = c1 == null || !c1.isEnabled();
final boolean c2Disabled = c2 == null || !c2.isEnabled();
return c1 == c2 || (c1Disabled && c2Disabled) ||
(c1 != null && c2 != null
&& nullSafeEqual(c1.getName(), c2.getName())
&& nullSafeEqual(c1.getClassName(), c2.getClassName())
&& nullSafeEqual(c1.getImplementation(), c2.getImplementation())
&& nullSafeEqual(c1.getProperties(), c2.getProperties())
&& nullSafeEqual(c1.getConfigObject(), c2.getConfigObject()));
}
}
private static class ManagementCenterConfigChecker extends ConfigChecker<ManagementCenterConfig> {
@Override
boolean check(ManagementCenterConfig c1, ManagementCenterConfig c2) {
final boolean c1Disabled = c1 == null || !c1.isEnabled();
final boolean c2Disabled = c2 == null || !c2.isEnabled();
return c1 == c2 || (c1Disabled && c2Disabled) ||
(c1 != null && c2 != null
&& nullSafeEqual(c1.getUrl(), c2.getUrl())
&& nullSafeEqual(c1.getUpdateInterval(), c2.getUpdateInterval()));
}
}
private static class HotRestartConfigChecker extends ConfigChecker<HotRestartPersistenceConfig> {
@Override
boolean check(HotRestartPersistenceConfig c1, HotRestartPersistenceConfig c2) {
final boolean c1Disabled = c1 == null || !c1.isEnabled();
final boolean c2Disabled = c2 == null || !c2.isEnabled();
return c1 == c2 || (c1Disabled && c2Disabled) ||
(c1 != null && c2 != null
&& nullSafeEqual(c1.getBaseDir(), c2.getBaseDir())
&& nullSafeEqual(c1.getBackupDir(), c2.getBackupDir())
&& nullSafeEqual(c1.getParallelism(), c2.getParallelism())
&& nullSafeEqual(c1.getValidationTimeoutSeconds(), c2.getValidationTimeoutSeconds())
&& nullSafeEqual(c1.getDataLoadTimeoutSeconds(), c2.getDataLoadTimeoutSeconds())
&& nullSafeEqual(c1.getClusterDataRecoveryPolicy(), c2.getClusterDataRecoveryPolicy()));
}
}
}