/*
* Copyright 2016 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.config.annotation;
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;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.regex.Pattern;
import org.apache.geode.cache.Region;
import org.apache.geode.cache.client.ClientRegionShortcut;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.ManagedList;
import org.springframework.context.annotation.FilterType;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.core.type.filter.AspectJTypeFilter;
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.GemFireCacheTypeAwareRegionFactoryBean;
import org.springframework.data.gemfire.config.annotation.support.GemFireComponentClassTypeScanner;
import org.springframework.data.gemfire.config.xml.GemfireConstants;
import org.springframework.data.gemfire.mapping.GemfireMappingContext;
import org.springframework.data.gemfire.mapping.GemfirePersistentEntity;
import org.springframework.data.gemfire.mapping.GemfirePersistentProperty;
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;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
/**
* The {@link EntityDefinedRegionsConfiguration} class is Spring {@link ImportBeanDefinitionRegistrar} used in
* the {@link EnableEntityDefinedRegions} annotation to dynamically create GemFire/Geode {@link Region Regions}
* 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
* @see org.springframework.beans.factory.config.BeanDefinition
* @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 org.springframework.data.gemfire.mapping.GemfireMappingContext
* @see org.springframework.data.gemfire.mapping.GemfirePersistentEntity
* @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
implements BeanClassLoaderAware, BeanFactoryAware, ImportBeanDefinitionRegistrar {
protected static final Class<? extends RegionLookupFactoryBean> DEFAULT_REGION_FACTORY_BEAN_CLASS =
GemFireCacheTypeAwareRegionFactoryBean.class;
protected static final Map<Class<? extends Annotation>, Class<? extends RegionLookupFactoryBean>> 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);
}
private BeanFactory beanFactory;
private ClassLoader beanClassLoader;
private GemfireMappingContext mappingContext;
/**
* Returns the {@link Annotation} {@link Class type} that configures and creates {@link Region Regions}
* for application persistent entities.
*
* @return the {@link Annotation} {@link Class type} that configures and creates {@link Region Regions}
* for application persistent entities.
* @see org.springframework.data.gemfire.config.annotation.EnableEntityDefinedRegions
* @see java.lang.annotation.Annotation
* @see java.lang.Class
*/
protected Class<? extends Annotation> getAnnotationType() {
return EnableEntityDefinedRegions.class;
}
/**
* Returns the name of the {@link Annotation} type that configures and creates {@link Region Regions}
* for application persistent entities.
*
* @return the name of the {@link Annotation} type that configures and creates {@link Region Regions}
* for application persistent entities.
* @see java.lang.Class#getName()
* @see #getAnnotationType()
*/
protected String getAnnotationTypeName() {
return getAnnotationType().getName();
}
/**
* Returns the simple name of the {@link Annotation} type that configures and creates {@link Region Regions}
* for application persistent entities.
*
* @return the simple name of the {@link Annotation} type that configures and creates {@link Region Regions}
* for application persistent entities.
* @see java.lang.Class#getSimpleName()
* @see #getAnnotationType()
*/
@SuppressWarnings("unused")
protected String getAnnotationTypeSimpleName() {
return getAnnotationType().getSimpleName();
}
/**
* @inheritDoc
*/
@Override
public void setBeanClassLoader(ClassLoader classLoader) {
this.beanClassLoader = classLoader;
}
/* (non-Javadoc) */
@SuppressWarnings("unused")
protected ClassLoader getBeanClassLoader() {
return this.beanClassLoader;
}
/**
* @inheritDoc
*/
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
}
/* (non-Javadoc) */
protected BeanFactory getBeanFactory() {
return this.beanFactory;
}
/* (non-Javadoc) */
protected boolean isAnnotationPresent(AnnotationMetadata importingClassMetadata) {
return isAnnotationPresent(importingClassMetadata, getAnnotationTypeName());
}
/* (non-Javadoc) */
protected boolean isAnnotationPresent(AnnotationMetadata importingClassMetadata, String annotationName) {
return importingClassMetadata.hasAnnotation(annotationName);
}
/* (non-Javadoc) */
protected AnnotationAttributes getAnnotationAttributes(Annotation annotation) {
return AnnotationAttributes.fromMap(AnnotationUtils.getAnnotationAttributes(annotation));
}
/* (non-Javadoc) */
protected AnnotationAttributes getAnnotationAttributes(AnnotationMetadata importingClassMetadata) {
return getAnnotationAttributes(importingClassMetadata, getAnnotationTypeName());
}
/* (non-Javadoc) */
protected AnnotationAttributes getAnnotationAttributes(AnnotationMetadata importingClassMetadata,
String annotationName) {
return AnnotationAttributes.fromMap(importingClassMetadata.getAnnotationAttributes(annotationName));
}
/* (non-Javadoc) */
protected GemfirePersistentEntity<?> getPersistentEntity(Class<?> persistentEntityType) {
return resolveMappingContext().getPersistentEntity(persistentEntityType).orElseThrow(
() -> new IllegalStateException(String.format("PersistentEntity for type [%s] not found",
persistentEntityType)));
}
/* (non-Javadoc) */
protected GemfireMappingContext resolveMappingContext() {
return Optional.ofNullable(this.mappingContext).orElseGet(() -> {
try {
this.mappingContext = getBeanFactory().getBean(GemfireMappingContext.class);
}
catch (Throwable ignore) {
this.mappingContext = new GemfireMappingContext();
}
return this.mappingContext;
});
}
/**
* @inheritDoc
*/
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
if (isAnnotationPresent(importingClassMetadata)) {
AnnotationAttributes enableEntityDefinedRegionsAttributes = getAnnotationAttributes(importingClassMetadata);
boolean strict = enableEntityDefinedRegionsAttributes.getBoolean("strict");
for (Class<?> persistentEntityClass : newGemFireComponentClassTypeScanner(
importingClassMetadata, enableEntityDefinedRegionsAttributes).scan()) {
GemfirePersistentEntity persistentEntity = getPersistentEntity(persistentEntityClass);
registerRegionBeanDefinition(persistentEntity, strict, registry);
postProcess(importingClassMetadata, registry, persistentEntity);
}
}
}
/* (non-Javadoc) */
protected GemFireComponentClassTypeScanner newGemFireComponentClassTypeScanner(
AnnotationMetadata importingClassMetadata, AnnotationAttributes enableEntityDefinedRegionsAttributes) {
Set<String> resolvedBasePackages = resolveBasePackages(importingClassMetadata,
enableEntityDefinedRegionsAttributes);
return GemFireComponentClassTypeScanner.from(resolvedBasePackages).with(resolveBeanClassLoader())
.withExcludes(resolveExcludes(enableEntityDefinedRegionsAttributes))
.withIncludes(resolveIncludes(enableEntityDefinedRegionsAttributes))
.withIncludes(regionAnnotatedPersistentEntityTypeFilters());
}
/* (non-Javadoc) */
protected Set<String> resolveBasePackages(AnnotationMetadata importingClassMetaData,
AnnotationAttributes enableEntityDefinedRegionAttributes) {
Set<String> resolvedBasePackages = new HashSet<>();
Collections.addAll(resolvedBasePackages, nullSafeArray(defaultIfEmpty(
enableEntityDefinedRegionAttributes.getStringArray("basePackages"),
enableEntityDefinedRegionAttributes.getStringArray("value")),
String.class));
stream(nullSafeArray(enableEntityDefinedRegionAttributes.getClassArray(
"basePackageClasses"), Class.class))
.forEach(type -> resolvedBasePackages.add(type.getPackage().getName()));
if (resolvedBasePackages.isEmpty()) {
resolvedBasePackages.add(ClassUtils.getPackageName(importingClassMetaData.getClassName()));
}
return resolvedBasePackages;
}
/* (non-Javadoc) */
protected ClassLoader resolveBeanClassLoader() {
return Optional.ofNullable(this.beanClassLoader)
.orElseGet(() -> Thread.currentThread().getContextClassLoader());
}
/* (non-Javadoc) */
protected Iterable<TypeFilter> resolveExcludes(AnnotationAttributes enableEntityDefinedRegionsAttributes) {
return parseFilters(enableEntityDefinedRegionsAttributes.getAnnotationArray("excludeFilters"));
}
/* (non-Javadoc) */
protected Iterable<TypeFilter> resolveIncludes(AnnotationAttributes enableEntityDefinedRegionsAttributes) {
return parseFilters(enableEntityDefinedRegionsAttributes.getAnnotationArray("includeFilters"));
}
/* (non-Javadoc) */
private Iterable<TypeFilter> parseFilters(AnnotationAttributes[] componentScanFilterAttributes) {
Set<TypeFilter> typeFilters = new HashSet<>();
stream(nullSafeArray(componentScanFilterAttributes, AnnotationAttributes.class))
.forEach(filterAttributes -> CollectionUtils.addAll(typeFilters, typeFiltersFor(filterAttributes)));
return typeFilters;
}
/* (non-Javadoc) */
@SuppressWarnings("unchecked")
private Iterable<TypeFilter> typeFiltersFor(AnnotationAttributes filterAttributes) {
Set<TypeFilter> typeFilters = new HashSet<>();
FilterType filterType = filterAttributes.getEnum("type");
for (Class<?> filterClass : nullSafeArray(filterAttributes.getClassArray("value"), Class.class)) {
switch (filterType) {
case ANNOTATION:
Assert.isAssignable(Annotation.class, filterClass,
String.format("@ComponentScan.Filter class [%s] must be an Annotation", filterClass));
typeFilters.add(new AnnotationTypeFilter((Class<Annotation>) filterClass));
break;
case ASSIGNABLE_TYPE:
typeFilters.add(new AssignableTypeFilter(filterClass));
break;
case CUSTOM:
Assert.isAssignable(TypeFilter.class, filterClass,
String.format("@ComponentScan.Filter class [%s] must be a TypeFilter", filterClass));
typeFilters.add(BeanUtils.instantiateClass(filterClass, TypeFilter.class));
break;
default:
throw new IllegalArgumentException(String.format(
"Illegal filter type [%s] when 'value' or 'classes' are specified", filterType));
}
for (String pattern : nullSafeGetPatterns(filterAttributes)) {
switch (filterType) {
case ASPECTJ:
typeFilters.add(new AspectJTypeFilter(pattern, resolveBeanClassLoader()));
break;
case REGEX:
typeFilters.add(new RegexPatternTypeFilter(Pattern.compile(pattern)));
break;
default:
throw new IllegalArgumentException(String.format(
"Illegal filter type [%s] when 'patterns' are specified", filterType));
}
}
}
return typeFilters;
}
/**
* Safely reads the {@code pattern} attribute from the given {@link AnnotationAttributes}
* and returns an empty array if the attribute is not present.
*
* @param filterAttributes {@link AnnotationAttributes} from which to extract the {@code pattern} attribute value.
* @return a {@link String} array.
*/
private String[] nullSafeGetPatterns(AnnotationAttributes filterAttributes) {
try {
return nullSafeArray(filterAttributes.getStringArray("pattern"), String.class);
}
catch (IllegalArgumentException ignore) {
return new String[0];
}
}
/* (non-Javadoc) */
@SuppressWarnings("unchecked")
protected Iterable<TypeFilter> regionAnnotatedPersistentEntityTypeFilters() {
Set<TypeFilter> regionAnnotatedPersistentEntityTypeFilters = new HashSet<>();
org.springframework.data.gemfire.mapping.annotation.Region.REGION_ANNOTATION_TYPES.forEach(
annotationType -> regionAnnotatedPersistentEntityTypeFilters.add(new AnnotationTypeFilter(annotationType)));
return regionAnnotatedPersistentEntityTypeFilters;
}
/* (non-Javadoc) */
protected void registerRegionBeanDefinition(GemfirePersistentEntity persistentEntity, boolean strict,
BeanDefinitionRegistry registry) {
BeanDefinitionBuilder regionFactoryBeanBuilder =
BeanDefinitionBuilder.genericBeanDefinition(resolveRegionFactoryBeanClass(persistentEntity))
.addPropertyReference("cache", GemfireConstants.DEFAULT_GEMFIRE_CACHE_NAME)
.addPropertyValue("close", false);
setRegionAttributes(persistentEntity, regionFactoryBeanBuilder, strict);
registry.registerBeanDefinition(persistentEntity.getRegionName(),
regionFactoryBeanBuilder.getBeanDefinition());
}
/* (non-Javadoc) */
@SuppressWarnings("unchecked")
protected Class<? extends RegionLookupFactoryBean> resolveRegionFactoryBeanClass(
GemfirePersistentEntity persistentEntity) {
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) {
Optional.ofNullable(persistentEntity.getRegionAnnotation()).ifPresent(regionAnnotation -> {
AnnotationAttributes regionAnnotationAttributes = getAnnotationAttributes(regionAnnotation);
if (strict) {
regionFactoryBeanBuilder.addPropertyValue("keyConstraint", resolveIdType(persistentEntity));
regionFactoryBeanBuilder.addPropertyValue("valueConstraint", resolveDomainType(persistentEntity));
}
if (regionAnnotationAttributes.containsKey("diskStoreName")) {
String diskStoreName = regionAnnotationAttributes.getString("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);
}
BeanDefinitionBuilder regionAttributesFactoryBeanBuilder =
resolveRegionAttributesFactoryBeanBuilder(regionAnnotation, regionFactoryBeanBuilder);
if (regionAnnotationAttributes.containsKey("diskSynchronous")) {
setPropertyValueIfNotDefault(regionAttributesFactoryBeanBuilder, "diskSynchronous",
regionAnnotationAttributes.getBoolean("diskSynchronous"), true);
}
if (regionAnnotationAttributes.containsKey("ignoreJta")) {
setPropertyValueIfNotDefault(regionAttributesFactoryBeanBuilder, "ignoreJTA",
regionAnnotationAttributes.getBoolean("ignoreJta"), false);
}
setClientRegionAttributes(regionAnnotationAttributes, regionFactoryBeanBuilder);
setPartitionRegionAttributes(regionAnnotationAttributes, regionFactoryBeanBuilder,
regionAttributesFactoryBeanBuilder);
setReplicateRegionAttributes(regionAnnotationAttributes, regionFactoryBeanBuilder);
});
return regionFactoryBeanBuilder;
}
/* (non-Javadoc) */
protected Class<?> resolveDomainType(GemfirePersistentEntity persistentEntity) {
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())
.orElse(Object.class);
}
/* (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,
BeanDefinitionBuilder regionFactoryBeanBuilder) {
if (regionAnnotationAttributes.containsKey("poolName")) {
setPropertyValueIfNotDefault(regionFactoryBeanBuilder, "poolName",
regionAnnotationAttributes.getString("poolName"), null);
}
if (regionAnnotationAttributes.containsKey("shortcut")) {
setPropertyValueIfNotDefault(regionFactoryBeanBuilder, "shortcut",
regionAnnotationAttributes.getEnum("shortcut"), ClientRegionShortcut.PROXY);
}
return regionFactoryBeanBuilder;
}
/* (non-Javadoc) */
protected BeanDefinitionBuilder setPartitionRegionAttributes(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, "");
if (StringUtils.hasText(collocatedWith)) {
regionFactoryBeanBuilder.addDependsOn(collocatedWith);
}
setPropertyReferenceIfSet(partitionAttributesFactoryBeanBuilder, "partitionResolver",
regionAnnotationAttributes.getString("partitionResolverName"));
setPropertyValueIfNotDefault(partitionAttributesFactoryBeanBuilder, "redundantCopies",
regionAnnotationAttributes.<Integer>getNumber("redundantCopies"), 0);
setFixedPartitionRegionAttributes(regionAnnotationAttributes, partitionAttributesFactoryBeanBuilder);
regionAttributesFactoryBeanBuilder.addPropertyValue("partitionAttributes",
partitionAttributesFactoryBeanBuilder.getBeanDefinition());
}
return regionAttributesFactoryBeanBuilder;
}
/* (non-Javadoc) */
protected BeanDefinitionBuilder setFixedPartitionRegionAttributes(AnnotationAttributes regionAnnotationAttributes,
BeanDefinitionBuilder partitionAttributesFactoryBeanBuilder) {
PartitionRegion.FixedPartition[] fixedPartitions = nullSafeArray(regionAnnotationAttributes.getAnnotationArray(
"fixedPartitions", PartitionRegion.FixedPartition.class), PartitionRegion.FixedPartition.class);
if (!ObjectUtils.isEmpty(fixedPartitions)) {
ManagedList<BeanDefinition> fixedPartitionAttributesFactoryBeans =
new ManagedList<BeanDefinition>(fixedPartitions.length);
for (PartitionRegion.FixedPartition fixedPartition : fixedPartitions) {
BeanDefinitionBuilder fixedPartitionAttributesFactoryBeanBuilder =
BeanDefinitionBuilder.genericBeanDefinition(FixedPartitionAttributesFactoryBean.class);
fixedPartitionAttributesFactoryBeanBuilder.addPropertyValue("partitionName", fixedPartition.name());
setPropertyValueIfNotDefault(fixedPartitionAttributesFactoryBeanBuilder, "primary",
fixedPartition.primary(), false);
setPropertyValueIfNotDefault(fixedPartitionAttributesFactoryBeanBuilder, "numBuckets",
fixedPartition.numBuckets(), 1);
fixedPartitionAttributesFactoryBeans.add(
fixedPartitionAttributesFactoryBeanBuilder.getBeanDefinition());
}
partitionAttributesFactoryBeanBuilder.addPropertyValue("fixedPartitionAttributes",
fixedPartitionAttributesFactoryBeans);
}
return partitionAttributesFactoryBeanBuilder;
}
/* (non-Javadoc) */
protected BeanDefinitionBuilder setReplicateRegionAttributes(AnnotationAttributes regionAnnotationAttributes,
BeanDefinitionBuilder regionFactoryBeanBuilder) {
if (regionAnnotationAttributes.containsKey("scope")) {
setPropertyValueIfNotDefault(regionFactoryBeanBuilder, "scope",
regionAnnotationAttributes.<ScopeType>getEnum("scope").getScope(),
ScopeType.DISTRIBUTED_NO_ACK);
}
return regionFactoryBeanBuilder;
}
/* (non-Javadoc) */
private <T> BeanDefinitionBuilder setPropertyReferenceIfSet(BeanDefinitionBuilder beanDefinitionBuilder,
String propertyName, String beanName) {
return (StringUtils.hasText(beanName)
? beanDefinitionBuilder.addPropertyReference(propertyName, beanName)
: beanDefinitionBuilder);
}
/* (non-Javadoc) */
private <T> BeanDefinitionBuilder setPropertyValueIfNotDefault(BeanDefinitionBuilder beanDefinitionBuilder,
String propertyName, T value, T defaultValue) {
return (value != null && !value.equals(defaultValue)
? beanDefinitionBuilder.addPropertyValue(propertyName, value)
: beanDefinitionBuilder);
}
/**
* Performs addition post processing on the {@link GemfirePersistentEntity} to offer additional feature support
* (e.g. dynamic Index creation).
*
* @param importingClassMetadata {@link AnnotationMetadata} for the importing application class.
* @param registry {@link BeanDefinitionRegistry} used to register Spring bean definitions.
* @param persistentEntity {@link GemfirePersistentEntity} to process.
* @return the given {@link GemfirePersistentEntity}.
* @see org.springframework.beans.factory.support.BeanDefinitionRegistry
* @see org.springframework.core.type.AnnotationMetadata
* @see org.springframework.data.gemfire.mapping.GemfirePersistentEntity
*/
protected GemfirePersistentEntity<?> postProcess(AnnotationMetadata importingClassMetadata,
BeanDefinitionRegistry registry, GemfirePersistentEntity<?> persistentEntity) {
return persistentEntity;
}
}