SGF-603 - Add ignoreIfExists attribute defaulted to true in @<Type>Region annotations for @EnableEntityDefinedRegions.

(cherry picked from commit 043cc922b95b0620b7ddb76b7bb19d96498d2561)
Signed-off-by: John Blum <jblum@pivotal.io>
This commit is contained in:
John Blum
2017-03-08 22:33:47 -08:00
parent 9b59a75b5c
commit 7562129080
14 changed files with 309 additions and 135 deletions

View File

@@ -16,6 +16,8 @@
package org.springframework.data.gemfire;
import java.util.Optional;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.geode.cache.GemFireCache;
@@ -44,7 +46,7 @@ public abstract class RegionLookupFactoryBean<K, V>
protected final Log log = LogFactory.getLog(getClass());
private Boolean lookupEnabled = Boolean.TRUE;
private Boolean lookupEnabled = false;
private GemFireCache cache;
@@ -70,8 +72,9 @@ public abstract class RegionLookupFactoryBean<K, V>
synchronized (this.cache) {
if (isLookupEnabled()) {
this.region = (getParent() != null ? getParent().<K, V>getSubregion(regionName)
: this.cache.<K, V>getRegion(regionName));
this.region = Optional.ofNullable(getParent())
.map(parentRegion -> parentRegion.<K, V>getSubregion(regionName))
.orElseGet(() -> this.cache.<K, V>getRegion(regionName));
}
if (region != null) {

View File

@@ -39,9 +39,7 @@ import org.springframework.core.annotation.AliasFor;
* @see org.springframework.context.annotation.ComponentScan.Filter
* @see org.springframework.context.annotation.Import
* @see org.springframework.core.annotation.AliasFor
* @see org.springframework.data.gemfire.config.annotation.EnableIndexes
* @see org.springframework.data.gemfire.config.annotation.EntityDefinedRegionsConfiguration
* @see org.springframework.data.gemfire.config.annotation.IndexConfiguration
* @see org.apache.geode.cache.Region
* @since 1.9.0
*/
@@ -84,6 +82,14 @@ public @interface EnableEntityDefinedRegions {
*/
Class<?>[] basePackageClasses() default {};
/**
* Specifies which types are not eligible for component scanning.
*
* @return an array of {@link org.springframework.context.annotation.ComponentScan.Filter Filters} used to
* specify application persistent entities to be excluded during the component scan.
*/
ComponentScan.Filter[] excludeFilters() default {};
/**
* Specifies which types are eligible for component scanning. Further narrows the set of candidate components
* from everything in {@link #basePackages()} to everything in the base packages that matches the given filter
@@ -94,14 +100,6 @@ public @interface EnableEntityDefinedRegions {
*/
ComponentScan.Filter[] includeFilters() default {};
/**
* Specifies which types are not eligible for component scanning.
*
* @return an array of {@link org.springframework.context.annotation.ComponentScan.Filter Filters} used to
* specify application persistent entities to be excluded during the component scan.
*/
ComponentScan.Filter[] excludeFilters() default {};
/**
* 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.

View File

@@ -17,8 +17,9 @@
package org.springframework.data.gemfire.config.annotation;
import static org.apache.geode.internal.lang.ObjectUtils.defaultIfNull;
import static java.util.Arrays.stream;
import static org.springframework.data.gemfire.util.ArrayUtils.defaultIfEmpty;
import static org.springframework.data.gemfire.util.ArrayUtils.nullSafeArray;
import java.lang.annotation.Annotation;
import java.util.Collections;
@@ -69,7 +70,6 @@ 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.util.ArrayUtils;
import org.springframework.data.gemfire.util.CollectionUtils;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
@@ -82,6 +82,7 @@ import org.springframework.util.StringUtils;
* based on the application persistent entity classes.
*
* @author John Blum
* @see java.lang.annotation.Annotation
* @see org.springframework.beans.factory.BeanClassLoaderAware
* @see org.springframework.beans.factory.BeanFactory
* @see org.springframework.beans.factory.BeanFactoryAware
@@ -89,19 +90,23 @@ import org.springframework.util.StringUtils;
* @see org.springframework.beans.factory.support.BeanDefinitionBuilder
* @see org.springframework.beans.factory.support.BeanDefinitionRegistry
* @see org.springframework.context.annotation.ImportBeanDefinitionRegistrar
* @see org.springframework.data.gemfire.FixedPartitionAttributesFactoryBean
* @see org.springframework.data.gemfire.LocalRegionFactoryBean
* @see org.springframework.data.gemfire.PartitionAttributesFactoryBean
* @see org.springframework.data.gemfire.PartitionedRegionFactoryBean
* @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 org.springframework.data.gemfire.config.annotation.support.GemFireComponentClassTypeScanner
* @see ClientRegion
* @see org.springframework.data.gemfire.mapping.GemfireMappingContext
* @see org.springframework.data.gemfire.mapping.GemfirePersistentEntity
* @see LocalRegion
* @see PartitionRegion
* @see ReplicateRegion
* @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.Region
* @see org.apache.geode.cache.Region
* @since 1.9.0
*/
public class EntityDefinedRegionsConfiguration
@@ -232,16 +237,16 @@ public class EntityDefinedRegionsConfiguration
/* (non-Javadoc) */
protected GemfireMappingContext resolveMappingContext() {
if (this.mappingContext == null) {
return Optional.ofNullable(this.mappingContext).orElseGet(() -> {
try {
this.mappingContext = getBeanFactory().getBean(GemfireMappingContext.class);
}
catch (Throwable ignore) {
this.mappingContext = new GemfireMappingContext();
}
}
return this.mappingContext;
return this.mappingContext;
});
}
/**
@@ -284,15 +289,14 @@ public class EntityDefinedRegionsConfiguration
Set<String> resolvedBasePackages = new HashSet<>();
Collections.addAll(resolvedBasePackages, ArrayUtils.nullSafeArray(defaultIfEmpty(
Collections.addAll(resolvedBasePackages, nullSafeArray(defaultIfEmpty(
enableEntityDefinedRegionAttributes.getStringArray("basePackages"),
enableEntityDefinedRegionAttributes.getStringArray("value")), String.class));
enableEntityDefinedRegionAttributes.getStringArray("value")),
String.class));
for (Class<?> type : ArrayUtils.nullSafeArray(
enableEntityDefinedRegionAttributes.getClassArray("basePackageClasses"), Class.class)) {
resolvedBasePackages.add(type.getPackage().getName());
}
stream(nullSafeArray(enableEntityDefinedRegionAttributes.getClassArray(
"basePackageClasses"), Class.class))
.forEach(type -> resolvedBasePackages.add(type.getPackage().getName()));
if (resolvedBasePackages.isEmpty()) {
resolvedBasePackages.add(ClassUtils.getPackageName(importingClassMetaData.getClassName()));
@@ -303,7 +307,8 @@ public class EntityDefinedRegionsConfiguration
/* (non-Javadoc) */
protected ClassLoader resolveBeanClassLoader() {
return (this.beanClassLoader != null ? this.beanClassLoader : Thread.currentThread().getContextClassLoader());
return Optional.ofNullable(this.beanClassLoader)
.orElseGet(() -> Thread.currentThread().getContextClassLoader());
}
/* (non-Javadoc) */
@@ -320,11 +325,8 @@ public class EntityDefinedRegionsConfiguration
private Iterable<TypeFilter> parseFilters(AnnotationAttributes[] componentScanFilterAttributes) {
Set<TypeFilter> typeFilters = new HashSet<>();
for (AnnotationAttributes filterAttributes : ArrayUtils.nullSafeArray(
componentScanFilterAttributes, AnnotationAttributes.class)) {
CollectionUtils.addAll(typeFilters, typeFiltersFor(filterAttributes));
}
stream(nullSafeArray(componentScanFilterAttributes, AnnotationAttributes.class))
.forEach(filterAttributes -> CollectionUtils.addAll(typeFilters, typeFiltersFor(filterAttributes)));
return typeFilters;
}
@@ -335,7 +337,7 @@ public class EntityDefinedRegionsConfiguration
Set<TypeFilter> typeFilters = new HashSet<>();
FilterType filterType = filterAttributes.getEnum("type");
for (Class<?> filterClass : ArrayUtils.nullSafeArray(filterAttributes.getClassArray("value"), Class.class)) {
for (Class<?> filterClass : nullSafeArray(filterAttributes.getClassArray("value"), Class.class)) {
switch (filterType) {
case ANNOTATION:
Assert.isAssignable(Annotation.class, filterClass,
@@ -382,7 +384,7 @@ public class EntityDefinedRegionsConfiguration
*/
private String[] nullSafeGetPatterns(AnnotationAttributes filterAttributes) {
try {
return ArrayUtils.nullSafeArray(filterAttributes.getStringArray("pattern"), String.class);
return nullSafeArray(filterAttributes.getStringArray("pattern"), String.class);
}
catch (IllegalArgumentException ignore) {
return new String[0];
@@ -394,11 +396,8 @@ public class EntityDefinedRegionsConfiguration
protected Iterable<TypeFilter> regionAnnotatedPersistentEntityTypeFilters() {
Set<TypeFilter> regionAnnotatedPersistentEntityTypeFilters = new HashSet<>();
for (Class<? extends Annotation> annotationType :
org.springframework.data.gemfire.mapping.annotation.Region.REGION_ANNOTATION_TYPES) {
regionAnnotatedPersistentEntityTypeFilters.add(new AnnotationTypeFilter(annotationType));
}
org.springframework.data.gemfire.mapping.annotation.Region.REGION_ANNOTATION_TYPES.forEach(
annotationType -> regionAnnotatedPersistentEntityTypeFilters.add(new AnnotationTypeFilter(annotationType)));
return regionAnnotatedPersistentEntityTypeFilters;
}
@@ -423,19 +422,17 @@ public class EntityDefinedRegionsConfiguration
protected Class<? extends RegionLookupFactoryBean> resolveRegionFactoryBeanClass(
GemfirePersistentEntity persistentEntity) {
return defaultIfNull(regionAnnotationToRegionFactoryBeanClass.get(persistentEntity.getRegionAnnotationType()),
DEFAULT_REGION_FACTORY_BEAN_CLASS);
return Optional.<Class<? extends RegionLookupFactoryBean>>ofNullable(
regionAnnotationToRegionFactoryBeanClass.get(persistentEntity.getRegionAnnotationType()))
.orElse(DEFAULT_REGION_FACTORY_BEAN_CLASS);
}
/* (non-Javadoc) */
protected BeanDefinitionBuilder setRegionAttributes(GemfirePersistentEntity persistentEntity,
BeanDefinitionBuilder regionFactoryBeanBuilder, boolean strict) {
Annotation regionAnnotation = persistentEntity.getRegionAnnotation();
if (regionAnnotation != null) {
AnnotationAttributes regionAnnotationAttributes =
AnnotationAttributes.fromMap(AnnotationUtils.getAnnotationAttributes(regionAnnotation));
Optional.ofNullable(persistentEntity.getRegionAnnotation()).ifPresent(regionAnnotation -> {
AnnotationAttributes regionAnnotationAttributes = getAnnotationAttributes(regionAnnotation);
if (strict) {
regionFactoryBeanBuilder.addPropertyValue("keyConstraint", resolveIdType(persistentEntity));
@@ -445,13 +442,19 @@ public class EntityDefinedRegionsConfiguration
if (regionAnnotationAttributes.containsKey("diskStoreName")) {
String diskStoreName = regionAnnotationAttributes.getString("diskStoreName");
setPropertyValueIfNotDefault(regionFactoryBeanBuilder, "diskStoreName", diskStoreName, "");
setPropertyValueIfNotDefault(regionFactoryBeanBuilder, "diskStoreName",
diskStoreName, "");
if (StringUtils.hasText(diskStoreName)) {
regionFactoryBeanBuilder.addDependsOn(diskStoreName);
}
}
if (regionAnnotationAttributes.containsKey("ignoreIfExists")) {
regionFactoryBeanBuilder.addPropertyValue("lookupEnabled",
regionAnnotationAttributes.getBoolean("ignoreIfExists"));
}
if (regionAnnotationAttributes.containsKey("persistent")) {
setPropertyValueIfNotDefault(regionFactoryBeanBuilder, "persistent",
regionAnnotationAttributes.getBoolean("persistent"), false);
@@ -476,22 +479,21 @@ public class EntityDefinedRegionsConfiguration
regionAttributesFactoryBeanBuilder);
setReplicateRegionAttributes(regionAnnotationAttributes, regionFactoryBeanBuilder);
}
});
return regionFactoryBeanBuilder;
}
/* (non-Javadoc) */
protected Class<?> resolveDomainType(GemfirePersistentEntity persistentEntity) {
return Optional.of(persistentEntity.getType()).orElse(Object.class);
return Optional.ofNullable(persistentEntity.getType()).orElse(Object.class);
}
/* (non-Javadoc) */
@SuppressWarnings("unchecked")
protected Class<?> resolveIdType(GemfirePersistentEntity persistentEntity) {
return (Class<?>) persistentEntity.getIdProperty()
.map((idProperty) -> ((GemfirePersistentProperty) idProperty).getActualType())
.map(idProperty -> ((GemfirePersistentProperty) idProperty).getActualType())
.orElse(Object.class);
}
@@ -502,8 +504,8 @@ public class EntityDefinedRegionsConfiguration
BeanDefinitionBuilder regionAttributesFactoryBeanBuilder = regionFactoryBeanBuilder;
if (!ClientRegion.class.isAssignableFrom(regionAnnotation.annotationType())) {
regionAttributesFactoryBeanBuilder = BeanDefinitionBuilder.genericBeanDefinition(
RegionAttributesFactoryBean.class);
regionAttributesFactoryBeanBuilder =
BeanDefinitionBuilder.genericBeanDefinition(RegionAttributesFactoryBean.class);
regionFactoryBeanBuilder.addPropertyValue("attributes",
regionAttributesFactoryBeanBuilder.getBeanDefinition());
@@ -564,9 +566,8 @@ public class EntityDefinedRegionsConfiguration
protected BeanDefinitionBuilder setFixedPartitionRegionAttributes(AnnotationAttributes regionAnnotationAttributes,
BeanDefinitionBuilder partitionAttributesFactoryBeanBuilder) {
PartitionRegion.FixedPartition[] fixedPartitions = ArrayUtils.nullSafeArray(
regionAnnotationAttributes.getAnnotationArray("fixedPartitions", PartitionRegion.FixedPartition.class),
PartitionRegion.FixedPartition.class);
PartitionRegion.FixedPartition[] fixedPartitions = nullSafeArray(regionAnnotationAttributes.getAnnotationArray(
"fixedPartitions", PartitionRegion.FixedPartition.class), PartitionRegion.FixedPartition.class);
if (!ObjectUtils.isEmpty(fixedPartitions)) {
ManagedList<BeanDefinition> fixedPartitionAttributesFactoryBeans =
@@ -601,7 +602,8 @@ public class EntityDefinedRegionsConfiguration
if (regionAnnotationAttributes.containsKey("scope")) {
setPropertyValueIfNotDefault(regionFactoryBeanBuilder, "scope",
regionAnnotationAttributes.<ScopeType>getEnum("scope").getScope(), ScopeType.DISTRIBUTED_NO_ACK);
regionAnnotationAttributes.<ScopeType>getEnum("scope").getScope(),
ScopeType.DISTRIBUTED_NO_ACK);
}
return regionFactoryBeanBuilder;
@@ -611,7 +613,8 @@ public class EntityDefinedRegionsConfiguration
private <T> BeanDefinitionBuilder setPropertyReferenceIfSet(BeanDefinitionBuilder beanDefinitionBuilder,
String propertyName, String beanName) {
return (StringUtils.hasText(beanName) ? beanDefinitionBuilder.addPropertyReference(propertyName, beanName)
return (StringUtils.hasText(beanName)
? beanDefinitionBuilder.addPropertyReference(propertyName, beanName)
: beanDefinitionBuilder);
}
@@ -619,8 +622,9 @@ public class EntityDefinedRegionsConfiguration
private <T> BeanDefinitionBuilder setPropertyValueIfNotDefault(BeanDefinitionBuilder beanDefinitionBuilder,
String propertyName, T value, T defaultValue) {
return (value != null && !value.equals(defaultValue) ?
beanDefinitionBuilder.addPropertyValue(propertyName, value) : beanDefinitionBuilder);
return (value != null && !value.equals(defaultValue)
? beanDefinitionBuilder.addPropertyValue(propertyName, value)
: beanDefinitionBuilder);
}
/**

View File

@@ -35,7 +35,8 @@ import org.springframework.data.gemfire.config.xml.GemfireConstants;
* persistent entity will be stored.
*
* @author John Blum
* @see Region
* @see org.springframework.data.gemfire.config.annotation.EntityDefinedRegionsConfiguration
* @see org.springframework.data.gemfire.mapping.annotation.Region
* @since 1.9.0
*/
@Target(ElementType.TYPE)
@@ -87,6 +88,16 @@ public @interface ClientRegion {
*/
boolean diskSynchronous() default true;
/**
* Determines whether an entity annotated with this Region annotation will ignore any existing Region definition
* identified by the given {@link #name()} for this entity.
*
* Overrides the global, {@link EnableEntityDefinedRegions#ignoreIfExists()} setting.
*
* Defaults to {@literal true}.
*/
boolean ignoreIfExists() default true;
/**
* Name of the GemFire/Geode {@link Pool} used by this persistent entity's {@link org.apache.geode.cache.Region}
* data access operations sent to the corresponding {@link org.apache.geode.cache.Region}

View File

@@ -26,12 +26,14 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.core.annotation.AliasFor;
import org.springframework.data.gemfire.config.annotation.EnableEntityDefinedRegions;
/**
* {@link Annotation} defining the Local {@link Region} in which the application persistent entity will be stored.
*
* @author John Blum
* @see Region
* @see org.springframework.data.gemfire.config.annotation.EnableEntityDefinedRegions
* @see org.springframework.data.gemfire.mapping.annotation.Region
* @since 1.9.0
*/
@Target(ElementType.TYPE)
@@ -83,6 +85,16 @@ public @interface LocalRegion {
*/
boolean diskSynchronous() default true;
/**
* Determines whether an entity annotated with this Region annotation will ignore any existing Region definition
* identified by the given {@link #name()} for this entity.
*
* Overrides the global, {@link EnableEntityDefinedRegions#ignoreIfExists()} setting.
*
* Defaults to {@literal true}.
*/
boolean ignoreIfExists() default true;
/**
* Determines whether this {@link org.apache.geode.cache.Region Region's} data access operations participates in
* any existing, Global JTA transaction in progress.

View File

@@ -31,7 +31,8 @@ import org.springframework.core.annotation.AliasFor;
* {@link Annotation} defining the Partition {@link Region} in which the application persistent entity will be stored.
*
* @author John Blum
* @see Region
* @see org.springframework.data.gemfire.config.annotation.EntityDefinedRegionsConfiguration
* @see org.springframework.data.gemfire.mapping.annotation.Region
* @since 1.9.0
*/
@Target(ElementType.TYPE)
@@ -105,6 +106,16 @@ public @interface PartitionRegion {
*/
FixedPartition[] fixedPartitions() default {};
/**
* Determines whether an entity annotated with this Region annotation will ignore any existing Region definition
* identified by the given {@link #name()} for this entity.
*
* Overrides the global, {@link EnableEntityDefinedRegions#ignoreIfExists()} setting.
*
* Defaults to {@literal true}.
*/
boolean ignoreIfExists() default true;
/**
* Determines whether this {@link org.apache.geode.cache.Region Region's} data access operations participates in
* any existing, Global JTA transaction in progress.

View File

@@ -71,4 +71,14 @@ public @interface Region {
@AliasFor(attribute = "name")
String value() default "";
/**
* Determines whether an entity annotated with this Region annotation will ignore any existing Region definition
* identified by the given {@link #name()} for this entity.
*
* Overrides the global, {@link EnableEntityDefinedRegions#ignoreIfExists()} setting.
*
* Defaults to {@literal true}.
*/
boolean ignoreIfExists() default true;
}

View File

@@ -32,7 +32,8 @@ import org.springframework.data.gemfire.ScopeType;
* {@link Annotation} defining the Replicate {@link Region} in which the application persistent entity will be stored.
*
* @author John Blum
* @see Region
* @see org.springframework.data.gemfire.config.annotation.EntityDefinedRegionsConfiguration
* @see org.springframework.data.gemfire.mapping.annotation.Region
* @since 1.9.0
*/
@Target(ElementType.TYPE)
@@ -84,6 +85,16 @@ public @interface ReplicateRegion {
*/
boolean diskSynchronous() default true;
/**
* Determines whether an entity annotated with this Region annotation will ignore any existing Region definition
* identified by the given {@link #name()} for this entity.
*
* Overrides the global, {@link EnableEntityDefinedRegions#ignoreIfExists()} setting.
*
* Defaults to {@literal true}.
*/
boolean ignoreIfExists() default true;
/**
* Determines whether this {@link org.apache.geode.cache.Region Region's} data access operations participates in
* any existing, Global JTA transaction in progress.

View File

@@ -21,6 +21,7 @@ import org.apache.geode.cache.Cache;
import org.apache.geode.cache.CacheClosedException;
import org.apache.geode.cache.CacheFactory;
import org.apache.geode.cache.GemFireCache;
import org.apache.geode.cache.Region;
import org.apache.geode.cache.client.ClientCache;
import org.apache.geode.cache.client.ClientCacheFactory;
import org.apache.geode.distributed.DistributedSystem;
@@ -125,7 +126,13 @@ public abstract class CacheUtils extends DistributedSystemUtils {
}
}
/* (non-Javadoc) */
public static GemFireCache resolveGemFireCache() {
return defaultIfNull(getCache(), CacheUtils::getClientCache);
}
/* (non-Javadoc) */
public static String toRegionPath(String regionName) {
return String.format("%1$s%2$s", Region.SEPARATOR, regionName);
}
}

View File

@@ -16,6 +16,7 @@
package org.springframework.data.gemfire.util;
import java.util.Optional;
import java.util.Properties;
import org.apache.geode.cache.GemFireCache;
@@ -87,7 +88,7 @@ public abstract class DistributedSystemUtils extends SpringUtils {
/* (non-Javadoc) */
@SuppressWarnings("unchecked")
public static <T extends DistributedSystem> T getDistributedSystem(GemFireCache gemfireCache) {
return (gemfireCache != null ? (T) gemfireCache.getDistributedSystem() : null);
return (T) Optional.ofNullable(gemfireCache).map(GemFireCache::getDistributedSystem).orElse(null);
}
/* (non-Javadoc)*/

View File

@@ -23,6 +23,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.function.Supplier;
import org.springframework.beans.factory.BeanFactory;
@@ -57,12 +58,12 @@ public abstract class SpringUtils {
/* (non-Javadoc) */
public static <T> T defaultIfNull(T value, T defaultValue) {
return (value != null ? value : defaultValue);
return Optional.ofNullable(value).orElse(defaultValue);
}
/* (non-Javadoc) */
public static <T> T defaultIfNull(T value, Supplier<T> supplier) {
return (value != null ? value : supplier.get());
return Optional.ofNullable(value).orElseGet(supplier);
}
/* (non-Javadoc) */

View File

@@ -21,10 +21,16 @@ 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.CacheUtils.toRegionPath;
import static org.springframework.data.gemfire.util.CollectionUtils.nullSafeList;
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;
@@ -32,10 +38,12 @@ import org.apache.geode.cache.Cache;
import org.apache.geode.cache.DataPolicy;
import org.apache.geode.cache.DiskStore;
import org.apache.geode.cache.FixedPartitionAttributes;
import org.apache.geode.cache.GemFireCache;
import org.apache.geode.cache.PartitionAttributes;
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.Scope;
import org.apache.geode.cache.client.ClientCache;
@@ -45,6 +53,7 @@ import org.junit.After;
import org.junit.Test;
import org.mockito.invocation.InvocationOnMock;
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;
@@ -52,17 +61,21 @@ 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;
import org.springframework.data.gemfire.config.annotation.test.entities.LocalRegionEntity;
import org.springframework.data.gemfire.config.annotation.test.entities.NonEntity;
import org.springframework.data.gemfire.config.annotation.test.entities.PartitionRegionEntity;
import org.springframework.data.gemfire.config.annotation.test.entities.ReplicateRegionEntity;
import org.springframework.data.gemfire.config.xml.GemfireConstants;
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.util.CollectionUtils;
/**
* Unit tests for the {@link EnableEntityDefinedRegions} annotation and {@link EntityDefinedRegionsConfiguration} class.
@@ -78,25 +91,26 @@ public class EnableEntityDefinedRegionsConfigurationUnitTests {
private static final AtomicInteger MOCK_ID = new AtomicInteger(0);
private static final Set<Region<?, ?>> cacheRegions = new HashSet<>();
private ConfigurableApplicationContext applicationContext;
@After
public void tearDown() {
if (applicationContext != null) {
applicationContext.close();
}
Optional.ofNullable(this.applicationContext).ifPresent(ConfigurableApplicationContext::close);
cacheRegions.clear();
}
/* (non-Javadoc) */
protected void assertRegion(Region<?, ?> region, String name) {
assertRegion(region, name, null, null);
assertRegion(region, name, toRegionPath(name), null, null);
}
/* (non-Javadoc) */
protected <K, V> void assertRegion(Region<?, ?> region, String name,
Class<K> keyConstraint, Class<V> valueConstraint) {
assertRegion(region, name, String.format("%1$s%2$s", Region.SEPARATOR, name), keyConstraint, valueConstraint);
assertRegion(region, name, toRegionPath(name), keyConstraint, valueConstraint);
}
/* (non-Javadoc) */
@@ -157,7 +171,7 @@ public class EnableEntityDefinedRegionsConfigurationUnitTests {
assertThat(partitionAttributes).isNotNull();
List<FixedPartitionAttributes> fixedPartitionAttributes =
CollectionUtils.nullSafeList(partitionAttributes.getFixedPartitionAttributes());
nullSafeList(partitionAttributes.getFixedPartitionAttributes());
for (FixedPartitionAttributes attributes : fixedPartitionAttributes) {
if (attributes.getPartitionName().equals(partitionName)) {
@@ -183,15 +197,15 @@ public class EnableEntityDefinedRegionsConfigurationUnitTests {
Region<String, ClientRegionEntity> sessions = applicationContext.getBean("Sessions", Region.class);
assertRegion(sessions, "Sessions", String.class, ClientRegionEntity.class);
assertRegionAttributes(sessions.getAttributes(), DataPolicy.NORMAL, null, true, false,
GemfireConstants.DEFAULT_GEMFIRE_POOL_NAME, null);
assertRegionAttributes(sessions.getAttributes(), DataPolicy.NORMAL, null, true,
false, GemfireConstants.DEFAULT_GEMFIRE_POOL_NAME, null);
Region<Long, GenericRegionEntity> genericRegionEntity =
applicationContext.getBean("GenericRegionEntity", Region.class);
assertRegion(genericRegionEntity, "GenericRegionEntity", Long.class, GenericRegionEntity.class);
assertRegionAttributes(genericRegionEntity.getAttributes(), DataPolicy.EMPTY, null, true, false,
GemfireConstants.DEFAULT_GEMFIRE_POOL_NAME, null);
assertRegionAttributes(genericRegionEntity.getAttributes(), DataPolicy.EMPTY, null,
true, false, GemfireConstants.DEFAULT_GEMFIRE_POOL_NAME, null);
assertThat(applicationContext.containsBean("CollocatedPartitionRegionEntity")).isFalse();
assertThat(applicationContext.containsBean("ContactEvents")).isFalse();
@@ -211,19 +225,20 @@ public class EnableEntityDefinedRegionsConfigurationUnitTests {
Region<Object, Object> customers = applicationContext.getBean("Customers", Region.class);
assertRegion(customers, "Customers");
assertRegionAttributes(customers.getAttributes(), DataPolicy.PERSISTENT_PARTITION, null, true, false, null,
Scope.DISTRIBUTED_NO_ACK);
assertPartitionAttributes(customers.getAttributes().getPartitionAttributes(), null, null, 1);
assertFixedPartitionAttributes(findFixedPartitionAttributes(
customers.getAttributes().getPartitionAttributes(), "one"), "one", true, 16);
assertFixedPartitionAttributes(findFixedPartitionAttributes(
customers.getAttributes().getPartitionAttributes(), "two"), "two", false, 21);
assertRegionAttributes(customers.getAttributes(), DataPolicy.PERSISTENT_PARTITION, null,
true, false, null, Scope.DISTRIBUTED_NO_ACK);
assertPartitionAttributes(customers.getAttributes().getPartitionAttributes(), null,
null, 1);
assertFixedPartitionAttributes(findFixedPartitionAttributes(customers.getAttributes().getPartitionAttributes(),
"one"), "one", true, 16);
assertFixedPartitionAttributes(findFixedPartitionAttributes(customers.getAttributes().getPartitionAttributes(),
"two"), "two", false, 21);
Region<Object, Object> contactEvents = applicationContext.getBean("ContactEvents", Region.class);
assertRegion(contactEvents, "ContactEvents");
assertRegionAttributes(contactEvents.getAttributes(), DataPolicy.PERSISTENT_PARTITION, "mockDiskStore",
false, true, null, Scope.DISTRIBUTED_NO_ACK);
assertRegionAttributes(contactEvents.getAttributes(), DataPolicy.PERSISTENT_PARTITION,
"mockDiskStore", false, true, null, Scope.DISTRIBUTED_NO_ACK);
assertPartitionAttributes(contactEvents.getAttributes().getPartitionAttributes(), "Customers",
applicationContext.getBean("mockPartitionResolver", PartitionResolver.class), 2);
@@ -237,23 +252,49 @@ public class EnableEntityDefinedRegionsConfigurationUnitTests {
assertThat(applicationContext.containsBean("Sessions")).isFalse();
}
@Test(expected = RegionExistsException.class)
public void entityPeerPartitionRegionAlreadyDefinedThrowsRegionExistsException() {
try {
applicationContext = newApplicationContext(ExistingPartitionRegionPersistentEntitiesConfiguration.class);
}
catch (BeanCreationException expected) {
assertThat(expected).hasCauseInstanceOf(RegionExistsException.class);
assertThat(expected.getCause()).hasMessage("/Customers");
throw (RegionExistsException) expected.getCause();
}
}
@Test
@SuppressWarnings("unchecked")
public void entityServerRegionsDefined() {
applicationContext = newApplicationContext(AllServerPersistentEntitiesConfiguration.class);
public void entityReplicateRegionAlreadyDefinedIgnoresEntityDefinedRegionDefinition() {
applicationContext = newApplicationContext(ExistingReplicateRegionPersistentEntitiesConfiguration.class);
Region<Object, Object> accounts = applicationContext.getBean("Accounts", Region.class);
assertRegion(accounts, "Accounts");
assertRegionAttributes(accounts.getAttributes(), DataPolicy.REPLICATE, null, true, false, null,
Scope.DISTRIBUTED_ACK);
assertRegionAttributes(accounts.getAttributes(), DataPolicy.REPLICATE, null, true,
false, null, Scope.DISTRIBUTED_NO_ACK);
}
@Test
@SuppressWarnings("unchecked")
public void entityServerRegionsDefined() {
applicationContext = newApplicationContext(ServerPersistentEntitiesConfiguration.class);
Region<Object, Object> accounts = applicationContext.getBean("Accounts", Region.class);
assertRegion(accounts, "Accounts");
assertRegionAttributes(accounts.getAttributes(), DataPolicy.REPLICATE, null, true,
false, null, Scope.DISTRIBUTED_ACK);
Region<Object, Object> customers = applicationContext.getBean("Customers", Region.class);
assertRegion(customers, "Customers");
assertRegionAttributes(customers.getAttributes(), DataPolicy.PERSISTENT_PARTITION, null, true, false, null,
Scope.DISTRIBUTED_NO_ACK);
assertPartitionAttributes(customers.getAttributes().getPartitionAttributes(), null, null, 1);
assertRegionAttributes(customers.getAttributes(), DataPolicy.PERSISTENT_PARTITION,
null, true, false, null, Scope.DISTRIBUTED_NO_ACK);
assertPartitionAttributes(customers.getAttributes().getPartitionAttributes(), null,
null, 1);
Region<Object, Object> localRegionEntity = applicationContext.getBean("LocalRegionEntity", Region.class);
@@ -261,11 +302,12 @@ public class EnableEntityDefinedRegionsConfigurationUnitTests {
assertRegionAttributes(localRegionEntity.getAttributes(), DataPolicy.NORMAL,
null, true, false, null, Scope.LOCAL);
Region<Object, Object> genericRegionEntity = applicationContext.getBean("GenericRegionEntity", Region.class);
Region<Object, Object> genericRegionEntity =
applicationContext.getBean("GenericRegionEntity", Region.class);
assertRegion(genericRegionEntity, "GenericRegionEntity");
assertRegionAttributes(genericRegionEntity.getAttributes(), DataPolicy.NORMAL, null, true, false, null,
Scope.DISTRIBUTED_NO_ACK);
assertRegionAttributes(genericRegionEntity.getAttributes(), DataPolicy.NORMAL,
null, true, false, null, Scope.DISTRIBUTED_NO_ACK);
assertThat(applicationContext.containsBean("CollocatedPartitionRegionEntity")).isFalse();
assertThat(applicationContext.containsBean("ContactEvents")).isFalse();
@@ -284,17 +326,15 @@ public class EnableEntityDefinedRegionsConfigurationUnitTests {
protected static <K, V> Cache mockCache() {
Cache mockCache = mock(Cache.class);
Answer<RegionFactory<K, V>> createRegionFactory = new Answer<RegionFactory<K, V>>() {
@Override @SuppressWarnings("unchecked")
public RegionFactory<K, V> answer(InvocationOnMock invocation) throws Throwable {
RegionAttributes<K, V> defaultRegionAttributes =
mockRegionAttributes(null, null, true, false, null, null, null, Scope.DISTRIBUTED_NO_ACK, null);
Answer<RegionFactory<K, V>> createRegionFactory = invocation -> {
RegionAttributes<K, V> defaultRegionAttributes = mockRegionAttributes(null,
null, true, false, null, null,
null, Scope.DISTRIBUTED_NO_ACK, null);
RegionAttributes<K, V> regionAttributes = (invocation.getArguments().length == 1
? invocation.getArgument(0) : defaultRegionAttributes);
return mockRegionFactory(regionAttributes);
}
return mockRegionFactory(mockCache, regionAttributes);
};
when(mockCache.createRegionFactory()).thenAnswer(createRegionFactory);
@@ -346,7 +386,7 @@ public class EnableEntityDefinedRegionsConfigurationUnitTests {
when(mockClientRegionFactory.setValueConstraint(any(Class.class))).thenAnswer(
newSetter(Class.class, valueConstraint, mockClientRegionFactory));
final RegionAttributes<K, V> mockRegionAttributes =
RegionAttributes<K, V> mockRegionAttributes =
mock(RegionAttributes.class, mockName("MockClientRegionAttributes"));
when(mockRegionAttributes.getDataPolicy()).thenReturn(
@@ -357,11 +397,17 @@ public class EnableEntityDefinedRegionsConfigurationUnitTests {
when(mockRegionAttributes.getPoolName()).thenAnswer(newGetter(poolName));
when(mockRegionAttributes.getValueConstraint()).thenAnswer(newGetter(valueConstraint));
when(mockClientRegionFactory.create(anyString())).thenAnswer(new Answer<Region<K, V>>() {
@Override
public Region<K, V> answer(InvocationOnMock invocation) throws Throwable {
return mockRegion(invocation.getArgument(0), mockRegionAttributes);
}
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<K, V> region = mockRegion(regionName, mockRegionAttributes);
cacheRegions.add(region);
return region;
});
return mockClientRegionFactory;
@@ -373,7 +419,8 @@ public class EnableEntityDefinedRegionsConfigurationUnitTests {
String diskStoreName, boolean diskSynchronous, boolean ignoreJta, Class<K> keyConstraint,
PartitionAttributes<K, V> partitionAttributes, String poolName, Scope scope, Class<V> valueConstraint) {
RegionAttributes<K, V> mockRegionAttributes = mock(RegionAttributes.class, mockName("MockRegionAttributes"));
RegionAttributes<K, V> mockRegionAttributes =
mock(RegionAttributes.class, mockName("MockRegionAttributes"));
when(mockRegionAttributes.getDataPolicy()).thenReturn(dataPolicy);
when(mockRegionAttributes.getDiskStoreName()).thenReturn(diskStoreName);
@@ -390,7 +437,9 @@ public class EnableEntityDefinedRegionsConfigurationUnitTests {
/* (non-Javadoc) */
@SuppressWarnings("unchecked")
protected static <K, V> RegionFactory<K, V> mockRegionFactory(RegionAttributes<K, V> regionAttributes) {
protected static <K, V> RegionFactory<K, V> mockRegionFactory(GemFireCache mockCache,
RegionAttributes<K, V> regionAttributes) {
RegionFactory<K, V> mockRegionFactory = mock(RegionFactory.class, mockName("MockRegionFactory"));
AtomicReference<DataPolicy> dataPolicy = new AtomicReference<>(regionAttributes.getDataPolicy());
@@ -398,8 +447,8 @@ public class EnableEntityDefinedRegionsConfigurationUnitTests {
AtomicReference<Boolean> diskSynchronous = new AtomicReference<>(regionAttributes.isDiskSynchronous());
AtomicReference<Boolean> ignoreJta = new AtomicReference<>(regionAttributes.getIgnoreJTA());
AtomicReference<Class> keyConstraint = new AtomicReference<>(null);
AtomicReference<PartitionAttributes> partitionAttributes = new AtomicReference<>(
regionAttributes.getPartitionAttributes());
AtomicReference<PartitionAttributes> partitionAttributes =
new AtomicReference<>(regionAttributes.getPartitionAttributes());
AtomicReference<Scope> scope = new AtomicReference<>(regionAttributes.getScope());
AtomicReference<Class> valueConstraint = new AtomicReference<>(null);
@@ -427,7 +476,7 @@ public class EnableEntityDefinedRegionsConfigurationUnitTests {
when(mockRegionFactory.setValueConstraint(any(Class.class))).thenAnswer(
newSetter(Class.class, valueConstraint, mockRegionFactory));
final RegionAttributes<K, V> mockRegionAttributes =
RegionAttributes<K, V> mockRegionAttributes =
mock(RegionAttributes.class, mockName("MockRegionAttributes"));
when(mockRegionAttributes.getDataPolicy()).thenAnswer(newGetter(dataPolicy));
@@ -439,11 +488,20 @@ public class EnableEntityDefinedRegionsConfigurationUnitTests {
when(mockRegionAttributes.getScope()).thenAnswer(newGetter(scope));
when(mockRegionAttributes.getValueConstraint()).thenAnswer(newGetter(valueConstraint));
when(mockRegionFactory.create(anyString())).thenAnswer(new Answer<Region<K, V>>() {
@Override
public Region<K, V> answer(InvocationOnMock invocation) throws Throwable {
return mockRegion(invocation.getArgument(0), mockRegionAttributes);
}
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<K, V> mockRegion = mockRegion(regionName, mockRegionAttributes);
cacheRegions.add(mockRegion);
when(mockCache.getRegion(eq(regionName))).thenReturn((Region<Object, Object>) mockRegion);
when(mockRegion.getRegionService()).thenReturn(mockCache);
return mockRegion;
});
return mockRegionFactory;
@@ -455,7 +513,7 @@ public class EnableEntityDefinedRegionsConfigurationUnitTests {
Region<K, V> mockRegion = mock(Region.class, mockName(name));
when(mockRegion.getName()).thenReturn(name);
when(mockRegion.getFullPath()).thenReturn(String.format("%1$s%2$s", Region.SEPARATOR, name));
when(mockRegion.getFullPath()).thenReturn(toRegionPath(name));
when(mockRegion.getAttributes()).thenReturn(regionAttributes);
return mockRegion;
@@ -495,24 +553,17 @@ public class EnableEntityDefinedRegionsConfigurationUnitTests {
}
}
@EnableEntityDefinedRegions(basePackageClasses = NonEntity.class,
excludeFilters = { @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = ClientRegion.class),
@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = CollocatedPartitionRegionEntity.class) })
@SuppressWarnings("all")
static class AllServerPersistentEntitiesConfiguration extends ServerCacheConfiguration {
}
@EnableEntityDefinedRegions(basePackageClasses = NonEntity.class, strict = true,
excludeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION,
classes = { LocalRegion.class, PartitionRegion.class, ReplicateRegion.class }))
@SuppressWarnings("all")
static class ClientPersistentEntitiesConfiguration extends ClientCacheConfiguration {
}
@SuppressWarnings("all")
@EnableEntityDefinedRegions(basePackageClasses = NonEntity.class,
excludeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION,
classes = { ClientRegion.class, LocalRegion.class, ReplicateRegion.class }))
@SuppressWarnings("all")
static class PeerPartitionRegionPersistentEntitiesConfiguration extends ServerCacheConfiguration {
@Bean @Lazy
@@ -525,4 +576,58 @@ public class EnableEntityDefinedRegionsConfigurationUnitTests {
return mock(PartitionResolver.class, mockName("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 {
}
@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 {
@Bean
@SuppressWarnings("unused")
PartitionedRegionFactoryBean<Long, PartitionRegionEntity> customersRegion(GemFireCache gemfireCache) {
PartitionedRegionFactoryBean<Long, PartitionRegionEntity> customers = new PartitionedRegionFactoryBean<>();
customers.setCache(gemfireCache);
customers.setClose(false);
customers.setPersistent(false);
customers.setRegionName("Customers");
return customers;
}
}
@SuppressWarnings("all")
@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 {
@Bean
@SuppressWarnings("unused")
ReplicatedRegionFactoryBean<Long, ReplicateRegionEntity> accountsRegion(GemFireCache gemfireCache) {
ReplicatedRegionFactoryBean<Long, ReplicateRegionEntity> accounts = new ReplicatedRegionFactoryBean<>();
accounts.setCache(gemfireCache);
accounts.setClose(false);
accounts.setLookupEnabled(true);
accounts.setPersistent(false);
accounts.setRegionName("Accounts");
accounts.setScope(Scope.DISTRIBUTED_NO_ACK);
return accounts;
}
}
}

View File

@@ -184,8 +184,8 @@ public class EnableIndexesConfigurationUnitTests {
doAnswer(invocation -> {
LuceneIndex mockLuceneIndex = mock(LuceneIndex.class);
String indexName = invocation.getArgumentAt(0, String.class);
String regionPath = invocation.getArgumentAt(1, String.class);
String indexName = invocation.getArgument(0);
String regionPath = invocation.getArgument(1);
when(mockLuceneIndex.getName()).thenReturn(indexName);
when(mockLuceneIndex.getRegionPath()).thenReturn(regionPath);

View File

@@ -30,7 +30,7 @@ import org.springframework.data.gemfire.mapping.annotation.PartitionRegion;
* @author John Blum
* @since 1.9.0
*/
@PartitionRegion(name = "Customers", persistent = true, redundantCopies = 1,
@PartitionRegion(name = "Customers", ignoreIfExists = false, persistent = true, redundantCopies = 1,
fixedPartitions = {
@PartitionRegion.FixedPartition(name = "one", primary = true, numBuckets = 16),
@PartitionRegion.FixedPartition(name = "two", numBuckets = 21)