From 5129cb04de843c6b0fbf0bd4c925412ce7fbdc20 Mon Sep 17 00:00:00 2001 From: John Blum Date: Mon, 20 Nov 2017 13:40:23 -0800 Subject: [PATCH] DATAGEODE-59 - Add support for configuring client and server Region data management policies in Entity-defined Regions. --- .../PartitionAttributesFactoryBean.java | 64 +- .../gemfire/RegionAttributesFactoryBean.java | 20 +- .../data/gemfire/RegionFactoryBean.java | 49 +- .../RegionShortcutToDataPolicyConverter.java | 55 ++ .../data/gemfire/RegionShortcutWrapper.java | 4 +- .../client/ClientRegionFactoryBean.java | 2 +- ...ntRegionShortcutToDataPolicyConverter.java | 56 ++ .../client/ClientRegionShortcutWrapper.java | 1 + .../CachingDefinedRegionsConfiguration.java | 10 +- .../EnableEntityDefinedRegions.java | 39 +- .../EntityDefinedRegionsConfiguration.java | 341 +++++--- .../config/annotation/RegionConfigurer.java | 3 +- ...a => CacheTypeAwareRegionFactoryBean.java} | 123 ++- .../mapping/GemfirePersistentEntity.java | 18 +- .../data/gemfire/RegionFactoryBeanTest.java | 166 +++- ...hortcutToDataPolicyConverterUnitTests.java | 192 +++++ .../client/ClientRegionFactoryBeanTest.java | 2 +- ...hortcutToDataPolicyConverterUnitTests.java | 110 +++ ...CacheServerPropertiesIntegrationTests.java | 2 +- .../EnableEntityDefinedRegionsUnitTests.java | 589 +++++++------- .../test/mock/MockGemFireObjectsSupport.java | 727 ++++++++++++++++-- .../gemfire/test/mock/MockObjectsSupport.java | 13 +- 22 files changed, 1930 insertions(+), 656 deletions(-) create mode 100644 src/main/java/org/springframework/data/gemfire/RegionShortcutToDataPolicyConverter.java create mode 100644 src/main/java/org/springframework/data/gemfire/client/ClientRegionShortcutToDataPolicyConverter.java rename src/main/java/org/springframework/data/gemfire/config/annotation/support/{GemFireCacheTypeAwareRegionFactoryBean.java => CacheTypeAwareRegionFactoryBean.java} (66%) create mode 100644 src/test/java/org/springframework/data/gemfire/RegionShortcutToDataPolicyConverterUnitTests.java create mode 100644 src/test/java/org/springframework/data/gemfire/client/ClientRegionShortcutToDataPolicyConverterUnitTests.java diff --git a/src/main/java/org/springframework/data/gemfire/PartitionAttributesFactoryBean.java b/src/main/java/org/springframework/data/gemfire/PartitionAttributesFactoryBean.java index 6776cb74..248d7cc4 100644 --- a/src/main/java/org/springframework/data/gemfire/PartitionAttributesFactoryBean.java +++ b/src/main/java/org/springframework/data/gemfire/PartitionAttributesFactoryBean.java @@ -16,6 +16,8 @@ package org.springframework.data.gemfire; +import static org.springframework.data.gemfire.util.CollectionUtils.nullSafeList; + import java.util.List; import org.apache.geode.cache.FixedPartitionAttributes; @@ -25,7 +27,7 @@ import org.apache.geode.cache.PartitionResolver; import org.apache.geode.cache.partition.PartitionListener; import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.InitializingBean; -import org.springframework.data.gemfire.util.CollectionUtils; +import org.springframework.data.gemfire.support.AbstractFactoryBeanSupport; /** * Spring {@link FactoryBean} for creating {@link PartitionAttributes}. @@ -35,101 +37,81 @@ import org.springframework.data.gemfire.util.CollectionUtils; * @author Costin Leau * @author David Turanski * @author John Blum - * @see org.springframework.beans.factory.FactoryBean - * @see org.springframework.beans.factory.InitializingBean * @see org.apache.geode.cache.FixedPartitionAttributes * @see org.apache.geode.cache.PartitionAttributes * @see org.apache.geode.cache.PartitionAttributesFactory * @see org.apache.geode.cache.PartitionResolver * @see org.apache.geode.cache.partition.PartitionListener + * @see org.springframework.beans.factory.FactoryBean + * @see org.springframework.beans.factory.InitializingBean + * @see org.springframework.data.gemfire.support.AbstractFactoryBeanSupport */ -@SuppressWarnings({ "rawtypes", "unchecked", "unused" }) -public class PartitionAttributesFactoryBean implements FactoryBean>, InitializingBean { +@SuppressWarnings("unused") +public class PartitionAttributesFactoryBean extends AbstractFactoryBeanSupport> + implements InitializingBean { private List partitionListeners; private PartitionAttributes partitionAttributes; - private final PartitionAttributesFactory partitionAttributesFactory = - new PartitionAttributesFactory(); + private final PartitionAttributesFactory partitionAttributesFactory = new PartitionAttributesFactory<>(); /** * @inheritDoc */ @Override public void afterPropertiesSet() throws Exception { - for (PartitionListener listener : CollectionUtils.nullSafeList(partitionListeners)) { - partitionAttributesFactory.addPartitionListener(listener); - } - + nullSafeList(partitionListeners).forEach(partitionAttributesFactory::addPartitionListener); this.partitionAttributes = partitionAttributesFactory.create(); } - /** - * @inheritDoc - */ @Override - public PartitionAttributes getObject() throws Exception { + public PartitionAttributes getObject() throws Exception { return this.partitionAttributes; } - /** - * @inheritDoc - */ @Override public Class getObjectType() { return (this.partitionAttributes != null ? this.partitionAttributes.getClass() : PartitionAttributes.class); } - /** - * @inheritDoc - */ - @Override - public boolean isSingleton() { - return false; - } - public void setColocatedWith(String collocatedWith) { - partitionAttributesFactory.setColocatedWith(collocatedWith); + this.partitionAttributesFactory.setColocatedWith(collocatedWith); } public void setFixedPartitionAttributes(List fixedPartitionAttributes) { - for (FixedPartitionAttributes fixedPartitionAttributesElement : - CollectionUtils.nullSafeList(fixedPartitionAttributes)) { - - partitionAttributesFactory.addFixedPartitionAttributes(fixedPartitionAttributesElement); - } + nullSafeList(fixedPartitionAttributes).forEach(this.partitionAttributesFactory::addFixedPartitionAttributes); } public void setLocalMaxMemory(int mb) { - partitionAttributesFactory.setLocalMaxMemory(mb); + this.partitionAttributesFactory.setLocalMaxMemory(mb); } public void setPartitionListeners(List partitionListeners) { this.partitionListeners = partitionListeners; } - public void setPartitionResolver(PartitionResolver resolver) { - partitionAttributesFactory.setPartitionResolver(resolver); + public void setPartitionResolver(PartitionResolver resolver) { + this.partitionAttributesFactory.setPartitionResolver(resolver); } public void setRecoveryDelay(long recoveryDelay) { - partitionAttributesFactory.setRecoveryDelay(recoveryDelay); + this.partitionAttributesFactory.setRecoveryDelay(recoveryDelay); } public void setRedundantCopies(int redundantCopies) { - partitionAttributesFactory.setRedundantCopies(redundantCopies); + this.partitionAttributesFactory.setRedundantCopies(redundantCopies); } public void setStartupRecoveryDelay(long startupRecoveryDelay) { - partitionAttributesFactory.setStartupRecoveryDelay(startupRecoveryDelay); + this.partitionAttributesFactory.setStartupRecoveryDelay(startupRecoveryDelay); } - public void setTotalMaxMemory(long mb) { - partitionAttributesFactory.setTotalMaxMemory(mb); + public void setTotalMaxMemory(long megabytes) { + this.partitionAttributesFactory.setTotalMaxMemory(megabytes); } public void setTotalNumBuckets(int numBuckets) { - partitionAttributesFactory.setTotalNumBuckets(numBuckets); + this.partitionAttributesFactory.setTotalNumBuckets(numBuckets); } } diff --git a/src/main/java/org/springframework/data/gemfire/RegionAttributesFactoryBean.java b/src/main/java/org/springframework/data/gemfire/RegionAttributesFactoryBean.java index 55e51b6a..6080a384 100644 --- a/src/main/java/org/springframework/data/gemfire/RegionAttributesFactoryBean.java +++ b/src/main/java/org/springframework/data/gemfire/RegionAttributesFactoryBean.java @@ -35,35 +35,23 @@ import org.springframework.beans.factory.InitializingBean; public class RegionAttributesFactoryBean extends AttributesFactory implements FactoryBean, InitializingBean { - private RegionAttributes attributes; + private RegionAttributes regionAttributes; - /** - * @inheritDoc - */ @Override public void afterPropertiesSet() throws Exception { - attributes = super.create(); + this.regionAttributes = super.create(); } - /** - * @inheritDoc - */ @Override public RegionAttributes getObject() throws Exception { - return attributes; + return this.regionAttributes; } - /** - * @inheritDoc - */ @Override public Class getObjectType() { - return (attributes != null ? attributes.getClass() : RegionAttributes.class); + return this.regionAttributes != null ? this.regionAttributes.getClass() : RegionAttributes.class; } - /** - * @inheritDoc - */ @Override public boolean isSingleton() { return true; diff --git a/src/main/java/org/springframework/data/gemfire/RegionFactoryBean.java b/src/main/java/org/springframework/data/gemfire/RegionFactoryBean.java index 85084138..20fbfc05 100644 --- a/src/main/java/org/springframework/data/gemfire/RegionFactoryBean.java +++ b/src/main/java/org/springframework/data/gemfire/RegionFactoryBean.java @@ -23,7 +23,6 @@ import static org.springframework.data.gemfire.util.CollectionUtils.nullSafeIter import static org.springframework.data.gemfire.util.RuntimeExceptionFactory.newIllegalArgumentException; import static org.springframework.data.gemfire.util.RuntimeExceptionFactory.newIllegalStateException; -import java.lang.reflect.Field; import java.util.Arrays; import java.util.Collections; import java.util.List; @@ -267,10 +266,11 @@ public abstract class RegionFactoryBean extends RegionLookupFactoryBean createRegionFactory(Cache cache) { if (this.shortcut != null) { + RegionFactory regionFactory = mergeRegionAttributes(cache.createRegionFactory(this.shortcut), this.attributes); - setDataPolicy(getDataPolicy(regionFactory)); + setDataPolicy(getDataPolicy(regionFactory, this.shortcut)); return regionFactory; } @@ -300,7 +300,7 @@ public abstract class RegionFactoryBean extends RegionLookupFactoryBean isDiskStoreConfigurationAllowed()) @@ -313,7 +313,7 @@ public abstract class RegionFactoryBean extends RegionLookupFactoryBean extends RegionLookupFactoryBean getFieldValue(attributesFactory,"regionAttributes", null)) + .map(regionAttributes -> ((RegionAttributes) regionAttributes).getDataPolicy()) + .orElseGet(() -> RegionShortcutToDataPolicyConverter.INSTANCE.convert(regionShortcut)); } /* (non-Javadoc) */ @SuppressWarnings("unchecked") - private T getFieldValue(Object source, String fieldName, Class targetType) { - Field field = ReflectionUtils.findField(source.getClass(), fieldName, targetType); - ReflectionUtils.makeAccessible(field); - return (T) ReflectionUtils.getField(field, source); + private Optional getFieldValue(Object source, String fieldName, Class targetType) { + + return Optional.ofNullable(source) + .map(Object::getClass) + .map(type -> ReflectionUtils.findField(type, fieldName, targetType)) + .map(field -> { + ReflectionUtils.makeAccessible(field); + return field; + }) + .map(field -> (T) ReflectionUtils.getField(field, source)); } /** @@ -402,8 +411,8 @@ public abstract class RegionFactoryBean extends RegionLookupFactoryBean regionAttributes) { if (regionAttributes != null) { - // NOTE this validation may not be strictly required depending on how the RegionAttributes were "created", - // but... + + // NOTE: this validation may not be strictly necessary depending on how the RegionAttributes were "created", validateRegionAttributes(regionAttributes); regionFactory.setCloningEnabled(regionAttributes.getCloningEnabled()); @@ -418,7 +427,7 @@ public abstract class RegionFactoryBean extends RegionLookupFactoryBean extends RegionLookupFactoryBean void mergePartitionAttributes(RegionFactory regionFactory, RegionAttributes regionAttributes) { - // NOTE PartitionAttributes are created by certain RegionShortcuts; need the null check since RegionAttributes + // NOTE: PartitionAttributes are created by certain RegionShortcuts; need the null check since RegionAttributes // can technically return null! - // NOTE most likely, the PartitionAttributes will never be null since the PartitionRegionFactoryBean always + // NOTE: most likely, the PartitionAttributes will never be null since the PartitionRegionFactoryBean always // sets a PartitionAttributesFactoryBean BeanBuilder on the RegionAttributesFactoryBean "partitionAttributes" // property. if (regionAttributes.getPartitionAttributes() != null) { @@ -572,12 +581,12 @@ public abstract class RegionFactoryBean extends RegionLookupFactoryBean extends RegionLookupFactoryBean regionFactory, Boolean persistent, String dataPolicy) { if (dataPolicy != null) { + DataPolicy resolvedDataPolicy = new DataPolicyConverter().convert(dataPolicy); - Assert.notNull(resolvedDataPolicy, String.format("Data Policy [%1$s] is invalid.", dataPolicy)); + Assert.notNull(resolvedDataPolicy, String.format("Data Policy [%s] is invalid.", dataPolicy)); assertDataPolicyAndPersistentAttributesAreCompatible(resolvedDataPolicy); regionFactory.setDataPolicy(resolvedDataPolicy); setDataPolicy(resolvedDataPolicy); } else { + DataPolicy regionAttributesDataPolicy = getDataPolicy(getAttributes(), DataPolicy.DEFAULT); DataPolicy resolvedDataPolicy = (isPersistent() && DataPolicy.DEFAULT.equals(regionAttributesDataPolicy) ? DataPolicy.PERSISTENT_REPLICATE : regionAttributesDataPolicy); diff --git a/src/main/java/org/springframework/data/gemfire/RegionShortcutToDataPolicyConverter.java b/src/main/java/org/springframework/data/gemfire/RegionShortcutToDataPolicyConverter.java new file mode 100644 index 00000000..e0170c17 --- /dev/null +++ b/src/main/java/org/springframework/data/gemfire/RegionShortcutToDataPolicyConverter.java @@ -0,0 +1,55 @@ +/* + * Copyright 2017 the original author or authors. + * + * 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.springframework.data.gemfire; + +import java.util.Optional; + +import org.apache.geode.cache.DataPolicy; +import org.apache.geode.cache.RegionShortcut; +import org.springframework.core.convert.converter.Converter; +import org.springframework.lang.Nullable; + +/** + * Spring {@link Converter} to convert a {@link RegionShortcut} into a {@link DataPolicy}. + * + * @author John Blum + * @see org.apache.geode.cache.DataPolicy + * @see org.apache.geode.cache.RegionShortcut + * @see org.springframework.core.convert.converter.Converter + * @see org.springframework.data.gemfire.RegionShortcutWrapper + * @since 2.0.2 + */ +public class RegionShortcutToDataPolicyConverter implements Converter { + + public static final RegionShortcutToDataPolicyConverter INSTANCE = new RegionShortcutToDataPolicyConverter(); + + /** + * Converts the given {@link RegionShortcut} into a corresponding {@link DataPolicy}. + * + * @param regionShortcut {@link RegionShortcut} to convert. + * @return a corresponding {@link DataPolicy} for the given {@link RegionShortcut}. + * @see org.apache.geode.cache.RegionShortcut + * @see org.apache.geode.cache.DataPolicy + */ + @Nullable @Override + public DataPolicy convert(RegionShortcut regionShortcut) { + + return Optional.ofNullable(RegionShortcutWrapper.valueOf(regionShortcut)) + .map(RegionShortcutWrapper::getDataPolicy) + .orElse(DataPolicy.DEFAULT); + } +} diff --git a/src/main/java/org/springframework/data/gemfire/RegionShortcutWrapper.java b/src/main/java/org/springframework/data/gemfire/RegionShortcutWrapper.java index 02a34c41..cac5fad6 100644 --- a/src/main/java/org/springframework/data/gemfire/RegionShortcutWrapper.java +++ b/src/main/java/org/springframework/data/gemfire/RegionShortcutWrapper.java @@ -31,10 +31,11 @@ import org.springframework.util.ObjectUtils; */ @SuppressWarnings("unused") public enum RegionShortcutWrapper { + LOCAL(RegionShortcut.LOCAL, DataPolicy.NORMAL), LOCAL_HEAP_LRU(RegionShortcut.LOCAL_HEAP_LRU, DataPolicy.NORMAL), LOCAL_OVERFLOW(RegionShortcut.LOCAL_OVERFLOW, DataPolicy.NORMAL), - LOCAL_PERSISTENT(RegionShortcut.LOCAL_PERSISTENT, DataPolicy.NORMAL), + LOCAL_PERSISTENT(RegionShortcut.LOCAL_PERSISTENT, DataPolicy.PERSISTENT_REPLICATE), LOCAL_PERSISTENT_OVERFLOW(RegionShortcut.LOCAL_PERSISTENT_OVERFLOW, DataPolicy.PERSISTENT_REPLICATE), PARTITION(RegionShortcut.PARTITION, DataPolicy.PARTITION), PARTITION_HEAP_LRU(RegionShortcut.PARTITION_HEAP_LRU, DataPolicy.PARTITION), @@ -66,6 +67,7 @@ public enum RegionShortcutWrapper { } public static RegionShortcutWrapper valueOf(RegionShortcut regionShortcut) { + for (RegionShortcutWrapper wrapper : values()) { if (ObjectUtils.nullSafeEquals(wrapper.getRegionShortcut(), regionShortcut)) { return wrapper; diff --git a/src/main/java/org/springframework/data/gemfire/client/ClientRegionFactoryBean.java b/src/main/java/org/springframework/data/gemfire/client/ClientRegionFactoryBean.java index 4860ef41..e0e603bc 100644 --- a/src/main/java/org/springframework/data/gemfire/client/ClientRegionFactoryBean.java +++ b/src/main/java/org/springframework/data/gemfire/client/ClientRegionFactoryBean.java @@ -278,7 +278,7 @@ public class ClientRegionFactoryBean extends RegionLookupFactoryBean else { // NOTE the DataPolicy validation is based on the ClientRegionShortcut initialization logic // in org.apache.geode.internal.cache.GemFireCacheImpl.initializeClientRegionShortcuts - throw newIllegalArgumentException("Data Policy [%s] is not valid for the client Region", dataPolicy); + throw newIllegalArgumentException("Data Policy [%s] is not valid for a client Region", dataPolicy); } } else { diff --git a/src/main/java/org/springframework/data/gemfire/client/ClientRegionShortcutToDataPolicyConverter.java b/src/main/java/org/springframework/data/gemfire/client/ClientRegionShortcutToDataPolicyConverter.java new file mode 100644 index 00000000..76a7dd0b --- /dev/null +++ b/src/main/java/org/springframework/data/gemfire/client/ClientRegionShortcutToDataPolicyConverter.java @@ -0,0 +1,56 @@ +/* + * Copyright 2017 the original author or authors. + * + * 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.springframework.data.gemfire.client; + +import java.util.Optional; + +import org.apache.geode.cache.DataPolicy; +import org.apache.geode.cache.client.ClientRegionShortcut; +import org.springframework.core.convert.converter.Converter; +import org.springframework.lang.Nullable; + +/** + * Spring {@link Converter} to convert a {@link ClientRegionShortcut} into a {@link DataPolicy}. + * + * @author John Blum + * @see org.apache.geode.cache.DataPolicy + * @see org.apache.geode.cache.client.ClientRegionShortcut + * @see org.springframework.core.convert.converter.Converter + * @see org.springframework.data.gemfire.client.ClientRegionShortcutWrapper + * @since 2.0.2 + */ +public class ClientRegionShortcutToDataPolicyConverter implements Converter { + + public static final ClientRegionShortcutToDataPolicyConverter INSTANCE = + new ClientRegionShortcutToDataPolicyConverter(); + + /** + * Converts the given {@link ClientRegionShortcut} into a corresponding {@link DataPolicy}. + * + * @param regionShortcut {@link ClientRegionShortcut} to convert. + * @return a corresponding {@link DataPolicy} for the given {@link ClientRegionShortcut}. + * @see org.apache.geode.cache.client.ClientRegionShortcut + * @see org.apache.geode.cache.DataPolicy + */ + @Nullable @Override + public DataPolicy convert(ClientRegionShortcut clientRegionShortcut) { + + return Optional.ofNullable(ClientRegionShortcutWrapper.valueOf(clientRegionShortcut)) + .map(ClientRegionShortcutWrapper::getDataPolicy) + .orElse(DataPolicy.DEFAULT); + } +} diff --git a/src/main/java/org/springframework/data/gemfire/client/ClientRegionShortcutWrapper.java b/src/main/java/org/springframework/data/gemfire/client/ClientRegionShortcutWrapper.java index 9a1fe03f..dff0ca16 100644 --- a/src/main/java/org/springframework/data/gemfire/client/ClientRegionShortcutWrapper.java +++ b/src/main/java/org/springframework/data/gemfire/client/ClientRegionShortcutWrapper.java @@ -48,6 +48,7 @@ public enum ClientRegionShortcutWrapper { private final DataPolicy dataPolicy; public static ClientRegionShortcutWrapper valueOf(ClientRegionShortcut clientRegionShortcut) { + for (ClientRegionShortcutWrapper wrapper : values()) { if (ObjectUtils.nullSafeEquals(wrapper.getClientRegionShortcut(), clientRegionShortcut)) { return wrapper; diff --git a/src/main/java/org/springframework/data/gemfire/config/annotation/CachingDefinedRegionsConfiguration.java b/src/main/java/org/springframework/data/gemfire/config/annotation/CachingDefinedRegionsConfiguration.java index f5c3b5e6..2a2c2935 100644 --- a/src/main/java/org/springframework/data/gemfire/config/annotation/CachingDefinedRegionsConfiguration.java +++ b/src/main/java/org/springframework/data/gemfire/config/annotation/CachingDefinedRegionsConfiguration.java @@ -65,7 +65,7 @@ import org.springframework.core.type.AnnotationMetadata; import org.springframework.data.gemfire.client.ClientRegionFactoryBean; import org.springframework.data.gemfire.config.annotation.support.AbstractAnnotationConfigSupport; import org.springframework.data.gemfire.config.annotation.support.BeanDefinitionRegistryPostProcessorSupport; -import org.springframework.data.gemfire.config.annotation.support.GemFireCacheTypeAwareRegionFactoryBean; +import org.springframework.data.gemfire.config.annotation.support.CacheTypeAwareRegionFactoryBean; import org.springframework.data.gemfire.config.xml.GemfireConstants; import org.springframework.data.gemfire.util.CollectionUtils; import org.springframework.lang.Nullable; @@ -106,7 +106,7 @@ import org.springframework.util.StringUtils; * @see org.springframework.data.gemfire.config.annotation.EnableCachingDefinedRegions * @see org.springframework.data.gemfire.config.annotation.support.AbstractAnnotationConfigSupport * @see org.springframework.data.gemfire.config.annotation.support.BeanDefinitionRegistryPostProcessorSupport - * @see org.springframework.data.gemfire.config.annotation.support.GemFireCacheTypeAwareRegionFactoryBean + * @see CacheTypeAwareRegionFactoryBean * @since 2.0.0 */ @Configuration @@ -312,7 +312,7 @@ public class CachingDefinedRegionsConfiguration extends AbstractAnnotationConfig if (!registry.containsBeanDefinition(cacheName)) { BeanDefinitionBuilder builder = - BeanDefinitionBuilder.genericBeanDefinition(GemFireCacheTypeAwareRegionFactoryBean.class); + BeanDefinitionBuilder.genericBeanDefinition(CacheTypeAwareRegionFactoryBean.class); builder.addPropertyReference("cache", GemfireConstants.DEFAULT_GEMFIRE_CACHE_NAME); builder.addPropertyValue("clientRegionShortcut", resolveClientRegionShortcut()); @@ -352,8 +352,8 @@ public class CachingDefinedRegionsConfiguration extends AbstractAnnotationConfig if (!beanFactory.containsBean(cacheName)) { try { - GemFireCacheTypeAwareRegionFactoryBean regionFactoryBean = - new GemFireCacheTypeAwareRegionFactoryBean<>(); + CacheTypeAwareRegionFactoryBean regionFactoryBean = + new CacheTypeAwareRegionFactoryBean<>(); GemFireCache gemfireCache = beanFactory.getBean(GemfireConstants.DEFAULT_GEMFIRE_CACHE_NAME, GemFireCache.class); diff --git a/src/main/java/org/springframework/data/gemfire/config/annotation/EnableEntityDefinedRegions.java b/src/main/java/org/springframework/data/gemfire/config/annotation/EnableEntityDefinedRegions.java index b9672545..78454de0 100644 --- a/src/main/java/org/springframework/data/gemfire/config/annotation/EnableEntityDefinedRegions.java +++ b/src/main/java/org/springframework/data/gemfire/config/annotation/EnableEntityDefinedRegions.java @@ -25,12 +25,15 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import org.apache.geode.cache.Region; +import org.apache.geode.cache.RegionShortcut; +import org.apache.geode.cache.client.ClientRegionShortcut; import org.apache.geode.cache.client.Pool; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; import org.springframework.core.annotation.AliasFor; import org.springframework.data.gemfire.client.ClientRegionFactoryBean; +import org.springframework.data.gemfire.config.annotation.support.CacheTypeAwareRegionFactoryBean; import org.springframework.data.gemfire.mapping.annotation.ClientRegion; /** @@ -39,7 +42,14 @@ import org.springframework.data.gemfire.mapping.annotation.ClientRegion; * the application persistent entities. * * @author John Blum + * @see java.lang.annotation.Documented + * @see java.lang.annotation.Inherited + * @see java.lang.annotation.Retention + * @see java.lang.annotation.Target * @see org.apache.geode.cache.Region + * @see org.apache.geode.cache.RegionShortcut + * @see org.apache.geode.cache.client.ClientRegionShortcut + * @see org.apache.geode.cache.client.Pool * @see org.springframework.context.annotation.ComponentScan * @see org.springframework.context.annotation.ComponentScan.Filter * @see org.springframework.context.annotation.Import @@ -48,7 +58,7 @@ import org.springframework.data.gemfire.mapping.annotation.ClientRegion; * @see org.springframework.data.gemfire.client.ClientRegionFactoryBean * @see org.springframework.data.gemfire.config.annotation.EntityDefinedRegionsConfiguration * @see org.springframework.data.gemfire.config.annotation.IndexConfiguration - * @see org.springframework.data.gemfire.config.annotation.support.GemFireCacheTypeAwareRegionFactoryBean + * @see CacheTypeAwareRegionFactoryBean * @see org.springframework.data.gemfire.mapping.annotation.ClientRegion * @see org.springframework.data.gemfire.mapping.annotation.LocalRegion * @see org.springframework.data.gemfire.mapping.annotation.PartitionRegion @@ -61,6 +71,7 @@ import org.springframework.data.gemfire.mapping.annotation.ClientRegion; @Inherited @Documented @Import(IndexConfiguration.class) +@SuppressWarnings("unused") public @interface EnableEntityDefinedRegions { /** @@ -120,15 +131,35 @@ public @interface EnableEntityDefinedRegions { ComponentScan.Filter[] includeFilters() default {}; /** - * When this annotation is applied in a cache client application, the {@literal poolName} attribute refers to - * the default name of the GemFire/Geode {@link Pool} assigned to the client {@link Region Region(s)}. + * When this annotation is applied to a cache client application, the {@literal clientRegionShortcut} attribute + * indicates the default data policy applied to client {@link Region Regions} where the persistent entities + * are only annotated with the generic {@link org.springframework.data.gemfire.mapping.annotation.Region} + * mapping annotation, or the non-data policy specific mapping annotation. * - * This value can be overridden by annotating entities with th e{@link ClientRegion} annotation. + * Defaults to {@link ClientRegionShortcut#PROXY}. + */ + ClientRegionShortcut clientRegionShortcut() default ClientRegionShortcut.PROXY; + + /** + * When this annotation is applied to a cache client application, the {@literal poolName} attribute refers to + * the default name of the GemFire/Geode {@link Pool} assigned to client {@link Region Region(s)}. + * + * This value can be overridden by annotating entities with the {@link ClientRegion} annotation. * * Defaults to {@literal DEFAULT}. */ String poolName() default ClientRegionFactoryBean.DEFAULT_POOL_NAME; + /** + * When this annotation is applied to a peer cache application, the {@literal serverRegionShortcut} attribute + * indicates the default data policy applied to server {@link Region Regions} where the persistent entities + * are only annotated with the generic {@link org.springframework.data.gemfire.mapping.annotation.Region} + * mapping annotation, or the non-data policy specific mapping annotation. + * + * Defaults to {@link RegionShortcut#PARTITION}. + */ + RegionShortcut serverRegionShortcut() default RegionShortcut.PARTITION; + /** * Determines whether the created {@link Region} will have strongly-typed key and value constraints * based on the ID and {@link Class} type of application persistent entity. diff --git a/src/main/java/org/springframework/data/gemfire/config/annotation/EntityDefinedRegionsConfiguration.java b/src/main/java/org/springframework/data/gemfire/config/annotation/EntityDefinedRegionsConfiguration.java index 370c30f1..0a06a241 100644 --- a/src/main/java/org/springframework/data/gemfire/config/annotation/EntityDefinedRegionsConfiguration.java +++ b/src/main/java/org/springframework/data/gemfire/config/annotation/EntityDefinedRegionsConfiguration.java @@ -22,11 +22,10 @@ import static org.springframework.data.gemfire.util.ArrayUtils.defaultIfEmpty; import static org.springframework.data.gemfire.util.ArrayUtils.nullSafeArray; import static org.springframework.data.gemfire.util.CollectionUtils.nullSafeMap; import static org.springframework.data.gemfire.util.RuntimeExceptionFactory.newIllegalArgumentException; -import static org.springframework.data.gemfire.util.SpringUtils.safeGetValue; +import static org.springframework.data.gemfire.util.RuntimeExceptionFactory.newIllegalStateException; import java.lang.annotation.Annotation; import java.util.Collections; -import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; @@ -36,6 +35,8 @@ import java.util.regex.Pattern; import java.util.stream.Collectors; import org.apache.geode.cache.Region; +import org.apache.geode.cache.RegionShortcut; +import org.apache.geode.cache.Scope; import org.apache.geode.cache.client.ClientRegionShortcut; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.BeanFactory; @@ -55,16 +56,12 @@ import org.springframework.core.type.filter.AssignableTypeFilter; import org.springframework.core.type.filter.RegexPatternTypeFilter; import org.springframework.core.type.filter.TypeFilter; import org.springframework.data.gemfire.FixedPartitionAttributesFactoryBean; -import org.springframework.data.gemfire.LocalRegionFactoryBean; import org.springframework.data.gemfire.PartitionAttributesFactoryBean; -import org.springframework.data.gemfire.PartitionedRegionFactoryBean; import org.springframework.data.gemfire.RegionAttributesFactoryBean; -import org.springframework.data.gemfire.RegionLookupFactoryBean; -import org.springframework.data.gemfire.ReplicatedRegionFactoryBean; import org.springframework.data.gemfire.ScopeType; import org.springframework.data.gemfire.client.ClientRegionFactoryBean; import org.springframework.data.gemfire.config.annotation.support.AbstractAnnotationConfigSupport; -import org.springframework.data.gemfire.config.annotation.support.GemFireCacheTypeAwareRegionFactoryBean; +import org.springframework.data.gemfire.config.annotation.support.CacheTypeAwareRegionFactoryBean; import org.springframework.data.gemfire.config.annotation.support.GemFireComponentClassTypeScanner; import org.springframework.data.gemfire.config.xml.GemfireConstants; import org.springframework.data.gemfire.mapping.GemfireMappingContext; @@ -100,7 +97,7 @@ import org.springframework.util.StringUtils; * @see org.springframework.data.gemfire.RegionAttributesFactoryBean * @see org.springframework.data.gemfire.ReplicatedRegionFactoryBean * @see org.springframework.data.gemfire.client.ClientRegionFactoryBean - * @see org.springframework.data.gemfire.config.annotation.support.GemFireCacheTypeAwareRegionFactoryBean + * @see CacheTypeAwareRegionFactoryBean * @see org.springframework.data.gemfire.config.annotation.support.GemFireComponentClassTypeScanner * @see org.springframework.data.gemfire.mapping.GemfireMappingContext * @see org.springframework.data.gemfire.mapping.GemfirePersistentEntity @@ -115,21 +112,11 @@ import org.springframework.util.StringUtils; public class EntityDefinedRegionsConfiguration extends AbstractAnnotationConfigSupport implements ImportBeanDefinitionRegistrar { - protected static final Class DEFAULT_REGION_FACTORY_BEAN_CLASS = - GemFireCacheTypeAwareRegionFactoryBean.class; + protected static final ClientRegionShortcut DEFAULT_CLIENT_REGION_SHORTCUT = ClientRegionShortcut.PROXY; - protected static final Map, Class> regionAnnotationToRegionFactoryBeanClass = - new HashMap<>(); - - static { - regionAnnotationToRegionFactoryBeanClass.put(ClientRegion.class, ClientRegionFactoryBean.class); - regionAnnotationToRegionFactoryBeanClass.put(LocalRegion.class, LocalRegionFactoryBean.class); - regionAnnotationToRegionFactoryBeanClass.put(PartitionRegion.class, PartitionedRegionFactoryBean.class); - regionAnnotationToRegionFactoryBeanClass.put(ReplicateRegion.class, ReplicatedRegionFactoryBean.class); - regionAnnotationToRegionFactoryBeanClass.put(org.springframework.data.gemfire.mapping.annotation.Region.class, - DEFAULT_REGION_FACTORY_BEAN_CLASS); - } + protected static final RegionShortcut DEFAULT_SERVER_REGION_SHORTCUT = RegionShortcut.PARTITION; + @Autowired(required = false) private GemfireMappingContext mappingContext; @Autowired(required = false) @@ -167,17 +154,17 @@ public class EntityDefinedRegionsConfiguration extends AbstractAnnotationConfigS AnnotationAttributes enableEntityDefinedRegionsAttributes = getAnnotationAttributes(importingClassMetadata); - String poolName = enableEntityDefinedRegionsAttributes.getString("poolName"); - - boolean strict = enableEntityDefinedRegionsAttributes.getBoolean("strict"); - newGemFireComponentClassTypeScanner(importingClassMetadata, enableEntityDefinedRegionsAttributes).scan() - .forEach(persistentEntityClass -> { + .forEach(persistentEntityType -> { - GemfirePersistentEntity persistentEntity = getPersistentEntity(persistentEntityClass); + RegionBeanDefinitionMetadata regionMetadata = + RegionBeanDefinitionMetadata.with(getPersistentEntity(persistentEntityType)) + .using(enableEntityDefinedRegionsAttributes); - registerRegionBeanDefinition(persistentEntity, poolName, strict, registry); - postProcess(importingClassMetadata, registry, persistentEntity); + registerRegionBeanDefinition(regionMetadata, registry); + + postProcess(importingClassMetadata, registry, + regionMetadata.getPersistentEntity().orElse(null)); }); } } @@ -329,6 +316,7 @@ public class EntityDefinedRegionsConfiguration extends AbstractAnnotationConfigS protected GemfireMappingContext resolveMappingContext() { return Optional.ofNullable(this.mappingContext).orElseGet(() -> { + try { this.mappingContext = getBeanFactory().getBean(GemfireMappingContext.class); } @@ -344,36 +332,24 @@ public class EntityDefinedRegionsConfiguration extends AbstractAnnotationConfigS * Registers an individual bean definition in the Spring container for the {@link Region} determined from * the application domain object, {@link GemfirePersistentEntity persistent entity}. * - * @param persistentEntity {@link GemfirePersistentEntity} from which to the resolve the {@link Region}. - * @param strict boolean value indicating whether the key and value constraints on the {@link Region} should be set. + * @param regionMetadata {@link RegionBeanDefinitionMetadata} used to configure the {@link Region} bean definition. * @param registry {@link BeanDefinitionRegistry} used to register the {@link Region} bean definition * in the Spring context. * @see org.springframework.beans.factory.support.BeanDefinitionRegistry * @see org.springframework.data.gemfire.mapping.GemfirePersistentEntity */ - protected void registerRegionBeanDefinition(GemfirePersistentEntity persistentEntity, String poolName, - boolean strict, BeanDefinitionRegistry registry) { + protected void registerRegionBeanDefinition(RegionBeanDefinitionMetadata regionMetadata, + BeanDefinitionRegistry registry) { BeanDefinitionBuilder regionFactoryBeanBuilder = - BeanDefinitionBuilder.genericBeanDefinition(resolveRegionFactoryBeanClass(persistentEntity)) + BeanDefinitionBuilder.genericBeanDefinition(CacheTypeAwareRegionFactoryBean.class) .addPropertyReference("cache", GemfireConstants.DEFAULT_GEMFIRE_CACHE_NAME) - .addPropertyValue("regionConfigurers", resolveRegionConfigurers()) - .addPropertyValue("close", false); + .addPropertyValue("close", false) + .addPropertyValue("regionConfigurers", resolveRegionConfigurers()); - setRegionAttributes(persistentEntity, regionFactoryBeanBuilder, poolName, strict); + setRegionAttributes(regionFactoryBeanBuilder, regionMetadata); - registry.registerBeanDefinition(persistentEntity.getRegionName(), - regionFactoryBeanBuilder.getBeanDefinition()); - } - - /* (non-Javadoc) */ - @SuppressWarnings("unchecked") - protected Class resolveRegionFactoryBeanClass( - GemfirePersistentEntity persistentEntity) { - - return Optional.>ofNullable( - regionAnnotationToRegionFactoryBeanClass.get(persistentEntity.getRegionAnnotationType())) - .orElse(DEFAULT_REGION_FACTORY_BEAN_CLASS); + registry.registerBeanDefinition(regionMetadata.getRegionName(), regionFactoryBeanBuilder.getBeanDefinition()); } /* (non-Javadoc) */ @@ -385,34 +361,37 @@ public class EntityDefinedRegionsConfiguration extends AbstractAnnotationConfigS Optional.of(getBeanFactory()) .filter(beanFactory -> beanFactory instanceof ListableBeanFactory) .map(beanFactory -> { + Map beansOfType = ((ListableBeanFactory) beanFactory) .getBeansOfType(RegionConfigurer.class, true, true); return nullSafeMap(beansOfType).values().stream().collect(Collectors.toList()); + }) .orElseGet(Collections::emptyList) ); } /* (non-Javadoc) */ - protected BeanDefinitionBuilder setRegionAttributes(GemfirePersistentEntity persistentEntity, - BeanDefinitionBuilder regionFactoryBeanBuilder, String poolName, boolean strict) { + protected BeanDefinitionBuilder setRegionAttributes(BeanDefinitionBuilder regionFactoryBeanBuilder, + RegionBeanDefinitionMetadata regionMetadata) { - Optional.ofNullable(persistentEntity.getRegionAnnotation()).ifPresent(regionAnnotation -> { + Optional.ofNullable(regionMetadata.getRegionAnnotation()).ifPresent(regionAnnotation -> { AnnotationAttributes regionAnnotationAttributes = getAnnotationAttributes(regionAnnotation); - if (strict) { - regionFactoryBeanBuilder.addPropertyValue("keyConstraint", resolveIdType(persistentEntity)); - regionFactoryBeanBuilder.addPropertyValue("valueConstraint", resolveDomainType(persistentEntity)); - } + regionFactoryBeanBuilder.addPropertyValue("clientRegionShortcut", + resolveClientRegionShortcut(regionMetadata, regionAnnotation, regionAnnotationAttributes)); + + regionFactoryBeanBuilder.addPropertyValue("serverRegionShortcut", + resolveServerRegionShortcut(regionMetadata, regionAnnotation, regionAnnotationAttributes)); if (regionAnnotationAttributes.containsKey("diskStoreName")) { String diskStoreName = regionAnnotationAttributes.getString("diskStoreName"); - setPropertyValueIfNotDefault(regionFactoryBeanBuilder, "diskStoreName", diskStoreName, - ""); + setPropertyValueIfNotDefault(regionFactoryBeanBuilder, "diskStoreName", + diskStoreName, ""); if (StringUtils.hasText(diskStoreName)) { regionFactoryBeanBuilder.addDependsOn(diskStoreName); @@ -424,13 +403,19 @@ public class EntityDefinedRegionsConfiguration extends AbstractAnnotationConfigS regionAnnotationAttributes.getBoolean("ignoreIfExists")); } - if (regionAnnotationAttributes.containsKey("persistent")) { - setPropertyValueIfNotDefault(regionFactoryBeanBuilder, "persistent", - regionAnnotationAttributes.getBoolean("persistent"), false); + if (regionMetadata.isStrict()) { + regionFactoryBeanBuilder.addPropertyValue("keyConstraint", + regionMetadata.getRegionKeyConstraint()); + + regionFactoryBeanBuilder.addPropertyValue("valueConstraint", + regionMetadata.getRegionValueConstraint()); } BeanDefinitionBuilder regionAttributesFactoryBeanBuilder = - resolveRegionAttributesFactoryBeanBuilder(regionAnnotation, regionFactoryBeanBuilder); + BeanDefinitionBuilder.genericBeanDefinition(RegionAttributesFactoryBean.class); + + regionFactoryBeanBuilder.addPropertyValue("attributes", + regionAttributesFactoryBeanBuilder.getBeanDefinition()); if (regionAnnotationAttributes.containsKey("diskSynchronous")) { setPropertyValueIfNotDefault(regionAttributesFactoryBeanBuilder, "diskSynchronous", @@ -442,85 +427,70 @@ public class EntityDefinedRegionsConfiguration extends AbstractAnnotationConfigS regionAnnotationAttributes.getBoolean("ignoreJta"), false); } - setClientRegionAttributes(regionAnnotationAttributes, poolName, regionFactoryBeanBuilder); + setClientRegionAttributes(regionMetadata, regionAnnotationAttributes, regionFactoryBeanBuilder); - setPartitionRegionAttributes(regionAnnotationAttributes, regionFactoryBeanBuilder, + setPartitionRegionAttributes(regionMetadata, regionAnnotationAttributes, regionFactoryBeanBuilder, regionAttributesFactoryBeanBuilder); - setReplicateRegionAttributes(regionAnnotationAttributes, regionFactoryBeanBuilder); + setReplicateRegionAttributes(regionMetadata, regionAnnotationAttributes, regionFactoryBeanBuilder); }); return regionFactoryBeanBuilder; } - /* (non-Javadoc) */ - protected Class resolveDomainType(GemfirePersistentEntity persistentEntity) { - return persistentEntity.getType(); + protected ClientRegionShortcut resolveClientRegionShortcut(RegionBeanDefinitionMetadata regionMetadata, + Annotation regionAnnotation, AnnotationAttributes regionAnnotationAttributes) { + + return ClientRegion.class.equals(regionAnnotation.annotationType()) + ? regionAnnotationAttributes.getEnum("shortcut") + : regionMetadata.resolveClientRegionShortcut(DEFAULT_CLIENT_REGION_SHORTCUT); + } + + protected RegionShortcut resolveServerRegionShortcut(RegionBeanDefinitionMetadata regionMetadata, + Annotation regionAnnotation, AnnotationAttributes regionAnnotationAttributes) { + + Class regionAnnotationType = regionAnnotation.annotationType(); + + boolean persistent = (regionAnnotationAttributes.containsKey("persistent") + && regionAnnotationAttributes.getBoolean("persistent")); + + return LocalRegion.class.equals(regionAnnotationType) + ? (persistent ? RegionShortcut.LOCAL_PERSISTENT : RegionShortcut.LOCAL) + : PartitionRegion.class.equals(regionAnnotationType) + ? (persistent ? RegionShortcut.PARTITION_PERSISTENT : RegionShortcut.PARTITION) + : ReplicateRegion.class.equals(regionAnnotationType) + ? (persistent ? RegionShortcut.REPLICATE_PERSISTENT : RegionShortcut.REPLICATE) + : regionMetadata.resolveServerRegionShortcut(DEFAULT_SERVER_REGION_SHORTCUT); } /* (non-Javadoc) */ - @SuppressWarnings("unchecked") - protected Class resolveIdType(GemfirePersistentEntity persistentEntity) { + protected BeanDefinitionBuilder setClientRegionAttributes(RegionBeanDefinitionMetadata regionMetadata, + AnnotationAttributes regionAnnotationAttributes, BeanDefinitionBuilder regionFactoryBeanBuilder) { - return Optional.ofNullable(persistentEntity.getIdProperty()) - .map(idProperty -> ((GemfirePersistentProperty) idProperty).getActualType()) - .orElse((Class) Object.class); - } + String resolvedPoolName = regionAnnotationAttributes.containsKey("poolName") + ? regionAnnotationAttributes.getString("poolName") + : regionMetadata.getPoolName().orElse(ClientRegionFactoryBean.DEFAULT_POOL_NAME); - /* (non-Javadoc) */ - protected BeanDefinitionBuilder resolveRegionAttributesFactoryBeanBuilder(Annotation regionAnnotation, - BeanDefinitionBuilder regionFactoryBeanBuilder) { - - BeanDefinitionBuilder regionAttributesFactoryBeanBuilder = regionFactoryBeanBuilder; - - if (!ClientRegion.class.isAssignableFrom(regionAnnotation.annotationType())) { - regionAttributesFactoryBeanBuilder = - BeanDefinitionBuilder.genericBeanDefinition(RegionAttributesFactoryBean.class); - - regionFactoryBeanBuilder.addPropertyValue("attributes", - regionAttributesFactoryBeanBuilder.getBeanDefinition()); - } - - return regionAttributesFactoryBeanBuilder; - } - - /* (non-Javadoc) */ - protected BeanDefinitionBuilder setClientRegionAttributes(AnnotationAttributes regionAnnotationAttributes, - String poolName, BeanDefinitionBuilder regionFactoryBeanBuilder) { - - if (isPoolNameConfigured(regionAnnotationAttributes, poolName)) { - setPropertyValueIfNotDefault(regionFactoryBeanBuilder, "poolName", - regionAnnotationAttributes.getString("poolName"), null); - } - - if (regionAnnotationAttributes.containsKey("shortcut")) { - setPropertyValueIfNotDefault(regionFactoryBeanBuilder, "shortcut", - regionAnnotationAttributes.getEnum("shortcut"), ClientRegionShortcut.PROXY); - } + setPropertyValueIfNotDefault(regionFactoryBeanBuilder, "poolName", + resolvedPoolName, ClientRegionFactoryBean.DEFAULT_POOL_NAME); return regionFactoryBeanBuilder; } - private boolean isPoolNameConfigured(AnnotationAttributes regionAnnotationAttributes, String poolName) { - return (regionAnnotationAttributes.containsKey("poolName") - || !ClientRegionFactoryBean.DEFAULT_POOL_NAME.equals(poolName)); - } - - private String resolvePoolName(AnnotationAttributes regionAnnotationAttributes, String poolName) { - return safeGetValue(() -> regionAnnotationAttributes.getString("poolName"), poolName); - } - /* (non-Javadoc) */ - protected BeanDefinitionBuilder setPartitionRegionAttributes(AnnotationAttributes regionAnnotationAttributes, - BeanDefinitionBuilder regionFactoryBeanBuilder, BeanDefinitionBuilder regionAttributesFactoryBeanBuilder) { + protected BeanDefinitionBuilder setPartitionRegionAttributes(RegionBeanDefinitionMetadata regionMetadata, + AnnotationAttributes regionAnnotationAttributes, BeanDefinitionBuilder regionFactoryBeanBuilder, + BeanDefinitionBuilder regionAttributesFactoryBeanBuilder) { if (regionAnnotationAttributes.containsKey("redundantCopies")) { + BeanDefinitionBuilder partitionAttributesFactoryBeanBuilder = BeanDefinitionBuilder.genericBeanDefinition(PartitionAttributesFactoryBean.class); String collocatedWith = regionAnnotationAttributes.getString("collocatedWith"); - setPropertyValueIfNotDefault(partitionAttributesFactoryBeanBuilder, "colocatedWith", collocatedWith, ""); + setPropertyValueIfNotDefault(partitionAttributesFactoryBeanBuilder, "colocatedWith", + collocatedWith, ""); if (StringUtils.hasText(collocatedWith)) { regionFactoryBeanBuilder.addDependsOn(collocatedWith); @@ -554,10 +524,12 @@ public class EntityDefinedRegionsConfiguration extends AbstractAnnotationConfigS new ManagedList<>(fixedPartitions.length); for (PartitionRegion.FixedPartition fixedPartition : fixedPartitions) { + BeanDefinitionBuilder fixedPartitionAttributesFactoryBeanBuilder = BeanDefinitionBuilder.genericBeanDefinition(FixedPartitionAttributesFactoryBean.class); - fixedPartitionAttributesFactoryBeanBuilder.addPropertyValue("partitionName", fixedPartition.name()); + fixedPartitionAttributesFactoryBeanBuilder.addPropertyValue("partitionName", + fixedPartition.name()); setPropertyValueIfNotDefault(fixedPartitionAttributesFactoryBeanBuilder, "primary", fixedPartition.primary(), false); @@ -565,25 +537,25 @@ public class EntityDefinedRegionsConfiguration extends AbstractAnnotationConfigS setPropertyValueIfNotDefault(fixedPartitionAttributesFactoryBeanBuilder, "numBuckets", fixedPartition.numBuckets(), 1); - fixedPartitionAttributesFactoryBeans.add( - fixedPartitionAttributesFactoryBeanBuilder.getBeanDefinition()); + fixedPartitionAttributesFactoryBeans + .add(fixedPartitionAttributesFactoryBeanBuilder.getBeanDefinition()); } - partitionAttributesFactoryBeanBuilder.addPropertyValue("fixedPartitionAttributes", - fixedPartitionAttributesFactoryBeans); + partitionAttributesFactoryBeanBuilder + .addPropertyValue("fixedPartitionAttributes", fixedPartitionAttributesFactoryBeans); } return partitionAttributesFactoryBeanBuilder; } /* (non-Javadoc) */ - protected BeanDefinitionBuilder setReplicateRegionAttributes(AnnotationAttributes regionAnnotationAttributes, - BeanDefinitionBuilder regionFactoryBeanBuilder) { + protected BeanDefinitionBuilder setReplicateRegionAttributes(RegionBeanDefinitionMetadata regionMetadata, + AnnotationAttributes regionAnnotationAttributes, BeanDefinitionBuilder regionFactoryBeanBuilder) { if (regionAnnotationAttributes.containsKey("scope")) { setPropertyValueIfNotDefault(regionFactoryBeanBuilder, "scope", regionAnnotationAttributes.getEnum("scope").getScope(), - ScopeType.DISTRIBUTED_NO_ACK); + Scope.DISTRIBUTED_NO_ACK); } return regionFactoryBeanBuilder; @@ -624,4 +596,125 @@ public class EntityDefinedRegionsConfiguration extends AbstractAnnotationConfigS return persistentEntity; } + + /** + * The {@link RegionBeanDefinitionMetadata} class encapsulates details for creating a {@link Region} + * from application persistent entities. The details are captured during a persistent entity component scan. + * + * @see org.springframework.data.gemfire.mapping.GemfirePersistentEntity + */ + protected static class RegionBeanDefinitionMetadata { + + /** + * Factory method used to construct a new instance of the {@link RegionBeanDefinitionMetadata}. + * + * @return a new instance of {@link RegionBeanDefinitionMetadata}. + */ + protected static RegionBeanDefinitionMetadata with(GemfirePersistentEntity persistentEntity) { + return new RegionBeanDefinitionMetadata(persistentEntity); + } + + private boolean strict; + + private ClientRegionShortcut clientRegionShortcut; + + private GemfirePersistentEntity persistentEntity; + + private RegionShortcut serverRegionShortcut; + + private String poolName; + + protected RegionBeanDefinitionMetadata(GemfirePersistentEntity persistentEntity) { + this.persistentEntity = Optional.ofNullable(persistentEntity) + .orElseThrow(() -> newIllegalArgumentException("GemfirePeristentEntity is required")); + } + + protected boolean isStrict() { + return this.strict; + } + + protected Optional getClientRegionShortcut() { + return Optional.ofNullable(this.clientRegionShortcut); + } + + protected ClientRegionShortcut resolveClientRegionShortcut(ClientRegionShortcut defaultClientRegionShortcut) { + return getClientRegionShortcut().orElse(defaultClientRegionShortcut); + } + + protected Optional> getPersistentEntity() { + return Optional.ofNullable(this.persistentEntity); + } + + protected GemfirePersistentEntity resolvePersistentEntity() { + return getPersistentEntity().orElseThrow(() -> + newIllegalStateException("GemfirePersistentEntity could not be resolved")); + } + + protected Optional getPoolName() { + return Optional.ofNullable(this.poolName).filter(StringUtils::hasText); + } + + protected T getRegionAnnotation() { + return resolvePersistentEntity().getRegionAnnotation(); + } + + @SuppressWarnings("unchecked") + protected Class getRegionKeyConstraint() { + + return Optional.ofNullable(resolvePersistentEntity().getIdProperty()) + .map(idProperty -> ((GemfirePersistentProperty) idProperty).getActualType()) + .orElse((Class) Object.class); + } + + protected String getRegionName() { + return resolvePersistentEntity().getRegionName(); + } + + @SuppressWarnings("all") + protected Class getRegionValueConstraint() { + + return Optional.ofNullable(resolvePersistentEntity().getType()) + .orElse((Class) Object.class); + } + + protected Optional getServerRegionShortcut() { + return Optional.ofNullable(this.serverRegionShortcut); + } + + protected RegionShortcut resolveServerRegionShortcut(RegionShortcut defaultServerRegionShortcut) { + return getServerRegionShortcut().orElse(defaultServerRegionShortcut); + } + + protected RegionBeanDefinitionMetadata is(boolean strict) { + this.strict = strict; + return this; + } + + protected RegionBeanDefinitionMetadata using(AnnotationAttributes enableEntityDefinedRegionsAttributes) { + + return Optional.ofNullable(enableEntityDefinedRegionsAttributes) + .map(it -> + this.using(it.getEnum("clientRegionShortcut")) + .using(it.getString("poolName")) + .using(it.getEnum("serverRegionShortcut")) + .is(it.getBoolean("strict")) + ) + .orElse(this); + } + + protected RegionBeanDefinitionMetadata using(ClientRegionShortcut clientRegionShortcut) { + this.clientRegionShortcut = clientRegionShortcut; + return this; + } + + protected RegionBeanDefinitionMetadata using(RegionShortcut serverRegionShortcut) { + this.serverRegionShortcut = serverRegionShortcut; + return this; + } + + protected RegionBeanDefinitionMetadata using(String poolName) { + this.poolName = poolName; + return this; + } + } } diff --git a/src/main/java/org/springframework/data/gemfire/config/annotation/RegionConfigurer.java b/src/main/java/org/springframework/data/gemfire/config/annotation/RegionConfigurer.java index fec908d5..7705c519 100644 --- a/src/main/java/org/springframework/data/gemfire/config/annotation/RegionConfigurer.java +++ b/src/main/java/org/springframework/data/gemfire/config/annotation/RegionConfigurer.java @@ -20,6 +20,7 @@ import org.apache.geode.cache.Region; import org.springframework.context.annotation.Configuration; import org.springframework.data.gemfire.RegionFactoryBean; import org.springframework.data.gemfire.client.ClientRegionFactoryBean; +import org.springframework.data.gemfire.config.annotation.support.CacheTypeAwareRegionFactoryBean; /** * The {@link RegionConfigurer} interface defines a contract for implementations to customize the configuration @@ -31,7 +32,7 @@ import org.springframework.data.gemfire.client.ClientRegionFactoryBean; * @see org.springframework.data.gemfire.RegionFactoryBean * @see org.springframework.data.gemfire.client.ClientRegionFactoryBean * @see org.springframework.data.gemfire.config.annotation.EnableEntityDefinedRegions - * @see org.springframework.data.gemfire.config.annotation.support.GemFireCacheTypeAwareRegionFactoryBean + * @see CacheTypeAwareRegionFactoryBean * @since 1.1.0 */ public interface RegionConfigurer { diff --git a/src/main/java/org/springframework/data/gemfire/config/annotation/support/GemFireCacheTypeAwareRegionFactoryBean.java b/src/main/java/org/springframework/data/gemfire/config/annotation/support/CacheTypeAwareRegionFactoryBean.java similarity index 66% rename from src/main/java/org/springframework/data/gemfire/config/annotation/support/GemFireCacheTypeAwareRegionFactoryBean.java rename to src/main/java/org/springframework/data/gemfire/config/annotation/support/CacheTypeAwareRegionFactoryBean.java index 256cfb56..90340690 100644 --- a/src/main/java/org/springframework/data/gemfire/config/annotation/support/GemFireCacheTypeAwareRegionFactoryBean.java +++ b/src/main/java/org/springframework/data/gemfire/config/annotation/support/CacheTypeAwareRegionFactoryBean.java @@ -24,38 +24,55 @@ import java.util.Collections; import java.util.List; import java.util.Optional; +import org.apache.geode.cache.Cache; import org.apache.geode.cache.DataPolicy; import org.apache.geode.cache.GemFireCache; import org.apache.geode.cache.Region; import org.apache.geode.cache.RegionAttributes; import org.apache.geode.cache.RegionShortcut; +import org.apache.geode.cache.Scope; +import org.apache.geode.cache.client.ClientCache; import org.apache.geode.cache.client.ClientRegionShortcut; -import org.apache.geode.cache.client.PoolManager; import org.springframework.beans.factory.FactoryBean; import org.springframework.data.gemfire.GemfireUtils; import org.springframework.data.gemfire.GenericRegionFactoryBean; +import org.springframework.data.gemfire.LocalRegionFactoryBean; +import org.springframework.data.gemfire.PartitionedRegionFactoryBean; +import org.springframework.data.gemfire.RegionFactoryBean; import org.springframework.data.gemfire.RegionLookupFactoryBean; +import org.springframework.data.gemfire.RegionShortcutWrapper; +import org.springframework.data.gemfire.ReplicatedRegionFactoryBean; import org.springframework.data.gemfire.client.ClientRegionFactoryBean; import org.springframework.data.gemfire.config.annotation.RegionConfigurer; import org.springframework.util.StringUtils; /** - * The {@link GemFireCacheTypeAwareRegionFactoryBean} class is a smart Spring {@link FactoryBean} that knows how to - * create a client or server {@link Region} depending on whether the {@link GemFireCache} is - * a {@link org.apache.geode.cache.client.ClientCache} or a peer {@link org.apache.geode.cache.Cache}. + * The {@link CacheTypeAwareRegionFactoryBean} class is a smart Spring {@link FactoryBean} that knows how to + * create a client or server {@link Region} depending on whether the {@link GemFireCache} is a {@link ClientCache} + * or a peer {@link Cache}. * * @author John Blum + * @see org.apache.geode.cache.Cache + * @see org.apache.geode.cache.DataPolicy * @see org.apache.geode.cache.GemFireCache * @see org.apache.geode.cache.Region + * @see org.apache.geode.cache.RegionAttributes + * @see org.apache.geode.cache.RegionShortcut + * @see org.apache.geode.cache.Scope + * @see org.apache.geode.cache.client.ClientCache + * @see org.apache.geode.cache.client.ClientRegionShortcut * @see org.springframework.data.gemfire.GenericRegionFactoryBean - * @see org.springframework.data.gemfire.RegionLookupFactoryBean + * @see org.springframework.data.gemfire.LocalRegionFactoryBean + * @see org.springframework.data.gemfire.PartitionedRegionFactoryBean * @see org.springframework.data.gemfire.RegionFactoryBean + * @see org.springframework.data.gemfire.RegionLookupFactoryBean + * @see org.springframework.data.gemfire.ReplicatedRegionFactoryBean * @see org.springframework.data.gemfire.client.ClientRegionFactoryBean * @see org.springframework.data.gemfire.config.annotation.RegionConfigurer * @since 1.9.0 */ @SuppressWarnings("unused") -public class GemFireCacheTypeAwareRegionFactoryBean extends RegionLookupFactoryBean { +public class CacheTypeAwareRegionFactoryBean extends RegionLookupFactoryBean { private GemFireCache gemfireCache; @@ -74,6 +91,9 @@ public class GemFireCacheTypeAwareRegionFactoryBean extends RegionLookupFa private RegionShortcut serverRegionShortcut; + private Scope scope; + + private String diskStoreName; private String poolName; private String regionName; @@ -88,7 +108,7 @@ public class GemFireCacheTypeAwareRegionFactoryBean extends RegionLookupFa } /** - * Constructs a new client {@link Region} using the {@link ClientRegionFactoryBean}. + * Constructs, configures and initialize\s a new client {@link Region} using the {@link ClientRegionFactoryBean}. * * @param gemfireCache reference to the {@link GemFireCache} used to create/initialize the factory * used to create the client {@link Region}. @@ -98,22 +118,25 @@ public class GemFireCacheTypeAwareRegionFactoryBean extends RegionLookupFa * @see org.springframework.data.gemfire.client.ClientRegionFactoryBean * @see org.apache.geode.cache.GemFireCache * @see org.apache.geode.cache.Region + * @see #newClientRegionFactoryBean() */ protected Region newClientRegion(GemFireCache gemfireCache, String regionName) throws Exception { - ClientRegionFactoryBean clientRegionFactory = new ClientRegionFactoryBean<>(); + ClientRegionFactoryBean clientRegionFactory = newClientRegionFactoryBean(); clientRegionFactory.setAttributes(getRegionAttributes()); clientRegionFactory.setBeanFactory(getBeanFactory()); clientRegionFactory.setCache(gemfireCache); clientRegionFactory.setClose(isClose()); + clientRegionFactory.setDiskStoreName(getDiskStoreName()); clientRegionFactory.setKeyConstraint(getKeyConstraint()); + clientRegionFactory.setLookupEnabled(getLookupEnabled()); clientRegionFactory.setRegionConfigurers(this.regionConfigurers); clientRegionFactory.setRegionName(regionName); clientRegionFactory.setShortcut(getClientRegionShortcut()); clientRegionFactory.setValueConstraint(getValueConstraint()); - resolvePoolName().ifPresent(clientRegionFactory::setPoolName); + getPoolName().ifPresent(clientRegionFactory::setPoolName); clientRegionFactory.afterPropertiesSet(); @@ -121,7 +144,20 @@ public class GemFireCacheTypeAwareRegionFactoryBean extends RegionLookupFa } /** - * Constructs a new server {@link Region} using the {@link GenericRegionFactoryBean}. + * Constructs a new instance of the {@link ClientRegionFactoryBean}. + * + * @param {@link Class type} of the created {@link Region Region's} key. + * @param {@link Class type} of the created {@link Region Region's} value. + * @return a new instance of the {@link ClientRegionFactoryBean}. + * @see org.springframework.data.gemfire.client.ClientRegionFactoryBean + */ + protected ClientRegionFactoryBean newClientRegionFactoryBean() { + return new ClientRegionFactoryBean<>(); + } + + /** + * Constructs, configures and initializes a new server {@link Region} using a sub-class + * of {@link RegionFactoryBean}. * * @param gemfireCache reference to the {@link GemFireCache} used to create/initialize the factory * used to create the server {@link Region}. @@ -131,17 +167,20 @@ public class GemFireCacheTypeAwareRegionFactoryBean extends RegionLookupFa * @see org.springframework.data.gemfire.GenericRegionFactoryBean * @see org.apache.geode.cache.GemFireCache * @see org.apache.geode.cache.Region + * @see #newRegionFactoryBean() */ protected Region newServerRegion(GemFireCache gemfireCache, String regionName) throws Exception { - GenericRegionFactoryBean serverRegionFactory = new GenericRegionFactoryBean<>(); + RegionFactoryBean serverRegionFactory = newRegionFactoryBean(); serverRegionFactory.setAttributes(getRegionAttributes()); serverRegionFactory.setBeanFactory(getBeanFactory()); serverRegionFactory.setCache(gemfireCache); serverRegionFactory.setClose(isClose()); serverRegionFactory.setDataPolicy(getDataPolicy()); + serverRegionFactory.setDiskStoreName(getDiskStoreName()); serverRegionFactory.setKeyConstraint(getKeyConstraint()); + serverRegionFactory.setLookupEnabled(getLookupEnabled()); serverRegionFactory.setRegionConfigurers(this.regionConfigurers); serverRegionFactory.setRegionName(regionName); serverRegionFactory.setShortcut(getServerRegionShortcut()); @@ -152,6 +191,39 @@ public class GemFireCacheTypeAwareRegionFactoryBean extends RegionLookupFa return serverRegionFactory.getObject(); } + /** + * Constructs a {@link Class sub-type} of the {@link RegionFactoryBean} class based on + * the {@link #getServerRegionShortcut()} and {@link #getDataPolicy()}. + * + * @return a new instance of the {@link RegionFactoryBean}. + * @see org.springframework.data.gemfire.LocalRegionFactoryBean + * @see org.springframework.data.gemfire.PartitionedRegionFactoryBean + * @see org.springframework.data.gemfire.ReplicatedRegionFactoryBean + * @see org.springframework.data.gemfire.RegionFactoryBean + */ + protected RegionFactoryBean newRegionFactoryBean() { + + RegionShortcutWrapper regionShortcutWrapper = RegionShortcutWrapper.valueOf(getServerRegionShortcut()); + + DataPolicy resolvedDataPolicy = Optional.of(regionShortcutWrapper) + .map(RegionShortcutWrapper::getDataPolicy) + .orElseGet(this::getDataPolicy); + + if (regionShortcutWrapper.isLocal()) { + return new LocalRegionFactoryBean<>(); + } + else if (resolvedDataPolicy.withPartitioning()) { + return new PartitionedRegionFactoryBean<>(); + } + else if (resolvedDataPolicy.withReplication()) { + ReplicatedRegionFactoryBean replicatedRegionFactoryBean = new ReplicatedRegionFactoryBean<>(); + replicatedRegionFactoryBean.setScope(getScope()); + return replicatedRegionFactoryBean; + } + + return new GenericRegionFactoryBean<>(); + } + public void setAttributes(RegionAttributes regionAttributes) { this.regionAttributes = regionAttributes; } @@ -188,6 +260,14 @@ public class GemFireCacheTypeAwareRegionFactoryBean extends RegionLookupFa return Optional.ofNullable(this.dataPolicy).orElse(DataPolicy.DEFAULT); } + public void setDiskStoreName(String diskStoreName) { + this.diskStoreName = diskStoreName; + } + + protected String getDiskStoreName() { + return this.diskStoreName; + } + public void setKeyConstraint(Class keyConstraint) { this.keyConstraint = keyConstraint; } @@ -200,17 +280,12 @@ public class GemFireCacheTypeAwareRegionFactoryBean extends RegionLookupFa this.poolName = poolName; } - protected String getPoolName() { - return Optional.ofNullable(this.poolName).filter(StringUtils::hasText) - .orElse(ClientRegionFactoryBean.GEMFIRE_POOL_NAME); + protected Optional getPoolName() { + return Optional.ofNullable(this.poolName).filter(StringUtils::hasText); } - protected Optional resolvePoolName() { - return Optional.of(getPoolName()).filter(this::isPoolResolvable); - } - - private boolean isPoolResolvable(String poolName) { - return (getBeanFactory().containsBean(poolName) || (PoolManager.find(poolName) != null)); + protected String resolvePoolName() { + return getPoolName().orElse(null); } /** @@ -238,6 +313,14 @@ public class GemFireCacheTypeAwareRegionFactoryBean extends RegionLookupFa this.regionConfigurers = Optional.ofNullable(regionConfigurers).orElseGet(Collections::emptyList); } + public void setScope(Scope scope) { + this.scope = scope; + } + + protected Scope getScope() { + return this.scope; + } + public void setServerRegionShortcut(RegionShortcut shortcut) { this.serverRegionShortcut = shortcut; } diff --git a/src/main/java/org/springframework/data/gemfire/mapping/GemfirePersistentEntity.java b/src/main/java/org/springframework/data/gemfire/mapping/GemfirePersistentEntity.java index bebe913f..ffebd6ed 100644 --- a/src/main/java/org/springframework/data/gemfire/mapping/GemfirePersistentEntity.java +++ b/src/main/java/org/springframework/data/gemfire/mapping/GemfirePersistentEntity.java @@ -16,8 +16,6 @@ package org.springframework.data.gemfire.mapping; -import static org.springframework.data.gemfire.util.SpringUtils.defaultIfEmpty; - import java.lang.annotation.Annotation; import java.util.Optional; @@ -30,6 +28,7 @@ import org.springframework.data.mapping.PersistentEntity; import org.springframework.data.mapping.PersistentProperty; import org.springframework.data.mapping.model.BasicPersistentEntity; import org.springframework.data.util.TypeInformation; +import org.springframework.util.StringUtils; /** * {@link PersistentEntity} implementation adding custom GemFire persistent entity related metadata, such as the @@ -50,9 +49,11 @@ public class GemfirePersistentEntity extends BasicPersistentEntity persistentEntityType) { + for (Class regionAnnotationType : Region.REGION_ANNOTATION_TYPES) { - Annotation regionAnnotation = AnnotatedElementUtils.getMergedAnnotation( - persistentEntityType, regionAnnotationType); + + Annotation regionAnnotation = + AnnotatedElementUtils.getMergedAnnotation(persistentEntityType, regionAnnotationType); if (regionAnnotation != null) { return regionAnnotation; @@ -64,11 +65,11 @@ public class GemfirePersistentEntity extends BasicPersistentEntity persistentEntityType, Annotation regionAnnotation) { - String regionName = Optional.ofNullable(regionAnnotation) - .map((annotation) -> getAnnotationAttributeStringValue(annotation, "value")) - .orElse(null); - return defaultIfEmpty(regionName, persistentEntityType.getSimpleName()); + Optional regionName = Optional.ofNullable(regionAnnotation) + .map((annotation) -> getAnnotationAttributeStringValue(annotation, "value")); + + return regionName.filter(StringUtils::hasText).orElse(persistentEntityType.getSimpleName()); } /* (non-Javadoc) */ @@ -86,6 +87,7 @@ public class GemfirePersistentEntity extends BasicPersistentEntity information) { + super(information); Class rawType = information.getType(); diff --git a/src/test/java/org/springframework/data/gemfire/RegionFactoryBeanTest.java b/src/test/java/org/springframework/data/gemfire/RegionFactoryBeanTest.java index dd0c1ccd..11aad9d0 100644 --- a/src/test/java/org/springframework/data/gemfire/RegionFactoryBeanTest.java +++ b/src/test/java/org/springframework/data/gemfire/RegionFactoryBeanTest.java @@ -172,7 +172,8 @@ public class RegionFactoryBeanTest extends AbstractRegionFactoryBeanTests { @Test public void testAssertDataPolicyAndPersistentAttributesAreCompatible() { - RegionFactoryBean factoryBean = new TestRegionFactoryBean(); + + RegionFactoryBean factoryBean = new TestRegionFactoryBean<>(); factoryBean.setPersistent(null); factoryBean.assertDataPolicyAndPersistentAttributesAreCompatible(DataPolicy.PARTITION); @@ -189,8 +190,9 @@ public class RegionFactoryBeanTest extends AbstractRegionFactoryBeanTests { @Test(expected = IllegalArgumentException.class) public void testAssertNonPersistentDataPolicyWithPersistentAttribute() { + try { - RegionFactoryBean factoryBean = new TestRegionFactoryBean(); + RegionFactoryBean factoryBean = new TestRegionFactoryBean<>(); factoryBean.setPersistent(true); factoryBean.assertDataPolicyAndPersistentAttributesAreCompatible(DataPolicy.REPLICATE); } @@ -202,8 +204,9 @@ public class RegionFactoryBeanTest extends AbstractRegionFactoryBeanTests { @Test(expected = IllegalArgumentException.class) public void testAssertPersistentDataPolicyWithNonPersistentAttribute() { + try { - RegionFactoryBean factoryBean = new TestRegionFactoryBean(); + RegionFactoryBean factoryBean = new TestRegionFactoryBean<>(); factoryBean.setPersistent(false); factoryBean.assertDataPolicyAndPersistentAttributesAreCompatible(DataPolicy.PERSISTENT_PARTITION); } @@ -216,7 +219,8 @@ public class RegionFactoryBeanTest extends AbstractRegionFactoryBeanTests { @Test public void testIsPersistent() { - RegionFactoryBean factoryBean = new TestRegionFactoryBean(); + + RegionFactoryBean factoryBean = new TestRegionFactoryBean<>(); assertFalse(factoryBean.isPersistent()); @@ -231,7 +235,8 @@ public class RegionFactoryBeanTest extends AbstractRegionFactoryBeanTests { @Test public void testIsPersistentUnspecified() { - RegionFactoryBean factoryBean = new TestRegionFactoryBean(); + + RegionFactoryBean factoryBean = new TestRegionFactoryBean<>(); assertTrue(factoryBean.isPersistentUnspecified()); @@ -250,7 +255,8 @@ public class RegionFactoryBeanTest extends AbstractRegionFactoryBeanTests { @Test public void testIsNotPersistent() { - RegionFactoryBean factoryBean = new TestRegionFactoryBean(); + + RegionFactoryBean factoryBean = new TestRegionFactoryBean<>(); assertFalse(factoryBean.isNotPersistent()); @@ -265,20 +271,22 @@ public class RegionFactoryBeanTest extends AbstractRegionFactoryBeanTests { @Test public void testCreateRegionFactoryWithShortcut() { + Cache mockCache = mock(Cache.class); RegionAttributes mockRegionAttributes = mock(RegionAttributes.class); - final RegionFactory mockRegionFactory = createMockRegionFactory(); + RegionFactory mockRegionFactory = createMockRegionFactory(); when(mockCache.createRegionFactory(eq(RegionShortcut.PARTITION_REDUNDANT_PERSISTENT_OVERFLOW))) .thenReturn(mockRegionFactory); - final AtomicBoolean setDataPolicyCalled = new AtomicBoolean(false); + AtomicBoolean setDataPolicyCalled = new AtomicBoolean(false); RegionFactoryBean factoryBean = new RegionFactoryBean() { + @Override - DataPolicy getDataPolicy(final RegionFactory regionFactory) { + DataPolicy getDataPolicy(RegionFactory regionFactory, RegionShortcut regionShortcut) { return DataPolicy.PERSISTENT_PARTITION; } @@ -306,6 +314,7 @@ public class RegionFactoryBeanTest extends AbstractRegionFactoryBeanTests { @Test public void testCreateRegionFactoryWithAttributes() { + Cache mockCache = mock(Cache.class); RegionAttributes mockRegionAttributes = mock(RegionAttributes.class); @@ -325,7 +334,9 @@ public class RegionFactoryBeanTest extends AbstractRegionFactoryBeanTests { @Test public void testCreateRegionFactory() { + Cache mockCache = mock(Cache.class); + RegionFactory mockRegionFactory = createMockRegionFactory(); when(mockCache.createRegionFactory()).thenReturn(mockRegionFactory); @@ -342,11 +353,13 @@ public class RegionFactoryBeanTest extends AbstractRegionFactoryBeanTests { @Test public void testMergeRegionAttributes() throws Exception { + EvictionAttributes testEvictionAttributes = EvictionAttributes.createLRUEntryAttributes(); ExpirationAttributes testExpirationAttributes = new ExpirationAttributes(120, ExpirationAction.LOCAL_DESTROY); MembershipAttributes testMembershipAttributes = new MembershipAttributes(); - PartitionAttributes testPartitionAttributes = createPartitionAttributes("TestRegion", 1024000, 15000l, 0, - 45000l, 2048000000l, 97); + PartitionAttributes testPartitionAttributes = createPartitionAttributes("TestRegion", + 1024000, 15000L, 0, 45000L, + 2048000000L, 97); SubscriptionAttributes testSubscriptionAttributes = new SubscriptionAttributes(); RegionAttributes mockRegionAttributes = mock(RegionAttributes.class); @@ -421,6 +434,7 @@ public class RegionFactoryBeanTest extends AbstractRegionFactoryBeanTests { @Test public void testMergeRegionAttributesWithNull() { + RegionFactory mockRegionFactory = createMockRegionFactory(); factoryBean.mergeRegionAttributes(mockRegionFactory, null); @@ -456,6 +470,7 @@ public class RegionFactoryBeanTest extends AbstractRegionFactoryBeanTests { @Test public void testPartialMergeRegionAttributes() { + ExpirationAttributes testExpirationAttributes = new ExpirationAttributes(300, ExpirationAction.LOCAL_INVALIDATE); RegionAttributes mockRegionAttributes = mock(RegionAttributes.class); @@ -530,8 +545,10 @@ public class RegionFactoryBeanTest extends AbstractRegionFactoryBeanTests { @Test public void testMergePartitionAttributesWithPartitionRedundantProxy() throws Exception { - PartitionAttributes testPartitionAttributes = createPartitionAttributes("TestRegion", 512000, 15000l, 0, - 30000l, 1024000l, 51); + + PartitionAttributes testPartitionAttributes = createPartitionAttributes("TestRegion", + 512000, 15000L, 0, 30000L, + 1024000L, 51); RegionAttributes mockRegionAttributes = mock(RegionAttributes.class); RegionFactory mockRegionFactory = createTestRegionFactory(); @@ -549,10 +566,10 @@ public class RegionFactoryBeanTest extends AbstractRegionFactoryBeanTests { assertNotSame(testPartitionAttributes, actualPartitionAttributes); assertEquals("TestRegion", actualPartitionAttributes.getColocatedWith()); assertEquals(0, actualPartitionAttributes.getLocalMaxMemory()); - assertEquals(15000l, actualPartitionAttributes.getRecoveryDelay()); + assertEquals(15000L, actualPartitionAttributes.getRecoveryDelay()); assertEquals(1, actualPartitionAttributes.getRedundantCopies()); - assertEquals(30000l, actualPartitionAttributes.getStartupRecoveryDelay()); - assertEquals(1024000l, actualPartitionAttributes.getTotalMaxMemory()); + assertEquals(30000L, actualPartitionAttributes.getStartupRecoveryDelay()); + assertEquals(1024000L, actualPartitionAttributes.getTotalMaxMemory()); assertEquals(51, actualPartitionAttributes.getTotalNumBuckets()); verify(mockRegionAttributes, times(2)).getPartitionAttributes(); @@ -560,8 +577,10 @@ public class RegionFactoryBeanTest extends AbstractRegionFactoryBeanTests { @Test public void testMergePartitionAttributesWithPartitionRedundant() throws Exception { - PartitionAttributes testPartitionAttributes = createPartitionAttributes("TestRegion", 512000, 15000l, 0, - 30000l, 1024000l, 51); + + PartitionAttributes testPartitionAttributes = createPartitionAttributes("TestRegion", + 512000, 15000L, 0, 30000L, + 1024000L, 51); RegionAttributes mockRegionAttributes = mock(RegionAttributes.class); RegionFactory mockRegionFactory = createTestRegionFactory(); @@ -579,10 +598,10 @@ public class RegionFactoryBeanTest extends AbstractRegionFactoryBeanTests { assertNotSame(testPartitionAttributes, actualPartitionAttributes); assertEquals("TestRegion", actualPartitionAttributes.getColocatedWith()); assertEquals(512000, actualPartitionAttributes.getLocalMaxMemory()); - assertEquals(15000l, actualPartitionAttributes.getRecoveryDelay()); + assertEquals(15000L, actualPartitionAttributes.getRecoveryDelay()); assertEquals(1, actualPartitionAttributes.getRedundantCopies()); - assertEquals(30000l, actualPartitionAttributes.getStartupRecoveryDelay()); - assertEquals(1024000l, actualPartitionAttributes.getTotalMaxMemory()); + assertEquals(30000L, actualPartitionAttributes.getStartupRecoveryDelay()); + assertEquals(1024000L, actualPartitionAttributes.getTotalMaxMemory()); assertEquals(51, actualPartitionAttributes.getTotalNumBuckets()); verify(mockRegionAttributes, times(2)).getPartitionAttributes(); @@ -590,8 +609,10 @@ public class RegionFactoryBeanTest extends AbstractRegionFactoryBeanTests { @Test public void testMergePartitionAttributesWithPartitionRedundantPersistentOverflow() throws Exception { - PartitionAttributes testPartitionAttributes = createPartitionAttributes("TestRegion", 512000, 15000l, 3, - 30000l, 1024000l, 51); + + PartitionAttributes testPartitionAttributes = createPartitionAttributes("TestRegion", + 512000, 15000L, 3, 30000L, + 1024000L, 51); RegionAttributes mockRegionAttributes = mock(RegionAttributes.class); RegionFactory mockRegionFactory = createTestRegionFactory(); @@ -609,10 +630,10 @@ public class RegionFactoryBeanTest extends AbstractRegionFactoryBeanTests { assertNotSame(testPartitionAttributes, actualPartitionAttributes); assertEquals("TestRegion", actualPartitionAttributes.getColocatedWith()); assertEquals(512000, actualPartitionAttributes.getLocalMaxMemory()); - assertEquals(15000l, actualPartitionAttributes.getRecoveryDelay()); + assertEquals(15000L, actualPartitionAttributes.getRecoveryDelay()); assertEquals(3, actualPartitionAttributes.getRedundantCopies()); - assertEquals(30000l, actualPartitionAttributes.getStartupRecoveryDelay()); - assertEquals(1024000l, actualPartitionAttributes.getTotalMaxMemory()); + assertEquals(30000L, actualPartitionAttributes.getStartupRecoveryDelay()); + assertEquals(1024000L, actualPartitionAttributes.getTotalMaxMemory()); assertEquals(51, actualPartitionAttributes.getTotalNumBuckets()); verify(mockRegionAttributes, times(2)).getPartitionAttributes(); @@ -620,8 +641,10 @@ public class RegionFactoryBeanTest extends AbstractRegionFactoryBeanTests { @Test public void testMergePartitionAttributesWithPartitionProxy() throws Exception { - PartitionAttributes testPartitionAttributes = createPartitionAttributes("TestRegion", 512000, 15000l, 0, - 30000l, 1024000l, 51); + + PartitionAttributes testPartitionAttributes = createPartitionAttributes("TestRegion", + 512000, 15000L, 0, 30000L, + 1024000L, 51); RegionAttributes mockRegionAttributes = mock(RegionAttributes.class); RegionFactory mockRegionFactory = createTestRegionFactory(); @@ -639,10 +662,10 @@ public class RegionFactoryBeanTest extends AbstractRegionFactoryBeanTests { assertNotSame(testPartitionAttributes, actualPartitionAttributes); assertEquals("TestRegion", actualPartitionAttributes.getColocatedWith()); assertEquals(0, actualPartitionAttributes.getLocalMaxMemory()); - assertEquals(15000l, actualPartitionAttributes.getRecoveryDelay()); + assertEquals(15000L, actualPartitionAttributes.getRecoveryDelay()); assertEquals(0, actualPartitionAttributes.getRedundantCopies()); - assertEquals(30000l, actualPartitionAttributes.getStartupRecoveryDelay()); - assertEquals(1024000l, actualPartitionAttributes.getTotalMaxMemory()); + assertEquals(30000L, actualPartitionAttributes.getStartupRecoveryDelay()); + assertEquals(1024000L, actualPartitionAttributes.getTotalMaxMemory()); assertEquals(51, actualPartitionAttributes.getTotalNumBuckets()); verify(mockRegionAttributes, times(2)).getPartitionAttributes(); @@ -650,8 +673,10 @@ public class RegionFactoryBeanTest extends AbstractRegionFactoryBeanTests { @Test public void testMergePartitionAttributesWithPartition() throws Exception { - PartitionAttributes testPartitionAttributes = createPartitionAttributes("TestRegion", 512000, 15000l, 0, - 30000l, 1024000l, 51); + + PartitionAttributes testPartitionAttributes = createPartitionAttributes("TestRegion", + 512000, 15000L, 0, 30000L, + 1024000L, 51); RegionAttributes mockRegionAttributes = mock(RegionAttributes.class); RegionFactory mockRegionFactory = createTestRegionFactory(); @@ -669,10 +694,10 @@ public class RegionFactoryBeanTest extends AbstractRegionFactoryBeanTests { assertNotSame(testPartitionAttributes, actualPartitionAttributes); assertEquals("TestRegion", actualPartitionAttributes.getColocatedWith()); assertEquals(512000, actualPartitionAttributes.getLocalMaxMemory()); - assertEquals(15000l, actualPartitionAttributes.getRecoveryDelay()); + assertEquals(15000L, actualPartitionAttributes.getRecoveryDelay()); assertEquals(0, actualPartitionAttributes.getRedundantCopies()); - assertEquals(30000l, actualPartitionAttributes.getStartupRecoveryDelay()); - assertEquals(1024000l, actualPartitionAttributes.getTotalMaxMemory()); + assertEquals(30000L, actualPartitionAttributes.getStartupRecoveryDelay()); + assertEquals(1024000L, actualPartitionAttributes.getTotalMaxMemory()); assertEquals(51, actualPartitionAttributes.getTotalNumBuckets()); verify(mockRegionAttributes, times(2)).getPartitionAttributes(); @@ -680,7 +705,9 @@ public class RegionFactoryBeanTest extends AbstractRegionFactoryBeanTests { @Test public void testMergePartitionAttributes() { + RegionAttributes mockRegionAttributes = mock(RegionAttributes.class); + RegionFactory mockRegionFactory = createMockRegionFactory(); when(mockRegionAttributes.getPartitionAttributes()).thenReturn(null); @@ -694,29 +721,39 @@ public class RegionFactoryBeanTest extends AbstractRegionFactoryBeanTests { @Test public void testResolveDataPolicyWhenPersistentUnspecifiedAndDataPolicyUnspecified() { + RegionFactory mockRegionFactory = createMockRegionFactory(); + factoryBean.resolveDataPolicy(mockRegionFactory, null, (String) null); + verify(mockRegionFactory).setDataPolicy(eq(DataPolicy.DEFAULT)); } @Test public void testResolveDataPolicyWhenNotPersistentAndDataPolicyUnspecified() { + RegionFactory mockRegionFactory = createMockRegionFactory(); + factoryBean.setPersistent(false); factoryBean.resolveDataPolicy(mockRegionFactory, false, (String) null); + verify(mockRegionFactory).setDataPolicy(eq(DataPolicy.DEFAULT)); } @Test public void testResolveDataPolicyWhenPersistentAndDataPolicyUnspecified() { + RegionFactory mockRegionFactory = createMockRegionFactory(); + factoryBean.setPersistent(true); factoryBean.resolveDataPolicy(mockRegionFactory, true, (String) null); + verify(mockRegionFactory).setDataPolicy(eq(DataPolicy.PERSISTENT_REPLICATE)); } @Test(expected = IllegalArgumentException.class) public void testResolveDataPolicyWithBlankDataPolicyName() { + RegionFactory mockRegionFactory = createMockRegionFactory(); try { @@ -736,6 +773,7 @@ public class RegionFactoryBeanTest extends AbstractRegionFactoryBeanTests { @Test(expected = IllegalArgumentException.class) public void testResolveDataPolicyWithEmptyDataPolicyName() { + RegionFactory mockRegionFactory = createMockRegionFactory(); try { @@ -755,6 +793,7 @@ public class RegionFactoryBeanTest extends AbstractRegionFactoryBeanTests { @Test(expected = IllegalArgumentException.class) public void testResolveDataPolicyWithInvalidDataPolicyName() { + RegionFactory mockRegionFactory = createMockRegionFactory(); try { @@ -774,21 +813,28 @@ public class RegionFactoryBeanTest extends AbstractRegionFactoryBeanTests { @Test public void testResolveDataPolicyWhenPersistentUnspecifiedAndNormalDataPolicy() { + RegionFactory mockRegionFactory = createMockRegionFactory(); + factoryBean.resolveDataPolicy(mockRegionFactory, null, "NORMAL"); + verify(mockRegionFactory).setDataPolicy(eq(DataPolicy.NORMAL)); } @Test public void testResolveDataPolicyWhenNotPersistentAndPreloadedDataPolicy() { + RegionFactory mockRegionFactory = createMockRegionFactory(); + factoryBean.setPersistent(false); factoryBean.resolveDataPolicy(mockRegionFactory, false, "PRELOADED"); + verify(mockRegionFactory).setDataPolicy(eq(DataPolicy.PRELOADED)); } @Test(expected = IllegalArgumentException.class) public void testResolveDataPolicyWhenPersistentAndEmptyDataPolicy() { + RegionFactory mockRegionFactory = createMockRegionFactory(); try { @@ -809,20 +855,27 @@ public class RegionFactoryBeanTest extends AbstractRegionFactoryBeanTests { @Test public void testResolveDataPolicyWhenPersistentUnspecifiedAndPartitionDataPolicy() { + RegionFactory mockRegionFactory = createMockRegionFactory(); + factoryBean.resolveDataPolicy(mockRegionFactory, null, "PARTITION"); + verify(mockRegionFactory).setDataPolicy(eq(DataPolicy.PARTITION)); } @Test public void testResolveDataPolicyWhenPersistentUnspecifiedAndPersistentPartitionDataPolicy() { + RegionFactory mockRegionFactory = createMockRegionFactory(); + factoryBean.resolveDataPolicy(mockRegionFactory, null, "PERSISTENT_PARTITION"); + verify(mockRegionFactory).setDataPolicy(eq(DataPolicy.PERSISTENT_PARTITION)); } @Test(expected = IllegalArgumentException.class) public void testResolveDataPolicyWhenNotPersistentAndPersistentPartitionDataPolicy() { + RegionFactory mockRegionFactory = createMockRegionFactory(); try { @@ -843,6 +896,7 @@ public class RegionFactoryBeanTest extends AbstractRegionFactoryBeanTests { @Test(expected = IllegalArgumentException.class) public void testResolveDataPolicyWhenPersistentAndPartitionDataPolicy() { + RegionFactory mockRegionFactory = createMockRegionFactory(); try { @@ -866,54 +920,70 @@ public class RegionFactoryBeanTest extends AbstractRegionFactoryBeanTests { @Test public void testResolveDataPolicyWhenNotPersistentAndPartitionDataPolicy() { + RegionFactory mockRegionFactory = createMockRegionFactory(); + factoryBean.setPersistent(false); factoryBean.resolveDataPolicy(mockRegionFactory, false, "PARTITION"); + verify(mockRegionFactory).setDataPolicy(eq(DataPolicy.PARTITION)); } @Test public void testResolveDataPolicyWhenPersistentAndPersistentPartitionDataPolicy() { + RegionFactory mockRegionFactory = createMockRegionFactory(); + factoryBean.setPersistent(true); factoryBean.resolveDataPolicy(mockRegionFactory, true, "PERSISTENT_PARTITION"); + verify(mockRegionFactory).setDataPolicy(eq(DataPolicy.PERSISTENT_PARTITION)); } @Test public void testResolveDataPolicyWhenPersistentUnspecifiedAndRegionAttributesPreloadedDataPolicy() { + RegionFactory mockRegionFactory = createMockRegionFactory(); + factoryBean.setAttributes(createMockRegionAttributes(DataPolicy.PRELOADED)); factoryBean.setDataPolicy((DataPolicy) null); factoryBean.resolveDataPolicy(mockRegionFactory, null, (String) null); + verify(mockRegionFactory, times(1)).setDataPolicy(eq(DataPolicy.PRELOADED)); assertEquals(DataPolicy.PRELOADED, factoryBean.getDataPolicy()); } @Test public void testResolveDataPolicyWhenNotPersistentAndRegionAttributesPartitionDataPolicy() { + RegionFactory mockRegionFactory = createMockRegionFactory(); + factoryBean.setAttributes(createMockRegionAttributes(DataPolicy.PARTITION)); factoryBean.setDataPolicy((DataPolicy) null); factoryBean.setPersistent(false); factoryBean.resolveDataPolicy(mockRegionFactory, false, (String) null); + verify(mockRegionFactory, times(1)).setDataPolicy(eq(DataPolicy.PARTITION)); assertEquals(DataPolicy.PARTITION, factoryBean.getDataPolicy()); } @Test public void testResolveDataPolicyWhenPersistentAndRegionAttributesPersistentPartitionDataPolicy() { + RegionFactory mockRegionFactory = createMockRegionFactory(); + factoryBean.setAttributes(createMockRegionAttributes(DataPolicy.PERSISTENT_PARTITION)); factoryBean.setDataPolicy((DataPolicy) null); factoryBean.setPersistent(true); factoryBean.resolveDataPolicy(mockRegionFactory, true, (String) null); + verify(mockRegionFactory, times(1)).setDataPolicy(eq(DataPolicy.PERSISTENT_PARTITION)); assertEquals(DataPolicy.PERSISTENT_PARTITION, factoryBean.getDataPolicy()); } @Test(expected = IllegalArgumentException.class) public void testResolveDataPolicyWhenNotPersistentAndRegionAttributesPersistentPartitionDataPolicy() { + RegionFactory mockRegionFactory = createMockRegionFactory(); try { @@ -935,6 +1005,7 @@ public class RegionFactoryBeanTest extends AbstractRegionFactoryBeanTests { @Test(expected = IllegalArgumentException.class) public void testResolveDataPolicyWhenPersistentAndRegionAttributesPartitionDataPolicy() { + RegionFactory mockRegionFactory = createMockRegionFactory(); try { @@ -956,47 +1027,63 @@ public class RegionFactoryBeanTest extends AbstractRegionFactoryBeanTests { @Test public void testResolveDataPolicyWhenPersistentUnspecifiedAndUnspecifiedDataPolicy() { + RegionFactory mockRegionFactory = createMockRegionFactory(); + factoryBean.setAttributes(createMockRegionAttributes()); factoryBean.setPersistent(null); factoryBean.resolveDataPolicy(mockRegionFactory, null, (DataPolicy) null); + verify(mockRegionFactory).setDataPolicy(eq(DataPolicy.DEFAULT)); } @Test public void testResolveDataPolicyWhenNotPersistentAndUnspecifiedDataPolicy() { + RegionFactory mockRegionFactory = createMockRegionFactory(); + factoryBean.setAttributes(createMockRegionAttributes()); factoryBean.setPersistent(false); factoryBean.resolveDataPolicy(mockRegionFactory, false, (DataPolicy) null); + verify(mockRegionFactory).setDataPolicy(eq(DataPolicy.DEFAULT)); } @Test public void testResolveDataPolicyWhenPersistentAndUnspecifiedDataPolicy() { + RegionFactory mockRegionFactory = createMockRegionFactory(); + factoryBean.setAttributes(createMockRegionAttributes()); factoryBean.setPersistent(true); factoryBean.resolveDataPolicy(mockRegionFactory, true, (DataPolicy) null); + verify(mockRegionFactory).setDataPolicy(eq(DataPolicy.PERSISTENT_REPLICATE)); } @Test public void testResolveDataPolicyWhenPersistentUnspecifiedAndReplicateDataPolicy() { + RegionFactory mockRegionFactory = createMockRegionFactory(); + factoryBean.resolveDataPolicy(mockRegionFactory, null, DataPolicy.REPLICATE); + verify(mockRegionFactory).setDataPolicy(eq(DataPolicy.REPLICATE)); } @Test public void testResolveDataPolicyWhenPersistentUnspecifiedAndPersistentReplicateDataPolicy() { + RegionFactory mockRegionFactory = createMockRegionFactory(); + factoryBean.resolveDataPolicy(mockRegionFactory, null, DataPolicy.PERSISTENT_REPLICATE); + verify(mockRegionFactory).setDataPolicy(eq(DataPolicy.PERSISTENT_REPLICATE)); } @Test(expected = IllegalArgumentException.class) public void testResolveDataPolicyWhenNotPersistentAndPersistentReplicateDataPolicy() { + RegionFactory mockRegionFactory = createMockRegionFactory(); try { @@ -1018,6 +1105,7 @@ public class RegionFactoryBeanTest extends AbstractRegionFactoryBeanTests { @Test(expected = IllegalArgumentException.class) public void testResolveDataPolicyWhenPersistentAndReplicateDataPolicy() { + RegionFactory mockRegionFactory = createMockRegionFactory(); try { @@ -1039,17 +1127,23 @@ public class RegionFactoryBeanTest extends AbstractRegionFactoryBeanTests { @Test public void testResolveDataPolicyWhenNotPersistentAndReplicateDataPolicy() { + RegionFactory mockRegionFactory = createMockRegionFactory(); + factoryBean.setPersistent(false); factoryBean.resolveDataPolicy(mockRegionFactory, false, DataPolicy.REPLICATE); + verify(mockRegionFactory).setDataPolicy(eq(DataPolicy.REPLICATE)); } @Test public void testResolveDataPolicyWhenPersistentAndPersistentReplicateDataPolicy() { + RegionFactory mockRegionFactory = createMockRegionFactory(); + factoryBean.setPersistent(true); factoryBean.resolveDataPolicy(mockRegionFactory, true, DataPolicy.PERSISTENT_REPLICATE); + verify(mockRegionFactory).setDataPolicy(eq(DataPolicy.PERSISTENT_REPLICATE)); } diff --git a/src/test/java/org/springframework/data/gemfire/RegionShortcutToDataPolicyConverterUnitTests.java b/src/test/java/org/springframework/data/gemfire/RegionShortcutToDataPolicyConverterUnitTests.java new file mode 100644 index 00000000..bdc0a4cc --- /dev/null +++ b/src/test/java/org/springframework/data/gemfire/RegionShortcutToDataPolicyConverterUnitTests.java @@ -0,0 +1,192 @@ +/* + * Copyright 2017 the original author or authors. + * + * 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.springframework.data.gemfire; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.apache.geode.cache.DataPolicy; +import org.apache.geode.cache.RegionShortcut; +import org.junit.Test; + +/** + * Unit tests for {@link RegionShortcutToDataPolicyConverter}. + * + * @author John Blum + * @see org.junit.Test + * @see org.apache.geode.cache.DataPolicy + * @see org.apache.geode.cache.RegionShortcut + * @see org.springframework.data.gemfire.RegionShortcutToDataPolicyConverter + * @since 2.0.2 + */ +public class RegionShortcutToDataPolicyConverterUnitTests { + + protected void assertDataPolicy(DataPolicy actual, DataPolicy expected) { + assertThat(actual).isEqualTo(expected); + } + + protected void assertDataPolicyDefault(DataPolicy actual) { + assertDataPolicy(actual, DataPolicy.DEFAULT); + } + + protected void assertDataPolicyEmpty(DataPolicy actual) { + assertDataPolicy(actual, DataPolicy.EMPTY); + } + + protected void assertDataPolicyNormal(DataPolicy actual) { + assertDataPolicy(actual, DataPolicy.NORMAL); + } + + protected void assertDataPolicyPersistentPartition(DataPolicy actual) { + assertDataPolicy(actual, DataPolicy.PERSISTENT_PARTITION); + } + + protected void assertDataPolicyPersistentReplicate(DataPolicy actual) { + assertDataPolicy(actual, DataPolicy.PERSISTENT_REPLICATE); + } + + protected void assertDataPolicyPartition(DataPolicy actual) { + assertDataPolicy(actual, DataPolicy.PARTITION); + } + + protected void assertDataPolicyReplicate(DataPolicy actual) { + assertDataPolicy(actual, DataPolicy.REPLICATE); + } + + protected DataPolicy convert(RegionShortcut regionShortcut) { + return RegionShortcutToDataPolicyConverter.INSTANCE.convert(regionShortcut); + } + + @Test + public void nullRegionShortcutIsDataPolicyDefault() { + assertDataPolicyDefault(convert(null)); + } + + @Test + public void regionShortcutLocalIsDataPolicyNormal() { + assertDataPolicyNormal(convert(RegionShortcut.LOCAL)); + } + + @Test + public void regionShortcutLocalHeapLruIsDataPolicyNormal() { + assertDataPolicyNormal(convert(RegionShortcut.LOCAL_HEAP_LRU)); + } + + @Test + public void regionShortcutLocalOverflowIsDataPolicyNormal() { + assertDataPolicyNormal(convert(RegionShortcut.LOCAL_HEAP_LRU)); + } + + @Test + public void regionShortcutLocalPersistentIsDataPolicyPersistentReplicate() { + assertDataPolicyPersistentReplicate(convert(RegionShortcut.LOCAL_PERSISTENT)); + } + + @Test + public void regionShortcutLocalPersistentOverflowIsDataPolicyPersistentReplicate() { + assertDataPolicyPersistentReplicate(convert(RegionShortcut.LOCAL_PERSISTENT_OVERFLOW)); + } + + @Test + public void regionShortcutPartitionIsDataPolicyPartition() { + assertDataPolicyPartition(convert(RegionShortcut.PARTITION)); + } + + @Test + public void regionShortcutPartitionHeapLruIsDataPolicyPartition() { + assertDataPolicyPartition(convert(RegionShortcut.PARTITION_HEAP_LRU)); + } + + @Test + public void regionShortcutPartitionOverflowIsDataPolicyPartition() { + assertDataPolicyPartition(convert(RegionShortcut.PARTITION_OVERFLOW)); + } + + @Test + public void regionShortcutPartitionPersistentIsDataPolicyPersistentPartition() { + assertDataPolicyPersistentPartition(convert(RegionShortcut.PARTITION_PERSISTENT)); + } + + @Test + public void regionShortcutPartitionPersistentOverflowIsDataPolicyPersistentPartition() { + assertDataPolicyPersistentPartition(convert(RegionShortcut.PARTITION_PERSISTENT_OVERFLOW)); + } + + @Test + public void regionShortcutPartitionProxyIsDataPolicyPartition() { + assertDataPolicyPartition(convert(RegionShortcut.PARTITION_PROXY)); + } + + @Test + public void regionShortcutPartitionProxyRedundantIsDataPolicyPartition() { + assertDataPolicyPartition(convert(RegionShortcut.PARTITION_PROXY_REDUNDANT)); + } + + @Test + public void regionShortcutPartitionRedundantIsDataPolicyPartition() { + assertDataPolicyPartition(convert(RegionShortcut.PARTITION_REDUNDANT)); + } + + @Test + public void regionShortcutPartitionRedundantHeapLruIsDataPolicyPartition() { + assertDataPolicyPartition(convert(RegionShortcut.PARTITION_REDUNDANT_HEAP_LRU)); + } + + @Test + public void regionShortcutPartitionRedundantOverflowIsDataPolicyPartition() { + assertDataPolicyPartition(convert(RegionShortcut.PARTITION_REDUNDANT_HEAP_LRU)); + } + + @Test + public void regionShortcutPartitionRedundantPersistentIsDataPolicyPartition() { + assertDataPolicyPersistentPartition(convert(RegionShortcut.PARTITION_REDUNDANT_PERSISTENT)); + } + + @Test + public void regionShortcutPartitionRedundantPersistentOverflowIsDataPolicyPartition() { + assertDataPolicyPersistentPartition(convert(RegionShortcut.PARTITION_REDUNDANT_PERSISTENT_OVERFLOW)); + } + + @Test + public void regionShortcutReplicateIsDataPolicyReplicate() { + assertDataPolicyReplicate(convert(RegionShortcut.REPLICATE)); + } + + @Test + public void regionShortcutReplicateHeapLruIsDataPolicyReplicate() { + assertDataPolicyReplicate(convert(RegionShortcut.REPLICATE_HEAP_LRU)); + } + + @Test + public void regionShortcutReplicateOverflowIsDataPolicyReplicate() { + assertDataPolicyReplicate(convert(RegionShortcut.REPLICATE_OVERFLOW)); + } + + @Test + public void regionShortcutReplicatePersistentIsDataPolicyPersistentReplicate() { + assertDataPolicyPersistentReplicate(convert(RegionShortcut.REPLICATE_PERSISTENT)); + } + + @Test + public void regionShortcutReplicatePersistentOverflowIsDataPolicyPersistentReplicate() { + assertDataPolicyPersistentReplicate(convert(RegionShortcut.REPLICATE_PERSISTENT_OVERFLOW)); + } + + @Test + public void regionShortcutReplicateProxyIsDataPolicyPersistentReplicate() { + assertDataPolicyEmpty(convert(RegionShortcut.REPLICATE_PROXY)); + } +} diff --git a/src/test/java/org/springframework/data/gemfire/client/ClientRegionFactoryBeanTest.java b/src/test/java/org/springframework/data/gemfire/client/ClientRegionFactoryBeanTest.java index 1bd09c9f..c2c6b048 100644 --- a/src/test/java/org/springframework/data/gemfire/client/ClientRegionFactoryBeanTest.java +++ b/src/test/java/org/springframework/data/gemfire/client/ClientRegionFactoryBeanTest.java @@ -598,7 +598,7 @@ public class ClientRegionFactoryBeanTest { } protected Interest newInterest(K key) { - return new Interest(key); + return new Interest<>(key); } @Test diff --git a/src/test/java/org/springframework/data/gemfire/client/ClientRegionShortcutToDataPolicyConverterUnitTests.java b/src/test/java/org/springframework/data/gemfire/client/ClientRegionShortcutToDataPolicyConverterUnitTests.java new file mode 100644 index 00000000..9a89de94 --- /dev/null +++ b/src/test/java/org/springframework/data/gemfire/client/ClientRegionShortcutToDataPolicyConverterUnitTests.java @@ -0,0 +1,110 @@ +/* + * Copyright 2017 the original author or authors. + * + * 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.springframework.data.gemfire.client; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.apache.geode.cache.DataPolicy; +import org.apache.geode.cache.client.ClientRegionShortcut; +import org.junit.Test; + +/** + * Unit tests for {@link ClientRegionShortcutToDataPolicyConverter}. + * + * @author John Blum + * @see org.junit.Test + * @see org.apache.geode.cache.DataPolicy + * @see org.apache.geode.cache.client.ClientRegionShortcut + * @see org.springframework.data.gemfire.client.ClientRegionShortcutToDataPolicyConverter + * @since 2.0.2 + */ +public class ClientRegionShortcutToDataPolicyConverterUnitTests { + + protected void assertDataPolicy(DataPolicy actual, DataPolicy expected) { + assertThat(actual).isEqualTo(expected); + } + + protected void assertDataPolicyDefault(DataPolicy actual) { + assertDataPolicy(actual, DataPolicy.DEFAULT); + } + + protected void assertDataPolicyEmpty(DataPolicy actual) { + assertDataPolicy(actual, DataPolicy.EMPTY); + } + + protected void assertDataPolicyNormal(DataPolicy actual) { + assertDataPolicy(actual, DataPolicy.NORMAL); + } + + protected void assertDataPolicyPersistentReplicate(DataPolicy actual) { + assertDataPolicy(actual, DataPolicy.PERSISTENT_REPLICATE); + } + + protected DataPolicy convert(ClientRegionShortcut clientRegionShortcut) { + return ClientRegionShortcutToDataPolicyConverter.INSTANCE.convert(clientRegionShortcut); + } + + @Test + public void clientRegionShortcutCachingProxyIsDataPolicyNormal() { + assertDataPolicyNormal(convert(ClientRegionShortcut.CACHING_PROXY)); + } + + @Test + public void clientRegionShortcutCachingProxyHeapLruIsDataPolicyNormal() { + assertDataPolicyNormal(convert(ClientRegionShortcut.CACHING_PROXY_HEAP_LRU)); + } + + @Test + public void clientRegionShortcutCachingProxyOverflowIsDataPolicyNormal() { + assertDataPolicyNormal(convert(ClientRegionShortcut.CACHING_PROXY_OVERFLOW)); + } + + @Test + public void clientRegionShortcutLocalIsDataPolicyNormal() { + assertDataPolicyNormal(convert(ClientRegionShortcut.LOCAL)); + } + + @Test + public void clientRegionShortcutLocalHeapLruIsDataPolicyNormal() { + assertDataPolicyNormal(convert(ClientRegionShortcut.LOCAL_HEAP_LRU)); + } + + @Test + public void clientRegionShortcutLocalOverflowIsDataPolicyNormal() { + assertDataPolicyNormal(convert(ClientRegionShortcut.LOCAL_OVERFLOW)); + } + + @Test + public void clientRegionShortcutLocalPersistentIsDataPolicyPersistentReplicate() { + assertDataPolicyPersistentReplicate(convert(ClientRegionShortcut.LOCAL_PERSISTENT)); + } + + @Test + public void clientRegionShortcutLocalPersistentOverflowIsDataPolicyPersistentReplicate() { + assertDataPolicyPersistentReplicate(convert(ClientRegionShortcut.LOCAL_PERSISTENT_OVERFLOW)); + } + + @Test + public void clientRegionShortcutLocalProxyIsDataPolicyEmpty() { + assertDataPolicyEmpty(convert(ClientRegionShortcut.PROXY)); + } + + @Test + public void nullClientRegionShortcutIsDataPolicyDefault() { + assertDataPolicyDefault(convert(null)); + } +} diff --git a/src/test/java/org/springframework/data/gemfire/config/annotation/CacheServerPropertiesIntegrationTests.java b/src/test/java/org/springframework/data/gemfire/config/annotation/CacheServerPropertiesIntegrationTests.java index 1906891e..4e391149 100644 --- a/src/test/java/org/springframework/data/gemfire/config/annotation/CacheServerPropertiesIntegrationTests.java +++ b/src/test/java/org/springframework/data/gemfire/config/annotation/CacheServerPropertiesIntegrationTests.java @@ -58,7 +58,7 @@ public class CacheServerPropertiesIntegrationTests { } private ConfigurableApplicationContext newApplicationContext(PropertySource testPropertySource, - Class... annotatedClasses) { + Class... annotatedClasses) { AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(); diff --git a/src/test/java/org/springframework/data/gemfire/config/annotation/EnableEntityDefinedRegionsUnitTests.java b/src/test/java/org/springframework/data/gemfire/config/annotation/EnableEntityDefinedRegionsUnitTests.java index ca9b4ddd..0247b763 100644 --- a/src/test/java/org/springframework/data/gemfire/config/annotation/EnableEntityDefinedRegionsUnitTests.java +++ b/src/test/java/org/springframework/data/gemfire/config/annotation/EnableEntityDefinedRegionsUnitTests.java @@ -17,24 +17,17 @@ package org.springframework.data.gemfire.config.annotation; +import static java.util.Arrays.stream; import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyBoolean; -import static org.mockito.Matchers.anyString; -import static org.mockito.Matchers.eq; import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; +import static org.springframework.data.gemfire.util.ArrayUtils.length; +import static org.springframework.data.gemfire.util.ArrayUtils.nullSafeArray; import static org.springframework.data.gemfire.util.CollectionUtils.nullSafeList; import static org.springframework.data.gemfire.util.RegionUtils.toRegionPath; -import java.util.HashSet; import java.util.List; import java.util.Optional; -import java.util.Set; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.atomic.AtomicReference; -import org.apache.geode.cache.Cache; import org.apache.geode.cache.DataPolicy; import org.apache.geode.cache.DiskStore; import org.apache.geode.cache.FixedPartitionAttributes; @@ -44,25 +37,21 @@ import org.apache.geode.cache.PartitionResolver; import org.apache.geode.cache.Region; import org.apache.geode.cache.RegionAttributes; import org.apache.geode.cache.RegionExistsException; -import org.apache.geode.cache.RegionFactory; +import org.apache.geode.cache.RegionShortcut; import org.apache.geode.cache.Scope; -import org.apache.geode.cache.client.ClientCache; -import org.apache.geode.cache.client.ClientRegionFactory; import org.apache.geode.cache.client.ClientRegionShortcut; +import org.apache.geode.cache.client.Pool; import org.junit.After; import org.junit.Test; -import org.mockito.stubbing.Answer; import org.springframework.beans.factory.BeanCreationException; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; -import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.FilterType; import org.springframework.context.annotation.Lazy; import org.springframework.data.gemfire.PartitionedRegionFactoryBean; import org.springframework.data.gemfire.ReplicatedRegionFactoryBean; -import org.springframework.data.gemfire.client.ClientRegionShortcutWrapper; import org.springframework.data.gemfire.config.annotation.test.entities.ClientRegionEntity; import org.springframework.data.gemfire.config.annotation.test.entities.CollocatedPartitionRegionEntity; import org.springframework.data.gemfire.config.annotation.test.entities.GenericRegionEntity; @@ -74,6 +63,8 @@ import org.springframework.data.gemfire.mapping.annotation.ClientRegion; import org.springframework.data.gemfire.mapping.annotation.LocalRegion; import org.springframework.data.gemfire.mapping.annotation.PartitionRegion; import org.springframework.data.gemfire.mapping.annotation.ReplicateRegion; +import org.springframework.data.gemfire.test.mock.MockObjectsSupport; +import org.springframework.data.gemfire.test.mock.annotation.EnableGemFireMockObjects; /** * Unit tests for the {@link EnableEntityDefinedRegions} annotation and {@link EntityDefinedRegionsConfiguration} class. @@ -81,31 +72,38 @@ import org.springframework.data.gemfire.mapping.annotation.ReplicateRegion; * @author John Blum * @see org.junit.Test * @see org.mockito.Mockito + * @see org.apache.geode.cache.GemFireCache + * @see org.apache.geode.cache.Region + * @see org.springframework.context.ConfigurableApplicationContext + * @see org.springframework.context.annotation.AnnotationConfigApplicationContext + * @see org.springframework.context.annotation.Bean * @see org.springframework.data.gemfire.config.annotation.EnableEntityDefinedRegions * @see org.springframework.data.gemfire.config.annotation.EntityDefinedRegionsConfiguration + * @see org.springframework.data.gemfire.mapping.annotation.ClientRegion + * @see org.springframework.data.gemfire.mapping.annotation.LocalRegion + * @see org.springframework.data.gemfire.mapping.annotation.PartitionRegion + * @see org.springframework.data.gemfire.mapping.annotation.ReplicateRegion + * @see org.springframework.data.gemfire.mapping.annotation.ReplicateRegion + * @see org.springframework.data.gemfire.test.mock.MockObjectsSupport + * @see org.springframework.data.gemfire.test.mock.annotation.EnableGemFireMockObjects * @since 1.9.0 */ public class EnableEntityDefinedRegionsUnitTests { - private static final AtomicInteger MOCK_ID = new AtomicInteger(0); - - private static final Set> cacheRegions = new HashSet<>(); - private ConfigurableApplicationContext applicationContext; @After public void tearDown() { Optional.ofNullable(this.applicationContext).ifPresent(ConfigurableApplicationContext::close); - cacheRegions.clear(); } /* (non-Javadoc) */ - protected void assertRegion(Region region, String name) { + protected void assertRegion(Region region, String name) { assertRegion(region, name, toRegionPath(name), null, null); } /* (non-Javadoc) */ - protected void assertRegion(Region region, String name, + protected void assertRegion(Region region, String name, Class keyConstraint, Class valueConstraint) { assertRegion(region, name, toRegionPath(name), keyConstraint, valueConstraint); @@ -113,12 +111,12 @@ public class EnableEntityDefinedRegionsUnitTests { /* (non-Javadoc) */ @SuppressWarnings("unused") - protected void assertRegion(Region region, String name, String fullPath) { + protected void assertRegion(Region region, String name, String fullPath) { assertRegion(region, name, fullPath, null, null); } /* (non-Javadoc) */ - protected void assertRegion(Region region, String name, String fullPath, + protected void assertRegion(Region region, String name, String fullPath, Class keyConstraint, Class valueConstraint) { assertThat(region).isNotNull(); @@ -130,7 +128,17 @@ public class EnableEntityDefinedRegionsUnitTests { } /* (non-Javadoc) */ - protected void assertRegionAttributes(RegionAttributes regionAttributes, DataPolicy dataPolicy, + protected void assertRegionWithAttributes(Region region, String name, DataPolicy dataPolicy, + String diskStoreName, Boolean diskSynchronous, Boolean ignoreJta, String poolName, Scope scope) { + + assertRegion(region, name); + assertThat(region.getAttributes()).isNotNull(); + assertRegionAttributes(region.getAttributes(), dataPolicy, diskStoreName, diskSynchronous, ignoreJta, + poolName, scope); + } + + /* (non-Javadoc) */ + protected void assertRegionAttributes(RegionAttributes regionAttributes, DataPolicy dataPolicy, String diskStoreName, Boolean diskSynchronous, Boolean ignoreJta, String poolName, Scope scope) { assertThat(regionAttributes).isNotNull(); @@ -143,7 +151,7 @@ public class EnableEntityDefinedRegionsUnitTests { } /* (non-Javadoc) */ - protected void assertPartitionAttributes(PartitionAttributes partitionAttributes, + protected void assertPartitionAttributes(PartitionAttributes partitionAttributes, String collocatedWith, PartitionResolver partitionResolver, Integer redundantCopies) { assertThat(partitionAttributes).isNotNull(); @@ -162,6 +170,14 @@ public class EnableEntityDefinedRegionsUnitTests { assertThat(fixedPartitionAttributes.getNumBuckets()).isEqualTo(numBuckets); } + protected void assertUndefinedRegions(String... regionBeanNames) { + + stream(nullSafeArray(regionBeanNames, String.class)).forEach(regionBeanName -> + assertThat(this.applicationContext.containsBean(regionBeanName)).isFalse()); + + assertThat(this.applicationContext.getBeansOfType(Region.class)).hasSize(11 - length(regionBeanNames)); + } + /* (non-Javadoc) */ @SuppressWarnings("unchecked") protected FixedPartitionAttributes findFixedPartitionAttributes(PartitionAttributes partitionAttributes, @@ -192,40 +208,102 @@ public class EnableEntityDefinedRegionsUnitTests { @SuppressWarnings("unchecked") public void entityClientRegionsDefined() { - applicationContext = newApplicationContext(ClientPersistentEntitiesConfiguration.class); + this.applicationContext = newApplicationContext(ClientPersistentEntitiesConfiguration.class); - Region sessions = applicationContext.getBean("Sessions", Region.class); + Region sessions = this.applicationContext.getBean("Sessions", Region.class); assertRegion(sessions, "Sessions", String.class, ClientRegionEntity.class); - assertRegionAttributes(sessions.getAttributes(), DataPolicy.NORMAL, null, true, - false, null, null); + assertRegionAttributes(sessions.getAttributes(), DataPolicy.NORMAL, + null, true, false, null, null); Region genericRegionEntity = - applicationContext.getBean("GenericRegionEntity", Region.class); + this.applicationContext.getBean("GenericRegionEntity", Region.class); assertRegion(genericRegionEntity, "GenericRegionEntity", Long.class, GenericRegionEntity.class); - assertRegionAttributes(genericRegionEntity.getAttributes(), DataPolicy.EMPTY, null, - true, false, null, null); + assertRegionAttributes(genericRegionEntity.getAttributes(), DataPolicy.EMPTY, + null, true, false, null, null); - assertThat(applicationContext.containsBean("CollocatedPartitionRegionEntity")).isFalse(); - assertThat(applicationContext.containsBean("ContactEvents")).isFalse(); - assertThat(applicationContext.containsBean("NonEntity")).isFalse(); - assertThat(applicationContext.containsBean("Accounts")).isFalse(); - assertThat(applicationContext.containsBean("Customers")).isFalse(); - assertThat(applicationContext.containsBean("LocalRegionEntity")).isFalse(); - assertThat(applicationContext.containsBean("PartitionRegionEntity")).isFalse(); - assertThat(applicationContext.containsBean("ReplicateRegionEntity")).isFalse(); + assertUndefinedRegions("ClientRegionEntity", "CollocatedPartitionRegionEntity", + "ContactEvents", "LocalRegionEntity", "NonEntity", "PartitionRegionEntity", "Customers", + "ReplicateRegionEntity", "Accounts"); + } + + @Test + @SuppressWarnings("unchecked") + public void entityClientRegionsDefinedWithCustomConfiguration() { + + this.applicationContext = newApplicationContext(ClientPersistentEntitiesWithCustomConfiguration.class); + + Region sessions = this.applicationContext.getBean("Sessions", Region.class); + + assertRegionWithAttributes(sessions, "Sessions", DataPolicy.NORMAL, + null, true, false, null, null); + + Region genericRegionEntity = + this.applicationContext.getBean("GenericRegionEntity", Region.class); + + assertRegionWithAttributes(genericRegionEntity, "GenericRegionEntity", DataPolicy.NORMAL, + null, true, false, "TestPool", null); + + assertUndefinedRegions("ClientRegionEntity", "CollocatedPartitionRegionEntity", + "ContactEvents", "LocalRegionEntity", "NonEntity", "PartitionRegionEntity", "Customers", + "ReplicateRegionEntity", "Accounts"); + } + + @Test + @SuppressWarnings("unchecked") + public void entityClientRegionsDefinedWithServerRegionMappingAnnotations() { + + this.applicationContext = + newApplicationContext(ClientPersistentEntitiesWithServerRegionMappingAnnotationsConfiguration.class); + + Region sessions = this.applicationContext.getBean("Sessions", Region.class); + + assertRegion(sessions, "Sessions", String.class, ClientRegionEntity.class); + assertRegionAttributes(sessions.getAttributes(), DataPolicy.NORMAL, + null, true, false, null, null); + + Region genericRegionEntity = + this.applicationContext.getBean("GenericRegionEntity", Region.class); + + assertRegion(genericRegionEntity, "GenericRegionEntity", Long.class, GenericRegionEntity.class); + assertRegionAttributes(genericRegionEntity.getAttributes(), DataPolicy.EMPTY, + null, true, false, null, null); + + Region localRegionEntity = + this.applicationContext.getBean("LocalRegionEntity", Region.class); + + assertRegion(localRegionEntity, "LocalRegionEntity", String.class, LocalRegionEntity.class); + assertRegionAttributes(localRegionEntity.getAttributes(), DataPolicy.EMPTY, + null, true, false, null, null); + + Region customers = + this.applicationContext.getBean("Customers", Region.class); + + assertRegion(customers, "Customers", Long.class, PartitionRegionEntity.class); + assertRegionAttributes(customers.getAttributes(), DataPolicy.EMPTY, + null, true, false, null, null); + + Region accounts = + this.applicationContext.getBean("Accounts", Region.class); + + assertRegion(accounts, "Accounts", Object.class, ReplicateRegionEntity.class); + assertRegionAttributes(accounts.getAttributes(), DataPolicy.EMPTY, + null, true, false, null, null); + + assertUndefinedRegions("ClientRegionEntity", "CollocatedPartitionRegionEntity", + "ContactEvents", "NonEntity", "PartitionRegionEntity", "ReplicateRegionEntity"); } @Test @SuppressWarnings("unchecked") public void entityPeerPartitionRegionsDefined() { - applicationContext = newApplicationContext(PeerPartitionRegionPersistentEntitiesConfiguration.class); - Region customers = applicationContext.getBean("Customers", Region.class); + this.applicationContext = newApplicationContext(PeerPartitionRegionPersistentEntitiesConfiguration.class); - assertRegion(customers, "Customers"); - assertRegionAttributes(customers.getAttributes(), DataPolicy.PERSISTENT_PARTITION, null, + Region customers = this.applicationContext.getBean("Customers", Region.class); + + assertRegionWithAttributes(customers, "Customers", DataPolicy.PERSISTENT_PARTITION, null, true, false, null, Scope.DISTRIBUTED_NO_ACK); assertPartitionAttributes(customers.getAttributes().getPartitionAttributes(), null, null, 1); @@ -234,30 +312,26 @@ public class EnableEntityDefinedRegionsUnitTests { assertFixedPartitionAttributes(findFixedPartitionAttributes(customers.getAttributes().getPartitionAttributes(), "two"), "two", false, 21); - Region contactEvents = applicationContext.getBean("ContactEvents", Region.class); + Region contactEvents = this.applicationContext.getBean("ContactEvents", Region.class); - assertRegion(contactEvents, "ContactEvents"); - assertRegionAttributes(contactEvents.getAttributes(), DataPolicy.PERSISTENT_PARTITION, + assertRegionWithAttributes(contactEvents, "ContactEvents", DataPolicy.PERSISTENT_PARTITION, "mockDiskStore", false, true, null, Scope.DISTRIBUTED_NO_ACK); assertPartitionAttributes(contactEvents.getAttributes().getPartitionAttributes(), "Customers", - applicationContext.getBean("mockPartitionResolver", PartitionResolver.class), 2); + this.applicationContext.getBean("mockPartitionResolver", PartitionResolver.class), 2); - assertThat(applicationContext.getBean("mockDiskStore")).isInstanceOf(DiskStore.class); - assertThat(applicationContext.containsBean("ClientRegion")).isFalse(); - assertThat(applicationContext.containsBean("NonEntity")).isFalse(); - assertThat(applicationContext.containsBean("Accounts")).isFalse(); - assertThat(applicationContext.containsBean("LocalRegionEntity")).isFalse(); - assertThat(applicationContext.containsBean("PartitionRegionEntity")).isFalse(); - assertThat(applicationContext.containsBean("ReplicateRegionEntity")).isFalse(); - assertThat(applicationContext.containsBean("Sessions")).isFalse(); + assertUndefinedRegions("ClientRegionEntity", "Sessions", "CollocatedPartitionRegionEntity", + "GenericRegionEntity", "LocalRegionEntity", "NonEntity", "PartitionRegionEntity", "ReplicateRegionEntity", + "Accounts"); } @Test(expected = RegionExistsException.class) - public void entityPeerPartitionRegionAlreadyDefinedThrowsRegionExistsException() { + public void entityPartitionRegionAlreadyDefinedThrowsRegionExistsException() { + try { - applicationContext = newApplicationContext(ExistingPartitionRegionPersistentEntitiesConfiguration.class); + this.applicationContext = newApplicationContext(ExistingPartitionRegionPersistentEntitiesConfiguration.class); } catch (BeanCreationException expected) { + assertThat(expected).hasCauseInstanceOf(RegionExistsException.class); assertThat(expected.getCause()).hasMessage("/Customers"); @@ -268,332 +342,209 @@ public class EnableEntityDefinedRegionsUnitTests { @Test @SuppressWarnings("unchecked") public void entityReplicateRegionAlreadyDefinedIgnoresEntityDefinedRegionDefinition() { - applicationContext = newApplicationContext(ExistingReplicateRegionPersistentEntitiesConfiguration.class); - Region accounts = applicationContext.getBean("Accounts", Region.class); + this.applicationContext = newApplicationContext(ExistingReplicateRegionPersistentEntitiesConfiguration.class); - assertRegion(accounts, "Accounts"); - assertRegionAttributes(accounts.getAttributes(), DataPolicy.REPLICATE, null, true, - false, null, Scope.DISTRIBUTED_NO_ACK); + Region accounts = this.applicationContext.getBean("Accounts", Region.class); + + assertRegionWithAttributes(accounts, "Accounts", DataPolicy.REPLICATE, + null, true, false, null, Scope.DISTRIBUTED_NO_ACK); } @Test @SuppressWarnings("unchecked") public void entityServerRegionsDefined() { - applicationContext = newApplicationContext(ServerPersistentEntitiesConfiguration.class); - Region accounts = applicationContext.getBean("Accounts", Region.class); + this.applicationContext = newApplicationContext(ServerPersistentEntitiesConfiguration.class); - assertRegion(accounts, "Accounts"); - assertRegionAttributes(accounts.getAttributes(), DataPolicy.REPLICATE, null, true, - false, null, Scope.DISTRIBUTED_ACK); + Region accounts = this.applicationContext.getBean("Accounts", Region.class); - Region customers = applicationContext.getBean("Customers", Region.class); + assertRegionWithAttributes(accounts, "Accounts", DataPolicy.REPLICATE, + null, true, false, null, Scope.DISTRIBUTED_ACK); - assertRegion(customers, "Customers"); - assertRegionAttributes(customers.getAttributes(), DataPolicy.PERSISTENT_PARTITION, + Region customers = this.applicationContext.getBean("Customers", Region.class); + + assertRegionWithAttributes(customers, "Customers", DataPolicy.PERSISTENT_PARTITION, null, true, false, null, Scope.DISTRIBUTED_NO_ACK); assertPartitionAttributes(customers.getAttributes().getPartitionAttributes(), null, null, 1); - Region localRegionEntity = applicationContext.getBean("LocalRegionEntity", Region.class); + Region localRegionEntity = this.applicationContext.getBean("LocalRegionEntity", Region.class); - assertRegion(localRegionEntity, "LocalRegionEntity"); - assertRegionAttributes(localRegionEntity.getAttributes(), DataPolicy.NORMAL, + assertRegionWithAttributes(localRegionEntity, "LocalRegionEntity", DataPolicy.NORMAL, null, true, false, null, Scope.LOCAL); Region genericRegionEntity = - applicationContext.getBean("GenericRegionEntity", Region.class); + this.applicationContext.getBean("GenericRegionEntity", Region.class); - assertRegion(genericRegionEntity, "GenericRegionEntity"); - assertRegionAttributes(genericRegionEntity.getAttributes(), DataPolicy.NORMAL, + assertRegionWithAttributes(genericRegionEntity, "GenericRegionEntity", DataPolicy.PARTITION, null, true, false, null, Scope.DISTRIBUTED_NO_ACK); - assertThat(applicationContext.containsBean("CollocatedPartitionRegionEntity")).isFalse(); - assertThat(applicationContext.containsBean("ContactEvents")).isFalse(); - assertThat(applicationContext.containsBean("NonEntity")).isFalse(); - assertThat(applicationContext.containsBean("PartitionRegionEntity")).isFalse(); - assertThat(applicationContext.containsBean("ReplicateRegionEntity")).isFalse(); - assertThat(applicationContext.containsBean("Sessions")).isFalse(); + assertUndefinedRegions("ClientRegionEntity", "Sessions", "CollocatedPartitionRegionEntity", + "ContactEvents", "NonEntity", "PartitionRegionEntity", "ReplicateRegionEntity"); } - /* (non-Javadoc) */ - protected static String mockName(String baseMockName) { - return String.format("%s%d", baseMockName, MOCK_ID.incrementAndGet()); - } - - /* (non-Javadoc) */ + @Test @SuppressWarnings("unchecked") - protected static Cache mockCache() { - Cache mockCache = mock(Cache.class); + public void entityServerRegionsDefinedWithCustomConfiguration() { - Answer> createRegionFactory = invocation -> { - RegionAttributes defaultRegionAttributes = mockRegionAttributes(null, - null, true, false, null, null, - null, Scope.DISTRIBUTED_NO_ACK, null); + this.applicationContext = newApplicationContext(ServerPersistentEntitiesWithCustomConfiguration.class); - RegionAttributes regionAttributes = (invocation.getArguments().length == 1 - ? invocation.getArgument(0) : defaultRegionAttributes); + Region accounts = this.applicationContext.getBean("Sessions", Region.class); - return mockRegionFactory(mockCache, regionAttributes); - }; + assertRegionWithAttributes(accounts, "Sessions", DataPolicy.REPLICATE, + null, true, false, null, Scope.DISTRIBUTED_NO_ACK); - when(mockCache.createRegionFactory()).thenAnswer(createRegionFactory); - when(mockCache.createRegionFactory(any(RegionAttributes.class))).thenAnswer(createRegionFactory); + Region genericRegionEntity = + this.applicationContext.getBean("GenericRegionEntity", Region.class); - return mockCache; + assertRegionWithAttributes(genericRegionEntity, "GenericRegionEntity", DataPolicy.REPLICATE, + null, true, false, null, Scope.DISTRIBUTED_NO_ACK); + + Region localRegionEntity = + this.applicationContext.getBean("LocalRegionEntity", Region.class); + + assertRegionWithAttributes(localRegionEntity, "LocalRegionEntity", DataPolicy.NORMAL, + null, true, false, null, Scope.LOCAL); + + Region customers = this.applicationContext.getBean("Customers", Region.class); + + assertRegionWithAttributes(customers, "Customers", DataPolicy.PERSISTENT_PARTITION, + null, true, false, null, Scope.DISTRIBUTED_NO_ACK); + + assertUndefinedRegions("ClientRegionEntity", "CollocatedPartitionRegionEntity", + "ContactEvents", "NonEntity", "PartitionRegionEntity", "ReplicateRegionEntity", "Accounts"); } - protected static ClientCache mockClientCache() { - - ClientCache mockClientCache = mock(ClientCache.class, mockName("ClientCache")); - - Answer> createClientRegionFactory = - invocation -> mockClientRegionFactory(invocation.getArgument(0)); - - when(mockClientCache.createClientRegionFactory(any(ClientRegionShortcut.class))) - .thenAnswer(createClientRegionFactory); - - return mockClientCache; - } - - /* (non-Javadoc) */ + @Test @SuppressWarnings("unchecked") - protected static ClientRegionFactory mockClientRegionFactory(ClientRegionShortcut shortcut) { - ClientRegionFactory mockClientRegionFactory = - mock(ClientRegionFactory.class, mockName("MockClientRegionFactory")); + public void entityServerRegionsDefinedWithClientRegionMappingAnnotations() { - AtomicReference diskStoreName = new AtomicReference<>(); - AtomicReference diskSynchronous = new AtomicReference<>(true); - AtomicReference keyConstraint = new AtomicReference<>(null); - AtomicReference poolName = new AtomicReference<>(); - AtomicReference valueConstraint = new AtomicReference<>(null); + this.applicationContext = + newApplicationContext(ServerPersistentEntitiesWithClientRegionMappingAnnotationsConfiguration.class); - when(mockClientRegionFactory.setDiskStoreName(anyString())).thenAnswer( - newSetter(String.class, diskStoreName, mockClientRegionFactory)); + Region sessions = this.applicationContext.getBean("Sessions", Region.class); - when(mockClientRegionFactory.setDiskSynchronous(anyBoolean())).thenAnswer( - newSetter(Boolean.TYPE, diskSynchronous, mockClientRegionFactory)); + assertRegionWithAttributes(sessions, "Sessions", DataPolicy.PARTITION, + null, true, false, null, Scope.DISTRIBUTED_NO_ACK); - when(mockClientRegionFactory.setKeyConstraint(any(Class.class))).thenAnswer( - newSetter(Class.class, keyConstraint, mockClientRegionFactory)); + Region genericRegionEntity = + this.applicationContext.getBean("GenericRegionEntity", Region.class); - when(mockClientRegionFactory.setPoolName(anyString())).thenAnswer( - newSetter(String.class, poolName, mockClientRegionFactory)); + assertRegionWithAttributes(genericRegionEntity, "GenericRegionEntity", DataPolicy.PARTITION, + null, true, false, null, Scope.DISTRIBUTED_NO_ACK); - when(mockClientRegionFactory.setValueConstraint(any(Class.class))).thenAnswer( - newSetter(Class.class, valueConstraint, mockClientRegionFactory)); + Region customers = + this.applicationContext.getBean("Customers", Region.class); - RegionAttributes mockRegionAttributes = - mock(RegionAttributes.class, mockName("MockClientRegionAttributes")); + assertRegionWithAttributes(customers, "Customers", DataPolicy.PERSISTENT_PARTITION, + null, true, false, null, Scope.DISTRIBUTED_NO_ACK); - when(mockRegionAttributes.getDataPolicy()).thenReturn( - ClientRegionShortcutWrapper.valueOf(shortcut).getDataPolicy()); - when(mockRegionAttributes.getDiskStoreName()).thenAnswer(newGetter(diskStoreName)); - when(mockRegionAttributes.isDiskSynchronous()).thenAnswer(newGetter(diskSynchronous)); - when(mockRegionAttributes.getKeyConstraint()).thenAnswer(newGetter(keyConstraint)); - when(mockRegionAttributes.getPoolName()).thenAnswer(newGetter(poolName)); - when(mockRegionAttributes.getValueConstraint()).thenAnswer(newGetter(valueConstraint)); - - when(mockClientRegionFactory.create(anyString())).thenAnswer(invocation -> { - String regionName = invocation.getArgument(0); - - cacheRegions.stream().filter(region -> region.getName().equals(regionName)).findAny() - .ifPresent(region -> { throw new RegionExistsException(region); }); - - Region region = mockRegion(regionName, mockRegionAttributes); - - cacheRegions.add(region); - - return region; - }); - - return mockClientRegionFactory; + assertUndefinedRegions("ClientRegionEntity", "CollocatedPartitionRegionEntity", + "ContactEvents", "LocalRegionEntity", "NonEntity", "PartitionRegionEntity", "ReplicateRegionEntity", + "Accounts"); } - /* (non-Javadoc) */ - @SuppressWarnings("unchecked") - protected static RegionAttributes mockRegionAttributes(DataPolicy dataPolicy, - String diskStoreName, boolean diskSynchronous, boolean ignoreJta, Class keyConstraint, - PartitionAttributes partitionAttributes, String poolName, Scope scope, Class valueConstraint) { - - RegionAttributes mockRegionAttributes = - mock(RegionAttributes.class, mockName("MockRegionAttributes")); - - when(mockRegionAttributes.getDataPolicy()).thenReturn(dataPolicy); - when(mockRegionAttributes.getDiskStoreName()).thenReturn(diskStoreName); - when(mockRegionAttributes.isDiskSynchronous()).thenReturn(diskSynchronous); - when(mockRegionAttributes.getIgnoreJTA()).thenReturn(ignoreJta); - when(mockRegionAttributes.getKeyConstraint()).thenReturn(keyConstraint); - when(mockRegionAttributes.getPartitionAttributes()).thenReturn(partitionAttributes); - when(mockRegionAttributes.getPoolName()).thenReturn(poolName); - when(mockRegionAttributes.getScope()).thenReturn(scope); - when(mockRegionAttributes.getValueConstraint()).thenReturn(valueConstraint); - - return mockRegionAttributes; + @ClientCacheApplication + @EnableGemFireMockObjects + @EnableEntityDefinedRegions(basePackageClasses = NonEntity.class, strict = true, excludeFilters = + @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = { + LocalRegion.class, PartitionRegion.class, ReplicateRegion.class + }) + ) + static class ClientPersistentEntitiesConfiguration { } - /* (non-Javadoc) */ - @SuppressWarnings("unchecked") - protected static RegionFactory mockRegionFactory(GemFireCache mockCache, - RegionAttributes regionAttributes) { - - RegionFactory mockRegionFactory = mock(RegionFactory.class, mockName("MockRegionFactory")); - - AtomicReference dataPolicy = new AtomicReference<>(regionAttributes.getDataPolicy()); - AtomicReference diskStoreName = new AtomicReference<>(regionAttributes.getDiskStoreName()); - AtomicReference diskSynchronous = new AtomicReference<>(regionAttributes.isDiskSynchronous()); - AtomicReference ignoreJta = new AtomicReference<>(regionAttributes.getIgnoreJTA()); - AtomicReference keyConstraint = new AtomicReference<>(null); - AtomicReference partitionAttributes = - new AtomicReference<>(regionAttributes.getPartitionAttributes()); - AtomicReference scope = new AtomicReference<>(regionAttributes.getScope()); - AtomicReference valueConstraint = new AtomicReference<>(null); - - when(mockRegionFactory.setDataPolicy(any(DataPolicy.class))).thenAnswer( - newSetter(DataPolicy.class, dataPolicy, mockRegionFactory)); - - when(mockRegionFactory.setDiskStoreName(anyString())).thenAnswer( - newSetter(String.class, diskStoreName, mockRegionFactory)); - - when(mockRegionFactory.setDiskSynchronous(anyBoolean())).thenAnswer( - newSetter(Boolean.TYPE, diskSynchronous, mockRegionFactory)); - - when(mockRegionFactory.setIgnoreJTA(anyBoolean())).thenAnswer( - newSetter(Boolean.TYPE, ignoreJta, mockRegionFactory)); - - when(mockRegionFactory.setKeyConstraint(any(Class.class))).thenAnswer( - newSetter(Class.class, keyConstraint, mockRegionFactory)); - - when(mockRegionFactory.setPartitionAttributes(any(PartitionAttributes.class))).thenAnswer( - newSetter(PartitionAttributes.class, partitionAttributes, mockRegionFactory)); - - when(mockRegionFactory.setScope(any(Scope.class))).thenAnswer( - newSetter(Scope.class, scope, mockRegionFactory)); - - when(mockRegionFactory.setValueConstraint(any(Class.class))).thenAnswer( - newSetter(Class.class, valueConstraint, mockRegionFactory)); - - RegionAttributes mockRegionAttributes = - mock(RegionAttributes.class, mockName("MockRegionAttributes")); - - when(mockRegionAttributes.getDataPolicy()).thenAnswer(newGetter(dataPolicy)); - when(mockRegionAttributes.getDiskStoreName()).thenAnswer(newGetter(diskStoreName)); - when(mockRegionAttributes.isDiskSynchronous()).thenAnswer(newGetter(diskSynchronous)); - when(mockRegionAttributes.getIgnoreJTA()).thenAnswer(newGetter(ignoreJta)); - when(mockRegionAttributes.getKeyConstraint()).thenAnswer(newGetter(keyConstraint)); - when(mockRegionAttributes.getPartitionAttributes()).thenAnswer(newGetter(partitionAttributes)); - when(mockRegionAttributes.getScope()).thenAnswer(newGetter(scope)); - when(mockRegionAttributes.getValueConstraint()).thenAnswer(newGetter(valueConstraint)); - - when(mockRegionFactory.create(anyString())).thenAnswer(invocation -> { - String regionName = invocation.getArgument(0); - - cacheRegions.stream().filter(region -> region.getName().equals(regionName)).findAny() - .ifPresent(region -> { throw new RegionExistsException(region); }); - - Region mockRegion = mockRegion(regionName, mockRegionAttributes); - - cacheRegions.add(mockRegion); - - when(mockCache.getRegion(eq(regionName))).thenReturn((Region) mockRegion); - when(mockRegion.getRegionService()).thenReturn(mockCache); - - return mockRegion; - }); - - return mockRegionFactory; - } - - /* (non-Javadoc) */ - @SuppressWarnings("unchecked") - protected static Region mockRegion(String name, RegionAttributes regionAttributes) { - Region mockRegion = mock(Region.class, mockName(name)); - - when(mockRegion.getName()).thenReturn(name); - when(mockRegion.getFullPath()).thenReturn(toRegionPath(name)); - when(mockRegion.getAttributes()).thenReturn(regionAttributes); - - return mockRegion; - } - - /* (non-Javadoc) */ - protected static Answer newGetter(AtomicReference returnValue) { - return invocation -> returnValue.get(); - } - - /* (non-Javadoc) */ + @ClientCacheApplication + @EnableGemFireMockObjects @SuppressWarnings("unused") - protected static Answer newSetter(Class parameterType, AtomicReference argument, R returnValue) { + @EnableEntityDefinedRegions(basePackageClasses = NonEntity.class, clientRegionShortcut = ClientRegionShortcut.LOCAL, + poolName = "TestPool", excludeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION, + classes = { LocalRegion.class, PartitionRegion.class, ReplicateRegion.class }) + ) + static class ClientPersistentEntitiesWithCustomConfiguration { - return invocation -> { - argument.set(invocation.getArgument(0)); - return returnValue; - }; - } - - @Configuration - @SuppressWarnings("unused") - static abstract class ClientCacheConfiguration { - - @Bean - ClientCache gemfireCache() { - return mockClientCache(); + @Bean("TestPool") + Pool testPool() { + return mock(Pool.class, "TestPool"); } } - @Configuration + @ClientCacheApplication + @EnableGemFireMockObjects + @EnableEntityDefinedRegions(basePackageClasses = NonEntity.class, serverRegionShortcut = RegionShortcut.LOCAL, + strict = true, excludeFilters = @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, + classes = CollocatedPartitionRegionEntity.class) + ) + static class ClientPersistentEntitiesWithServerRegionMappingAnnotationsConfiguration { + } + + @PeerCacheApplication + @EnableGemFireMockObjects @SuppressWarnings("unused") - static abstract class ServerCacheConfiguration { - - @Bean - Cache gemfireCache() { - return mockCache(); - } - } - - @SuppressWarnings("all") - @EnableEntityDefinedRegions(basePackageClasses = NonEntity.class, strict = true, - excludeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION, - classes = { LocalRegion.class, PartitionRegion.class, ReplicateRegion.class })) - static class ClientPersistentEntitiesConfiguration extends ClientCacheConfiguration { - } - - @SuppressWarnings("all") - @EnableEntityDefinedRegions(basePackageClasses = NonEntity.class, - excludeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION, - classes = { ClientRegion.class, LocalRegion.class, ReplicateRegion.class })) - static class PeerPartitionRegionPersistentEntitiesConfiguration extends ServerCacheConfiguration { + @EnableEntityDefinedRegions(basePackageClasses = NonEntity.class, excludeFilters = { + @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = { + ClientRegion.class, LocalRegion.class, ReplicateRegion.class + }), + @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = GenericRegionEntity.class) + }) + static class PeerPartitionRegionPersistentEntitiesConfiguration { @Bean @Lazy DiskStore mockDiskStore() { - return mock(DiskStore.class, mockName("MockDiskStore")); + return mock(DiskStore.class, MockObjectsSupport.mockObjectIdentifier("MockDiskStore")); } @Bean @Lazy PartitionResolver mockPartitionResolver() { - return mock(PartitionResolver.class, mockName("MockPartitionResolver")); + return mock(PartitionResolver.class, + MockObjectsSupport.mockObjectIdentifier("MockPartitionResolver")); } } - @SuppressWarnings("all") - @EnableEntityDefinedRegions(basePackageClasses = NonEntity.class, - excludeFilters = { @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = ClientRegion.class), - @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = CollocatedPartitionRegionEntity.class) }) - static class ServerPersistentEntitiesConfiguration extends ServerCacheConfiguration { + @PeerCacheApplication + @EnableGemFireMockObjects + @EnableEntityDefinedRegions(basePackageClasses = NonEntity.class, excludeFilters = { + @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = ClientRegion.class), + @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = CollocatedPartitionRegionEntity.class) + }) + static class ServerPersistentEntitiesConfiguration { } - @EnableEntityDefinedRegions(basePackageClasses = NonEntity.class, + @PeerCacheApplication + @EnableGemFireMockObjects + @EnableEntityDefinedRegions(basePackageClasses = NonEntity.class, serverRegionShortcut = RegionShortcut.REPLICATE, excludeFilters = @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = { + CollocatedPartitionRegionEntity.class, ReplicateRegionEntity.class + }) + ) + static class ServerPersistentEntitiesWithCustomConfiguration { + } + + @PeerCacheApplication + @EnableGemFireMockObjects + @EnableEntityDefinedRegions(basePackageClasses = NonEntity.class, clientRegionShortcut = ClientRegionShortcut.LOCAL, + poolName = "TestPool", excludeFilters = @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = { + CollocatedPartitionRegionEntity.class, LocalRegionEntity.class, ReplicateRegionEntity.class + }) + ) + static class ServerPersistentEntitiesWithClientRegionMappingAnnotationsConfiguration { + } + + @PeerCacheApplication + @EnableGemFireMockObjects + @EnableEntityDefinedRegions(basePackageClasses = NonEntity.class, excludeFilters = + @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = { ClientRegionEntity.class, CollocatedPartitionRegionEntity.class, GenericRegionEntity.class, LocalRegionEntity.class, ReplicateRegionEntity.class }) ) - static class ExistingPartitionRegionPersistentEntitiesConfiguration extends ServerCacheConfiguration { + static class ExistingPartitionRegionPersistentEntitiesConfiguration { @Bean @SuppressWarnings("unused") PartitionedRegionFactoryBean customersRegion(GemFireCache gemfireCache) { + PartitionedRegionFactoryBean customers = new PartitionedRegionFactoryBean<>(); customers.setCache(gemfireCache); @@ -605,18 +556,20 @@ public class EnableEntityDefinedRegionsUnitTests { } } - @SuppressWarnings("all") - @EnableEntityDefinedRegions(basePackageClasses = NonEntity.class, - excludeFilters = @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = { + @PeerCacheApplication + @EnableGemFireMockObjects + @EnableEntityDefinedRegions(basePackageClasses = NonEntity.class, excludeFilters = + @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = { ClientRegionEntity.class, CollocatedPartitionRegionEntity.class, GenericRegionEntity.class, LocalRegionEntity.class, PartitionRegionEntity.class }) ) - static class ExistingReplicateRegionPersistentEntitiesConfiguration extends ServerCacheConfiguration { + static class ExistingReplicateRegionPersistentEntitiesConfiguration { @Bean @SuppressWarnings("unused") ReplicatedRegionFactoryBean accountsRegion(GemFireCache gemfireCache) { + ReplicatedRegionFactoryBean accounts = new ReplicatedRegionFactoryBean<>(); accounts.setCache(gemfireCache); diff --git a/src/test/java/org/springframework/data/gemfire/test/mock/MockGemFireObjectsSupport.java b/src/test/java/org/springframework/data/gemfire/test/mock/MockGemFireObjectsSupport.java index 0e75c5e6..8191eff6 100644 --- a/src/test/java/org/springframework/data/gemfire/test/mock/MockGemFireObjectsSupport.java +++ b/src/test/java/org/springframework/data/gemfire/test/mock/MockGemFireObjectsSupport.java @@ -16,6 +16,7 @@ package org.springframework.data.gemfire.test.mock; +import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyFloat; @@ -29,11 +30,14 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; import static org.springframework.data.gemfire.util.ArrayUtils.nullSafeArray; +import static org.springframework.data.gemfire.util.CollectionUtils.nullSafeSet; import static org.springframework.data.gemfire.util.RuntimeExceptionFactory.NOT_SUPPORTED; import static org.springframework.data.gemfire.util.RuntimeExceptionFactory.newIllegalArgumentException; +import static org.springframework.data.gemfire.util.RuntimeExceptionFactory.newIllegalStateException; import static org.springframework.data.gemfire.util.RuntimeExceptionFactory.newUnsupportedOperationException; import java.io.File; +import java.io.IOException; import java.io.InputStream; import java.net.InetSocketAddress; import java.util.ArrayList; @@ -58,6 +62,9 @@ import java.util.stream.Collectors; import org.apache.geode.cache.Cache; import org.apache.geode.cache.CacheFactory; +import org.apache.geode.cache.CacheListener; +import org.apache.geode.cache.CacheLoader; +import org.apache.geode.cache.CacheWriter; import org.apache.geode.cache.CustomExpiry; import org.apache.geode.cache.DataPolicy; import org.apache.geode.cache.DiskStore; @@ -66,9 +73,15 @@ import org.apache.geode.cache.EvictionAttributes; import org.apache.geode.cache.ExpirationAction; import org.apache.geode.cache.ExpirationAttributes; import org.apache.geode.cache.GemFireCache; +import org.apache.geode.cache.PartitionAttributes; import org.apache.geode.cache.Region; import org.apache.geode.cache.RegionAttributes; +import org.apache.geode.cache.RegionExistsException; +import org.apache.geode.cache.RegionFactory; import org.apache.geode.cache.RegionService; +import org.apache.geode.cache.RegionShortcut; +import org.apache.geode.cache.Scope; +import org.apache.geode.cache.SubscriptionAttributes; import org.apache.geode.cache.client.ClientCache; import org.apache.geode.cache.client.ClientCacheFactory; import org.apache.geode.cache.client.ClientRegionFactory; @@ -85,6 +98,7 @@ import org.apache.geode.cache.query.QueryStatistics; import org.apache.geode.cache.server.CacheServer; import org.apache.geode.cache.server.ClientSubscriptionConfig; import org.apache.geode.compression.Compressor; +import org.apache.geode.distributed.DistributedMember; import org.apache.geode.distributed.DistributedSystem; import org.apache.geode.internal.concurrent.ConcurrentHashSet; import org.apache.geode.pdx.PdxSerializer; @@ -132,6 +146,9 @@ public abstract class MockGemFireObjectsSupport extends MockObjectsSupport { private static final String REPEATING_REGION_SEPARATOR = Region.SEPARATOR + "{2,}"; + /** + * Destroys all mock object state. + */ public static void destroy() { singletonCache.set(null); diskStores.clear(); @@ -139,27 +156,241 @@ public abstract class MockGemFireObjectsSupport extends MockObjectsSupport { regionAttributes.clear(); } - /* (non-Javadoc) */ + /** + * Converts the given {@link ClientRegionShortcut} into a corresponding {@link DataPolicy}. + * + * @param clientRegionShortcut {@link ClientRegionShortcut} to convert. + * @return a {@link DataPolicy} from the {@link ClientRegionShortcut}. + * @see org.apache.geode.cache.client.ClientRegionShortcut + * @see org.apache.geode.cache.DataPolicy + */ + @SuppressWarnings("unchecked") + private static DataPolicy convert(ClientRegionShortcut clientRegionShortcut) { + + return Optional.ofNullable(clientRegionShortcut).map(shortcut -> { + + switch(shortcut) { + case CACHING_PROXY: + case CACHING_PROXY_HEAP_LRU: + case CACHING_PROXY_OVERFLOW: + case LOCAL: + case LOCAL_HEAP_LRU: + case LOCAL_OVERFLOW: + return DataPolicy.NORMAL; + case LOCAL_PERSISTENT: + case LOCAL_PERSISTENT_OVERFLOW: + return DataPolicy.PERSISTENT_REPLICATE; + case PROXY: + return DataPolicy.EMPTY; + default: + return null; + } + + }).orElse(DataPolicy.DEFAULT); + } + + /** + * Converts the given {@link RegionShortcut} into a corresponding {@link DataPolicy}. + * + * @param regionShortcut {@link RegionShortcut} to convert. + * @return a {@link DataPolicy} from the {@link RegionShortcut}. + * @see org.apache.geode.cache.RegionShortcut + * @see org.apache.geode.cache.DataPolicy + */ + @SuppressWarnings("unchecked") + private static DataPolicy convert(RegionShortcut regionShortcut) { + + return Optional.ofNullable(regionShortcut).map(shortcut -> { + + switch (shortcut) { + case LOCAL: + case LOCAL_HEAP_LRU: + case LOCAL_OVERFLOW: + return DataPolicy.NORMAL; + case PARTITION: + case PARTITION_HEAP_LRU: + case PARTITION_OVERFLOW: + case PARTITION_PROXY: + case PARTITION_PROXY_REDUNDANT: + case PARTITION_REDUNDANT: + case PARTITION_REDUNDANT_HEAP_LRU: + case PARTITION_REDUNDANT_OVERFLOW: + return DataPolicy.PARTITION; + case PARTITION_PERSISTENT: + case PARTITION_PERSISTENT_OVERFLOW: + case PARTITION_REDUNDANT_PERSISTENT: + case PARTITION_REDUNDANT_PERSISTENT_OVERFLOW: + return DataPolicy.PERSISTENT_PARTITION; + case REPLICATE: + case REPLICATE_HEAP_LRU: + case REPLICATE_OVERFLOW: + return DataPolicy.REPLICATE; + case LOCAL_PERSISTENT: + case LOCAL_PERSISTENT_OVERFLOW: + case REPLICATE_PERSISTENT: + case REPLICATE_PERSISTENT_OVERFLOW: + return DataPolicy.PERSISTENT_REPLICATE; + case REPLICATE_PROXY: + return DataPolicy.EMPTY; + default: + return null; + } + + }).orElse(DataPolicy.DEFAULT); + } + + /** + * Executes the given {@link IoExceptionThrowingOperation}, handling any {@link IOException IOExceptions} thrown + * during normal IO processing. + * + * @param operation {@link IoExceptionThrowingOperation} to execute. + * @return a boolean indicating whether the IO operation was successful, or {@literal false} if the IO operation + * threw an {@link IOException}. + * @see org.springframework.data.gemfire.test.mock.MockGemFireObjectsSupport.IoExceptionThrowingOperation + * @see java.io.IOException + */ + private static boolean doSafeIo(IoExceptionThrowingOperation operation) { + + try { + operation.doIo(); + return true; + } + catch (IOException cause) { + return false; + } + } + + /** + * Determines whether the given {@link Region} is a root {@link Region}. + * + * @param region {@link Region} to evaluate. + * @return a boolean value indicating whether the {@link Region} is a root {@link Region}. + * @see org.apache.geode.cache.Region + * @see #isRootRegion(String) + */ private static boolean isRootRegion(Region region) { return isRootRegion(region.getFullPath()); } - /* (non-Javadoc) */ + /** + * Determines whether the {@link Region} identified by the given {@link String path} is a root {@link Region}. + * + * @param regionPath {@link String path} identifying the {@link Region} to evaluate. + * @return a boolean value indicating whether the {@link Region} identified by the given {@link String path} + * is a root {@link Region}. + */ private static boolean isRootRegion(String regionPath) { return (regionPath.lastIndexOf(Region.SEPARATOR) <= 0); } - /* (non-Javadoc) */ + /** + * Normalizes the given {@link Region#getFullPath() Regon path} by removing all duplicate, repeating + * {@link Region#SEPARATOR} characters between path segments as well as removing the trailing + * {@link Region#SEPARATOR}. + * + * @param regionPath {@link Region#getFullPath()} to normalize. + * @return a normalized version of the given {@link Region#getFullPath()}. + */ private static String normalizeRegionPath(String regionPath) { regionPath = regionPath.replaceAll(REPEATING_REGION_SEPARATOR, Region.SEPARATOR); + regionPath = regionPath.endsWith(Region.SEPARATOR) ? regionPath.substring(0, regionPath.length() - 1) : regionPath; return regionPath; } - /* (non-Javadoc) */ + /** + * Remembers the given mock {@link GemFireCache} object, which may be a {@link ClientCache} or a peer {@link Cache}. + * + * @param {@link Class sub-type} of the {@link GemFireCache} instance. + * @param mockedGemFireCache {@link GemFireCache} to remember. + * @param useSingletonCache boolean value indicating whether the {@link GemFireCache} is a Singleton. + * @return the given {@link GemFireCache}. + * @throws IllegalArgumentException if {@link GemFireCache} is {@literal null}. + * @see org.apache.geode.cache.GemFireCache + */ + private static T rememberMockedGemFireCache(T mockedGemFireCache, + boolean useSingletonCache) { + + return Optional.ofNullable(mockedGemFireCache) + .map(it -> { + + if (useSingletonCache) { + singletonCache.compareAndSet(null, it); + } + + return it; + }) + .orElseThrow(() -> newIllegalArgumentException("GemFireCache is required")); + } + + /** + * Remembers the given mock {@link Region}. + * + * @param {@link Class type} of the {@link Region} key. + * @param {@link Class type} of the {@link Region} value. + * @param mockRegion {@link Region} to remember. + * @throws IllegalArgumentException if the given {@link Region} is {@literal null}. + * @throws RegionExistsException if the given {@link Region} already exists. + * @return the given {@link Region}. + * @see org.apache.geode.cache.Region + */ + @SuppressWarnings("unchecked") + private static Region rememberMockedRegion(Region mockRegion) { + + String mockRegionPath = Optional.ofNullable(mockRegion).map(Region::getFullPath) + .orElseThrow(() -> newIllegalArgumentException("Region is required")); + + if (regions.putIfAbsent(mockRegionPath, (Region) mockRegion) != null) { + throw new RegionExistsException(mockRegion); + } + + assertThat(regions).containsValue((Region) mockRegion); + + return mockRegion; + } + + /** + * Resolves the single, remembered {@link GemFireCache} if using GemFire in Singleton-mode. + * + * @param {@link Class sub-type} of the {@link GemFireCache} instance. + * @param useSingletonCache boolean value indicating if mock infrastructure is using GemFire Singletons. + * @return an {@link Optional}, single remembered instance of the {@link GemFireCache}. + * @see org.apache.geode.cache.GemFireCache + */ + @SuppressWarnings("unchecked") + private static Optional resolveMockedGemFireCache(boolean useSingletonCache) { + return Optional.ofNullable((T) singletonCache.get()).filter(it -> useSingletonCache); + } + + /** + * Resolves the {@link RegionAttributes} identified by the given {@link String id}. + * + * @param {@link Class type} of the {@link Region} key. + * @param {@link Class type} of the {@link Region} value. + * @param regionAttributesId {@link String id} identifying the {@link RegionAttributes} to resolve. + * @return the resolved {@link RegionAttributes} identified by the given {@link String id}. + * @throws IllegalStateException if {@link RegionAttributes} could not be resolved from the given {@link String id}. + * @see org.apache.geode.cache.RegionAttributes + */ + @SuppressWarnings("unchecked") + private static RegionAttributes resolveRegionAttributes(String regionAttributesId) { + + return (RegionAttributes) Optional.ofNullable(regionAttributes.get(regionAttributesId)).orElseThrow(() -> + newIllegalStateException("RegionAttributes with ID [%s] cannot be found", regionAttributesId)); + } + + /** + * Converts the given {@link String Region name} into a proper {@link Region#getName() Region name}. + * + * @param regionName {@link String Region name} to evaluate. + * @return a proper {@link Region#getName() Region name} from the given {@link String Region name}. + * @throws IllegalArgumentException if {@link String Region name} is {@literal null} + * or {@link String#isEmpty() empty}. + * @see java.lang.String + */ private static String toRegionName(String regionName) { return Optional.ofNullable(regionName) @@ -172,7 +403,15 @@ public abstract class MockGemFireObjectsSupport extends MockObjectsSupport { .orElseThrow(() -> newIllegalArgumentException("Region name [%s] is required", regionName)); } - /* (non-Javadoc) */ + /** + * Converts the given {@link String Region path} into a proper {@link Region#getFullPath() Region path}. + * + * @param regionPath {@link String Region path} to evaluate. + * @return a proper {@link Region#getFullPath() Region path} from the given {@link String Region path}. + * @throws IllegalArgumentException if {@link String Region path} is {@literal null} + * or {@link String#isEmpty() empty}. + * @see java.lang.String + */ private static String toRegionPath(String regionPath) { return Optional.ofNullable(regionPath) @@ -235,11 +474,13 @@ public abstract class MockGemFireObjectsSupport extends MockObjectsSupport { String regionPath = invocation.getArgument(0); - Optional.ofNullable(regionPath).map(String::trim).filter(it -> !it.isEmpty()) + String resolvedRegionPath = Optional.ofNullable(regionPath) + .map(String::trim) + .filter(it -> !it.isEmpty()) .map(MockGemFireObjectsSupport::toRegionPath) .orElseThrow(() -> newIllegalArgumentException("Region path [%s] is not valid", regionPath)); - return regions.get(regionPath); + return regions.get(resolvedRegionPath); }); when(mockRegionService.createPdxEnum(anyString(), anyString(), anyInt())) @@ -260,8 +501,11 @@ public abstract class MockGemFireObjectsSupport extends MockObjectsSupport { doAnswer(newVoidAnswer(invocation -> mockClientCache.close())).when(mockClientCache).close(anyBoolean()); - when(mockClientCache.createClientRegionFactory(any(ClientRegionShortcut.class))) - .thenAnswer(invocation -> mockClientRegionFactory(mockClientCache)); + when(mockClientCache.createClientRegionFactory(any(ClientRegionShortcut.class))).thenAnswer(invocation -> + mockClientRegionFactory(mockClientCache, invocation.getArgument(0))); + + when(mockClientCache.createClientRegionFactory(anyString())).thenAnswer(invocation -> + mockClientRegionFactory(mockClientCache, invocation.getArgument(0))); return mockQueryService(mockCacheApi(mockClientCache)); } @@ -273,6 +517,7 @@ public abstract class MockGemFireObjectsSupport extends MockObjectsSupport { return mockQueryService(mockCacheApi(mockGemFireCache)); } + @SuppressWarnings("unchecked") public static Cache mockPeerCache() { Cache mockCache = mock(Cache.class); @@ -306,6 +551,17 @@ public abstract class MockGemFireObjectsSupport extends MockObjectsSupport { when(mockCache.getReconnectedCache()).thenAnswer(invocation -> mockPeerCache()); when(mockCache.getSearchTimeout()).thenAnswer(newGetter(searchTimeout)); + when(mockCache.createRegionFactory()).thenAnswer(invocation -> mockRegionFactory(mockCache)); + + when(mockCache.createRegionFactory(any(RegionAttributes.class))).thenAnswer(invocation -> + mockRegionFactory(mockCache, invocation.>getArgument(0))); + + when(mockCache.createRegionFactory(any(RegionShortcut.class))).thenAnswer(invocation -> + mockRegionFactory(mockCache, invocation.getArgument(0))); + + when(mockCache.createRegionFactory(anyString())).thenAnswer(invocation -> + mockRegionFactory(mockCache, invocation.getArgument(0))); + return mockQueryService(mockCacheApi(mockCache)); } @@ -313,6 +569,7 @@ public abstract class MockGemFireObjectsSupport extends MockObjectsSupport { CacheServer mockCacheServer = mock(CacheServer.class); + AtomicBoolean running = new AtomicBoolean(false); AtomicBoolean tcpNoDelay = new AtomicBoolean(CacheServer.DEFAULT_TCP_NO_DELAY); AtomicInteger maxConnections = new AtomicInteger(CacheServer.DEFAULT_MAX_CONNECTIONS); @@ -361,27 +618,51 @@ public abstract class MockGemFireObjectsSupport extends MockObjectsSupport { doAnswer(newSetter(tcpNoDelay, null)) .when(mockCacheServer).setTcpNoDelay(anyBoolean()); + when(mockCacheServer.isRunning()).thenAnswer(newGetter(running)); + when(mockCacheServer.getAllClientSessions()).thenReturn(Collections.emptySet()); when(mockCacheServer.getBindAddress()).thenAnswer(newGetter(bindAddress)); + when(mockCacheServer.getClientSession(any(DistributedMember.class))) + .thenThrow(newUnsupportedOperationException(NOT_SUPPORTED)); + when(mockCacheServer.getClientSession(anyString())).thenThrow(newUnsupportedOperationException(NOT_SUPPORTED)); when(mockCacheServer.getHostnameForClients()).thenAnswer(newGetter(hostnameForClients)); + when(mockCacheServer.getInterestRegistrationListeners()).thenReturn(Collections.emptySet()); when(mockCacheServer.getLoadPollInterval()).thenAnswer(newGetter(loadPollInterval)); + when(mockCacheServer.getLoadProbe()).thenThrow(newUnsupportedOperationException(NOT_SUPPORTED)); when(mockCacheServer.getMaxConnections()).thenAnswer(newGetter(maxConnections)); when(mockCacheServer.getMaximumMessageCount()).thenAnswer(newGetter(maxMessageCount)); - when(mockCacheServer.getMaxThreads()).thenAnswer(newGetter(maxThreads)); when(mockCacheServer.getMaximumTimeBetweenPings()).thenAnswer(newGetter(maxTimeBetweenPings)); + when(mockCacheServer.getMaxThreads()).thenAnswer(newGetter(maxThreads)); when(mockCacheServer.getMessageTimeToLive()).thenAnswer(newGetter(messageTimeToLive)); when(mockCacheServer.getPort()).thenAnswer(newGetter(port)); when(mockCacheServer.getSocketBufferSize()).thenAnswer(newGetter(socketBufferSize)); when(mockCacheServer.getTcpNoDelay()).thenAnswer(newGetter(tcpNoDelay)); - ClientSubscriptionConfig mockClientSubsriptionConfig = mockClientSubscriptionConfig(); + ClientSubscriptionConfig mockClientSubscriptionConfig = mockClientSubscriptionConfig(); - when(mockCacheServer.getClientSubscriptionConfig()).thenReturn(mockClientSubsriptionConfig); + when(mockCacheServer.getClientSubscriptionConfig()).thenReturn(mockClientSubscriptionConfig); + + doSafeIo(() -> doAnswer(newSetter(running, true, null)).when(mockCacheServer).start()); + doAnswer(newSetter(running, false, null)).when(mockCacheServer).stop(); return mockCacheServer; } + public static ClientRegionFactory mockClientRegionFactory(ClientCache mockClientCache, + ClientRegionShortcut clientRegionShortcut) { + + return mockClientRegionFactory(mockClientCache, clientRegionShortcut, null); + } + + public static ClientRegionFactory mockClientRegionFactory(ClientCache mockClientCache, + String regionAttributesId) { + + return mockClientRegionFactory(mockClientCache, null, + resolveRegionAttributes(regionAttributesId)); + } + @SuppressWarnings("unchecked") - public static ClientRegionFactory mockClientRegionFactory(ClientCache mockClientCache) { + public static ClientRegionFactory mockClientRegionFactory(ClientCache mockClientCache, + ClientRegionShortcut clientRegionShortcut, RegionAttributes regionAttributes) { ClientRegionFactory mockClientRegionFactory = mock(ClientRegionFactory.class, mockObjectIdentifier("MockClientRegionFactory")); @@ -389,28 +670,79 @@ public abstract class MockGemFireObjectsSupport extends MockObjectsSupport { ExpirationAttributes DEFAULT_EXPIRATION_ATTRIBUTES = new ExpirationAttributes(0, ExpirationAction.INVALIDATE); - AtomicBoolean cloningEnabled = new AtomicBoolean(false); - AtomicBoolean concurrencyChecksEnabled = new AtomicBoolean(false); - AtomicBoolean diskSynchronous = new AtomicBoolean(true); - AtomicBoolean statisticsEnabled = new AtomicBoolean(false); + Optional> optionalRegionAttributes = Optional.ofNullable(regionAttributes); - AtomicInteger concurrencyLevel = new AtomicInteger(16); - AtomicInteger initialCapacity = new AtomicInteger(16); + AtomicBoolean cloningEnabled = new AtomicBoolean(optionalRegionAttributes + .map(RegionAttributes::getCloningEnabled).orElse(false)); - AtomicReference compressor = new AtomicReference<>(null); - AtomicReference> customEntryIdleTimeout = new AtomicReference<>(null); - AtomicReference> customEntryTimeToLive = new AtomicReference<>(null); - AtomicReference diskStoreName = new AtomicReference<>(null); - AtomicReference entryIdleTimeout = new AtomicReference<>(DEFAULT_EXPIRATION_ATTRIBUTES); - AtomicReference entryTimeToLive = new AtomicReference<>(DEFAULT_EXPIRATION_ATTRIBUTES); - AtomicReference evictionAttributes = - new AtomicReference<>(EvictionAttributes.createLRUEntryAttributes()); - AtomicReference> keyConstraint = new AtomicReference<>(); - AtomicReference loadFactor = new AtomicReference<>(0.75f); - AtomicReference poolName = new AtomicReference<>(null); - AtomicReference regionIdleTimeout = new AtomicReference<>(DEFAULT_EXPIRATION_ATTRIBUTES); - AtomicReference regionTimeToLive = new AtomicReference<>(DEFAULT_EXPIRATION_ATTRIBUTES); - AtomicReference> valueConstraint = new AtomicReference<>(); + AtomicBoolean concurrencyChecksEnabled = new AtomicBoolean(optionalRegionAttributes + .map(RegionAttributes::getConcurrencyChecksEnabled).orElse(false)); + + AtomicBoolean diskSynchronous = new AtomicBoolean(optionalRegionAttributes + .map(RegionAttributes::isDiskSynchronous).orElse(true)); + + AtomicBoolean statisticsEnabled = new AtomicBoolean(optionalRegionAttributes + .map(RegionAttributes::getStatisticsEnabled).orElse(false)); + + AtomicInteger concurrencyLevel = new AtomicInteger(optionalRegionAttributes + .map(RegionAttributes::getConcurrencyLevel).orElse(16)); + + AtomicInteger initialCapacity = new AtomicInteger(optionalRegionAttributes + .map(RegionAttributes::getInitialCapacity).orElse(16)); + + AtomicReference compressor = new AtomicReference<>(optionalRegionAttributes + .map(RegionAttributes::getCompressor).orElse(null)); + + AtomicReference> customEntryIdleTimeout = new AtomicReference<>(optionalRegionAttributes + .map(RegionAttributes::getCustomEntryIdleTimeout).orElse(null)); + + AtomicReference> customEntryTimeToLive = new AtomicReference<>(optionalRegionAttributes + .map(RegionAttributes::getCustomEntryTimeToLive).orElse(null)); + + AtomicReference dataPolicy = new AtomicReference<>(optionalRegionAttributes + .map(RegionAttributes::getDataPolicy).orElseGet(() -> convert(clientRegionShortcut))); + + AtomicReference diskStoreName = new AtomicReference<>(optionalRegionAttributes + .map(RegionAttributes::getDiskStoreName).orElse(null)); + + AtomicReference entryIdleTimeout = new AtomicReference<>(optionalRegionAttributes + .map(RegionAttributes::getEntryIdleTimeout).orElse(DEFAULT_EXPIRATION_ATTRIBUTES)); + + AtomicReference entryTimeToLive = new AtomicReference<>(optionalRegionAttributes + .map(RegionAttributes::getEntryTimeToLive).orElse(DEFAULT_EXPIRATION_ATTRIBUTES)); + + AtomicReference evictionAttributes = new AtomicReference<>(optionalRegionAttributes + .map(RegionAttributes::getEvictionAttributes).orElseGet(() -> EvictionAttributes.createLRUEntryAttributes())); + + AtomicReference> keyConstraint = new AtomicReference<>(optionalRegionAttributes + .map(RegionAttributes::getKeyConstraint).orElse(null)); + + AtomicReference loadFactor = new AtomicReference<>(optionalRegionAttributes + .map(RegionAttributes::getLoadFactor).orElse(0.75f)); + + AtomicReference poolName = new AtomicReference<>(optionalRegionAttributes + .map(RegionAttributes::getPoolName).orElse(null)); + + AtomicReference regionIdleTimeout = new AtomicReference<>(optionalRegionAttributes + .map(RegionAttributes::getRegionIdleTimeout).orElse(DEFAULT_EXPIRATION_ATTRIBUTES)); + + AtomicReference regionTimeToLive = new AtomicReference<>(optionalRegionAttributes + .map(RegionAttributes::getRegionTimeToLive).orElse(DEFAULT_EXPIRATION_ATTRIBUTES)); + + AtomicReference> valueConstraint = new AtomicReference<>(optionalRegionAttributes + .map(RegionAttributes::getValueConstraint).orElse(null)); + + List cacheListeners = new ArrayList<>(Arrays.asList(nullSafeArray(optionalRegionAttributes + .map(RegionAttributes::getCacheListeners).orElse(null), CacheListener.class))); + + when(mockClientRegionFactory.addCacheListener(any(CacheListener.class))) + .thenAnswer(newAdder(cacheListeners, mockClientRegionFactory)); + + when(mockClientRegionFactory.initCacheListeners(any(CacheListener[].class))).thenAnswer(invocation -> { + cacheListeners.clear(); + Collections.addAll(cacheListeners, invocation.getArgument(0)); + return mockClientRegionFactory; + }); when(mockClientRegionFactory.setCloningEnabled(anyBoolean())) .thenAnswer(newSetter(cloningEnabled, mockClientRegionFactory)); @@ -472,13 +804,16 @@ public abstract class MockGemFireObjectsSupport extends MockObjectsSupport { RegionAttributes mockRegionAttributes = mock(RegionAttributes.class, mockObjectIdentifier("MockRegionAttributes")); + when(mockRegionAttributes.getCacheListeners()) + .thenAnswer(newGetter(() -> cacheListeners.toArray(new CacheListener[cacheListeners.size()]))); + when(mockRegionAttributes.getCloningEnabled()).thenAnswer(newGetter(cloningEnabled)); when(mockRegionAttributes.getCompressor()).thenAnswer(newGetter(compressor)); when(mockRegionAttributes.getConcurrencyChecksEnabled()).thenAnswer(newGetter(concurrencyChecksEnabled)); when(mockRegionAttributes.getConcurrencyLevel()).thenAnswer(newGetter(concurrencyLevel)); when(mockRegionAttributes.getCustomEntryIdleTimeout()).thenAnswer(newGetter(customEntryIdleTimeout)); when(mockRegionAttributes.getCustomEntryTimeToLive()).thenAnswer(newGetter(customEntryTimeToLive)); - when(mockRegionAttributes.getDataPolicy()).thenReturn(DataPolicy.NORMAL); + when(mockRegionAttributes.getDataPolicy()).thenAnswer(newGetter(dataPolicy)); when(mockRegionAttributes.getDiskStoreName()).thenAnswer(newGetter(diskStoreName)); when(mockRegionAttributes.isDiskSynchronous()).thenAnswer(newGetter(diskSynchronous)); when(mockRegionAttributes.getEntryIdleTimeout()).thenAnswer(newGetter(entryIdleTimeout)); @@ -871,7 +1206,9 @@ public abstract class MockGemFireObjectsSupport extends MockObjectsSupport { } private static CqQuery add(Collection cqQueries, CqQuery cqQuery) { + cqQueries.add(cqQuery); + return cqQuery; } @@ -1000,14 +1337,14 @@ public abstract class MockGemFireObjectsSupport extends MockObjectsSupport { boolean recursive = invocation.getArgument(0); - return recursive ? subRegions.stream() - .flatMap(subRegion -> subRegion.subregions(true).stream()).collect(Collectors.toSet()) + return recursive + ? subRegions.stream() + .flatMap(subRegion -> subRegion.subregions(true).stream()) + .collect(Collectors.toSet()) : subRegions; }); - regions.put(mockRegion.getFullPath(), (Region) mockRegion); - - return mockRegion; + return rememberMockedRegion(mockRegion); } public static Region mockSubRegion(Region parent, String name, @@ -1022,6 +1359,295 @@ public abstract class MockGemFireObjectsSupport extends MockObjectsSupport { return mockSubRegion; } + public static RegionFactory mockRegionFactory(Cache mockCache) { + return mockRegionFactory(mockCache, null, null); + } + + public static RegionFactory mockRegionFactory(Cache mockCache, + RegionAttributes regionAttributes) { + + return mockRegionFactory(mockCache, null, regionAttributes); + } + + public static RegionFactory mockRegionFactory(Cache mockCache, RegionShortcut regionShortcut) { + return mockRegionFactory(mockCache, regionShortcut, null); + } + + public static RegionFactory mockRegionFactory(Cache mockCache, String regionAttributesId) { + return mockRegionFactory(mockCache, null, resolveRegionAttributes(regionAttributesId)); + } + + @SuppressWarnings("unchecked") + public static RegionFactory mockRegionFactory(Cache mockCache, RegionShortcut regionShortcut, + RegionAttributes regionAttributes) { + + RegionFactory mockRegionFactory = mock(RegionFactory.class, + mockObjectIdentifier("MockRegionFactory")); + + Optional> optionalRegionAttributes = Optional.ofNullable(regionAttributes); + + ExpirationAttributes DEFAULT_EXPIRATION_ATTRIBUTES = + new ExpirationAttributes(0, ExpirationAction.INVALIDATE); + + AtomicBoolean cloningEnabled = new AtomicBoolean(optionalRegionAttributes + .map(RegionAttributes::getCloningEnabled).orElse(false)); + + AtomicBoolean concurrencyChecksEnabled = new AtomicBoolean(optionalRegionAttributes + .map(RegionAttributes::getConcurrencyChecksEnabled).orElse(true)); + + AtomicBoolean diskSynchronous = new AtomicBoolean(optionalRegionAttributes + .map(RegionAttributes::isDiskSynchronous).orElse(true)); + + AtomicBoolean enableAsyncConflation = new AtomicBoolean(optionalRegionAttributes + .map(RegionAttributes::getEnableAsyncConflation).orElse(false)); + + AtomicBoolean enableSubscriptionConflation = new AtomicBoolean(optionalRegionAttributes + .map(RegionAttributes::getEnableSubscriptionConflation).orElse(false)); + + AtomicBoolean ignoreJta = new AtomicBoolean(optionalRegionAttributes + .map(RegionAttributes::getIgnoreJTA).orElse(false)); + + AtomicBoolean indexMaintenanceSynchronous = new AtomicBoolean(optionalRegionAttributes + .map(RegionAttributes::getIndexMaintenanceSynchronous).orElse(true)); + + AtomicBoolean lockGrantor = new AtomicBoolean(optionalRegionAttributes + .map(RegionAttributes::isLockGrantor).orElse(false)); + + AtomicBoolean multicastEnabled = new AtomicBoolean(optionalRegionAttributes + .map(RegionAttributes::getMulticastEnabled).orElse(false)); + + AtomicBoolean offHeap = new AtomicBoolean(optionalRegionAttributes + .map(RegionAttributes::getOffHeap).orElse(false)); + + AtomicBoolean statisticsEnabled = new AtomicBoolean(optionalRegionAttributes + .map(RegionAttributes::getStatisticsEnabled).orElse(false)); + + AtomicInteger concurrencyLevel = new AtomicInteger(optionalRegionAttributes + .map(RegionAttributes::getConcurrencyLevel).orElse(16)); + + AtomicInteger initialCapacity = new AtomicInteger(optionalRegionAttributes + .map(RegionAttributes::getInitialCapacity).orElse(16)); + + AtomicReference cacheLoader = new AtomicReference<>(optionalRegionAttributes + .map(RegionAttributes::getCacheLoader).orElse(null)); + + AtomicReference cacheWriter = new AtomicReference<>(optionalRegionAttributes + .map(RegionAttributes::getCacheWriter).orElse(null)); + + AtomicReference compressor = new AtomicReference<>(optionalRegionAttributes + .map(RegionAttributes::getCompressor).orElse(null)); + + AtomicReference> customEntryIdleTimeout = new AtomicReference<>(optionalRegionAttributes + .map(RegionAttributes::getCustomEntryIdleTimeout).orElse(null)); + + AtomicReference> customEntryTimeToLive = new AtomicReference<>(optionalRegionAttributes + .map(RegionAttributes::getCustomEntryTimeToLive).orElse(null)); + + AtomicReference dataPolicy = new AtomicReference<>(optionalRegionAttributes + .map(RegionAttributes::getDataPolicy).orElseGet(() -> convert(regionShortcut))); + + AtomicReference diskStoreName = new AtomicReference<>(optionalRegionAttributes + .map(RegionAttributes::getDiskStoreName).orElse(null)); + + AtomicReference entryIdleTimeout = new AtomicReference<>(optionalRegionAttributes + .map(RegionAttributes::getEntryIdleTimeout).orElse(DEFAULT_EXPIRATION_ATTRIBUTES)); + + AtomicReference entryTimeToLive = new AtomicReference<>(optionalRegionAttributes + .map(RegionAttributes::getEntryTimeToLive).orElse(DEFAULT_EXPIRATION_ATTRIBUTES)); + + AtomicReference evictionAttributes = new AtomicReference<>(optionalRegionAttributes + .map(RegionAttributes::getEvictionAttributes).orElseGet(() -> EvictionAttributes.createLRUEntryAttributes())); + + AtomicReference> keyConstraint = new AtomicReference<>(optionalRegionAttributes + .map(RegionAttributes::getKeyConstraint).orElse(null)); + + AtomicReference loadFactor = new AtomicReference<>(optionalRegionAttributes + .map(RegionAttributes::getLoadFactor).orElse(0.75f)); + + AtomicReference> partitionAttributes = new AtomicReference<>(optionalRegionAttributes + .map(RegionAttributes::getPartitionAttributes).orElse(null)); + + AtomicReference poolName = new AtomicReference<>(optionalRegionAttributes + .map(RegionAttributes::getPoolName).orElse(null)); + + AtomicReference regionIdleTimeout = new AtomicReference<>(optionalRegionAttributes + .map(RegionAttributes::getRegionIdleTimeout).orElse(DEFAULT_EXPIRATION_ATTRIBUTES)); + + AtomicReference regionTimeToLive = new AtomicReference<>(optionalRegionAttributes + .map(RegionAttributes::getRegionTimeToLive).orElse(DEFAULT_EXPIRATION_ATTRIBUTES)); + + AtomicReference scope = new AtomicReference<>(optionalRegionAttributes + .map(RegionAttributes::getScope).orElse(Scope.DISTRIBUTED_NO_ACK)); + + AtomicReference subscriptionAttributes = new AtomicReference<>(optionalRegionAttributes + .map(RegionAttributes::getSubscriptionAttributes).orElseGet(() -> new SubscriptionAttributes())); + + AtomicReference> valueConstraint = new AtomicReference<>(optionalRegionAttributes + .map(RegionAttributes::getValueConstraint).orElse(null)); + + List cacheListeners = new ArrayList<>(Arrays.asList(nullSafeArray(optionalRegionAttributes + .map(RegionAttributes::getCacheListeners).orElse(null), CacheListener.class))); + + Set asyncEventQueueIds = new HashSet<>(nullSafeSet(optionalRegionAttributes + .map(RegionAttributes::getAsyncEventQueueIds).orElse(null))); + + Set gatewaySenderIds = new HashSet<>(nullSafeSet(optionalRegionAttributes + .map(RegionAttributes::getGatewaySenderIds).orElse(null))); + + when(mockRegionFactory.addAsyncEventQueueId(anyString())) + .thenAnswer(newAdder(asyncEventQueueIds, mockRegionFactory)); + + when(mockRegionFactory.addCacheListener(any(CacheListener.class))) + .thenAnswer(newAdder(cacheListeners, mockRegionFactory)); + + when(mockRegionFactory.addGatewaySenderId(anyString())) + .thenAnswer(newAdder(gatewaySenderIds, mockRegionFactory)); + + when(mockRegionFactory.initCacheListeners(any(CacheListener[].class))).thenAnswer(invocation -> { + cacheListeners.clear(); + Collections.addAll(cacheListeners, invocation.getArgument(0)); + return mockRegionFactory; + }); + + when(mockRegionFactory.setCacheLoader(any(CacheLoader.class))) + .thenAnswer(newSetter(cacheLoader, mockRegionFactory)); + + when(mockRegionFactory.setCacheWriter(any(CacheWriter.class))) + .thenAnswer(newSetter(cacheWriter, mockRegionFactory)); + + when(mockRegionFactory.setCloningEnabled(anyBoolean())) + .thenAnswer(newSetter(cloningEnabled, mockRegionFactory)); + + when(mockRegionFactory.setCompressor(any(Compressor.class))) + .thenAnswer(newSetter(compressor, mockRegionFactory)); + + when(mockRegionFactory.setConcurrencyChecksEnabled(anyBoolean())) + .then(newSetter(concurrencyChecksEnabled, mockRegionFactory)); + + when(mockRegionFactory.setConcurrencyLevel(anyInt())) + .thenAnswer(newSetter(concurrencyLevel, mockRegionFactory)); + + when(mockRegionFactory.setCustomEntryIdleTimeout(any(CustomExpiry.class))) + .thenAnswer(newSetter(customEntryIdleTimeout, mockRegionFactory)); + + when(mockRegionFactory.setCustomEntryTimeToLive(any(CustomExpiry.class))) + .thenAnswer(newSetter(customEntryTimeToLive, mockRegionFactory)); + + when(mockRegionFactory.setDataPolicy(any(DataPolicy.class))) + .thenAnswer(newSetter(dataPolicy, mockRegionFactory)); + + when(mockRegionFactory.setDiskStoreName(anyString())).thenAnswer(newSetter(diskStoreName, mockRegionFactory)); + + when(mockRegionFactory.setDiskSynchronous(anyBoolean())) + .thenAnswer(newSetter(diskSynchronous, mockRegionFactory)); + + when(mockRegionFactory.setEnableAsyncConflation(anyBoolean())) + .thenAnswer(newSetter(enableAsyncConflation, mockRegionFactory)); + + when(mockRegionFactory.setEnableSubscriptionConflation(anyBoolean())) + .thenAnswer(newSetter(enableSubscriptionConflation, mockRegionFactory)); + + when(mockRegionFactory.setEntryIdleTimeout(any(ExpirationAttributes.class))) + .thenAnswer(newSetter(entryIdleTimeout, mockRegionFactory)); + + when(mockRegionFactory.setEntryTimeToLive(any(ExpirationAttributes.class))) + .thenAnswer(newSetter(entryTimeToLive, mockRegionFactory)); + + when(mockRegionFactory.setEvictionAttributes(any(EvictionAttributes.class))) + .thenAnswer(newSetter(evictionAttributes, mockRegionFactory)); + + when(mockRegionFactory.setIgnoreJTA(anyBoolean())).thenAnswer(newSetter(ignoreJta, mockRegionFactory)); + + when(mockRegionFactory.setIndexMaintenanceSynchronous(anyBoolean())) + .thenAnswer(newSetter(indexMaintenanceSynchronous, mockRegionFactory)); + + when(mockRegionFactory.setInitialCapacity(anyInt())).thenAnswer(newSetter(initialCapacity, mockRegionFactory)); + + when(mockRegionFactory.setKeyConstraint(any(Class.class))) + .thenAnswer(newSetter(keyConstraint, mockRegionFactory)); + + when(mockRegionFactory.setLoadFactor(anyFloat())).thenAnswer(newSetter(loadFactor, mockRegionFactory)); + + when(mockRegionFactory.setLockGrantor(anyBoolean())).thenAnswer(newSetter(lockGrantor, mockRegionFactory)); + + when(mockRegionFactory.setMulticastEnabled(anyBoolean())) + .thenAnswer(newSetter(multicastEnabled, mockRegionFactory)); + + when(mockRegionFactory.setOffHeap(anyBoolean())).thenAnswer(newSetter(offHeap, mockRegionFactory)); + + when(mockRegionFactory.setPartitionAttributes(any(PartitionAttributes.class))) + .thenAnswer(newSetter(partitionAttributes, mockRegionFactory)); + + when(mockRegionFactory.setPoolName(anyString())).thenAnswer(newSetter(poolName, mockRegionFactory)); + + when(mockRegionFactory.setRegionIdleTimeout(any(ExpirationAttributes.class))) + .thenAnswer(newSetter(regionIdleTimeout, mockRegionFactory)); + + when(mockRegionFactory.setRegionTimeToLive(any(ExpirationAttributes.class))) + .thenAnswer(newSetter(regionTimeToLive, mockRegionFactory)); + + when(mockRegionFactory.setScope(any(Scope.class))).thenAnswer(newSetter(scope, mockRegionFactory)); + + when(mockRegionFactory.setStatisticsEnabled(anyBoolean())) + .thenAnswer(newSetter(statisticsEnabled, mockRegionFactory)); + + when(mockRegionFactory.setSubscriptionAttributes(any(SubscriptionAttributes.class))) + .thenAnswer(newSetter(subscriptionAttributes, mockRegionFactory)); + + when(mockRegionFactory.setValueConstraint(any(Class.class))) + .thenAnswer(newSetter(valueConstraint, mockRegionFactory)); + + RegionAttributes mockRegionAttributes = + mock(RegionAttributes.class, mockObjectIdentifier("MockRegionAttributes")); + + when(mockRegionAttributes.getAsyncEventQueueIds()).thenReturn(asyncEventQueueIds); + + when(mockRegionAttributes.getCacheListeners()) + .thenAnswer(newGetter(() -> cacheListeners.toArray(new CacheListener[cacheListeners.size()]))); + + when(mockRegionAttributes.getCacheLoader()).thenAnswer(newGetter(cacheLoader)); + when(mockRegionAttributes.getCacheWriter()).thenAnswer(newGetter(cacheWriter)); + when(mockRegionAttributes.getCloningEnabled()).thenAnswer(newGetter(cloningEnabled)); + when(mockRegionAttributes.getCompressor()).thenAnswer(newGetter(compressor)); + when(mockRegionAttributes.getConcurrencyChecksEnabled()).thenAnswer(newGetter(concurrencyChecksEnabled)); + when(mockRegionAttributes.getConcurrencyLevel()).thenAnswer(newGetter(concurrencyLevel)); + when(mockRegionAttributes.getCustomEntryIdleTimeout()).thenAnswer(newGetter(customEntryIdleTimeout)); + when(mockRegionAttributes.getCustomEntryTimeToLive()).thenAnswer(newGetter(customEntryTimeToLive)); + when(mockRegionAttributes.getDataPolicy()).thenAnswer(newGetter(dataPolicy)); + when(mockRegionAttributes.getDiskStoreName()).thenAnswer(newGetter(diskStoreName)); + when(mockRegionAttributes.isDiskSynchronous()).thenAnswer(newGetter(diskSynchronous)); + when(mockRegionAttributes.getEnableAsyncConflation()).thenAnswer(newGetter(enableAsyncConflation)); + when(mockRegionAttributes.getEnableSubscriptionConflation()).thenAnswer(newGetter(enableSubscriptionConflation)); + when(mockRegionAttributes.getEntryIdleTimeout()).thenAnswer(newGetter(entryIdleTimeout)); + when(mockRegionAttributes.getEntryTimeToLive()).thenAnswer(newGetter(entryTimeToLive)); + when(mockRegionAttributes.getEvictionAttributes()).thenAnswer(newGetter(evictionAttributes)); + when(mockRegionAttributes.getGatewaySenderIds()).thenReturn(gatewaySenderIds); + when(mockRegionAttributes.getIgnoreJTA()).thenAnswer(newGetter(ignoreJta)); + when(mockRegionAttributes.getIndexMaintenanceSynchronous()).thenAnswer(newGetter(indexMaintenanceSynchronous)); + when(mockRegionAttributes.getInitialCapacity()).thenAnswer(newGetter(initialCapacity)); + when(mockRegionAttributes.getKeyConstraint()).thenAnswer(newGetter(keyConstraint)); + when(mockRegionAttributes.getLoadFactor()).thenAnswer(newGetter(loadFactor)); + when(mockRegionAttributes.isLockGrantor()).thenAnswer(newGetter(lockGrantor)); + when(mockRegionAttributes.getMulticastEnabled()).thenAnswer(newGetter(multicastEnabled)); + when(mockRegionAttributes.getOffHeap()).thenAnswer(newGetter(offHeap)); + when(mockRegionAttributes.getPartitionAttributes()).thenAnswer(newGetter(partitionAttributes)); + when(mockRegionAttributes.getPoolName()).thenAnswer(newGetter(poolName)); + when(mockRegionAttributes.getRegionIdleTimeout()).thenAnswer(newGetter(regionIdleTimeout)); + when(mockRegionAttributes.getRegionTimeToLive()).thenAnswer(newGetter(regionTimeToLive)); + when(mockRegionAttributes.getScope()).thenAnswer(newGetter(scope)); + when(mockRegionAttributes.getStatisticsEnabled()).thenAnswer(newGetter(statisticsEnabled)); + when(mockRegionAttributes.getSubscriptionAttributes()).thenAnswer(newGetter(subscriptionAttributes)); + when(mockRegionAttributes.getValueConstraint()).thenAnswer(newGetter(valueConstraint)); + + when(mockRegionFactory.create(anyString())).thenAnswer(invocation -> + mockRegion(mockCache, invocation.getArgument(0), mockRegionAttributes)); + + when(mockRegionFactory.createSubregion(any(Region.class), anyString())).thenAnswer(invocation -> + mockSubRegion(invocation.getArgument(0), invocation.getArgument(1), mockRegionAttributes)); + + return mockRegionFactory; + } + public static ResourceManager mockResourceManager() { ResourceManager mockResourceManager = mock(ResourceManager.class); @@ -1059,25 +1685,6 @@ public abstract class MockGemFireObjectsSupport extends MockObjectsSupport { return mockResourceManager; } - private static T rememberMockedGemFireCache(T mockedGemFireCache, - boolean useSingletonCache) { - - return Optional.ofNullable(mockedGemFireCache) - .map(it -> { - if (useSingletonCache) { - singletonCache.compareAndSet(null, mockedGemFireCache); - } - - return mockedGemFireCache; - }) - .orElseThrow(() -> newIllegalArgumentException("GemFireCache is required")); - } - - @SuppressWarnings("unchecked") - private static Optional resolveMockedGemFireCache(boolean useSingletonCache) { - return Optional.ofNullable((T) singletonCache.get()).filter(it -> useSingletonCache); - } - public static CacheFactory spyOn(CacheFactory cacheFactory) { return spyOn(cacheFactory, DEFAULT_USE_SINGLETON_CACHE); } @@ -1291,4 +1898,8 @@ public abstract class MockGemFireObjectsSupport extends MockObjectsSupport { return clientCacheFactorySpy; } + + protected interface IoExceptionThrowingOperation { + void doIo() throws IOException; + } } diff --git a/src/test/java/org/springframework/data/gemfire/test/mock/MockObjectsSupport.java b/src/test/java/org/springframework/data/gemfire/test/mock/MockObjectsSupport.java index aaf9a4fa..fc0d7ff2 100644 --- a/src/test/java/org/springframework/data/gemfire/test/mock/MockObjectsSupport.java +++ b/src/test/java/org/springframework/data/gemfire/test/mock/MockObjectsSupport.java @@ -16,6 +16,7 @@ package org.springframework.data.gemfire.test.mock; +import java.util.Collection; import java.util.Map; import java.util.Optional; import java.util.concurrent.atomic.AtomicBoolean; @@ -46,11 +47,11 @@ public abstract class MockObjectsSupport { private static final String DEFAULT_MOCK_OBJECT_NAME = "MockObject"; - protected static String mockObjectIdentifier() { + public static String mockObjectIdentifier() { return mockObjectIdentifier(DEFAULT_MOCK_OBJECT_NAME); } - protected static String mockObjectIdentifier(String mockObjectName) { + public static String mockObjectIdentifier(String mockObjectName) { return String.format("%s%d", Optional.ofNullable(mockObjectName).filter(StringUtils::hasText) .orElse(DEFAULT_MOCK_OBJECT_NAME), mockObjectIdentifier.incrementAndGet()); } @@ -90,6 +91,14 @@ public abstract class MockObjectsSupport { return invocation -> converter.apply(returnValue.get()); } + /* (non-Javadoc) */ + protected static , R> Answer newAdder(C collection, R returnValue) { + return invocation -> { + collection.add(invocation.getArgument(0)); + return returnValue; + }; + } + /* (non-Javadoc) */ protected static Answer newSetter(AtomicBoolean argument, R returnValue) { return invocation -> {