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) */