SGF-688 - Add support for configuring client and server Region data management policies in Entity-defined Regions.

This commit is contained in:
John Blum
2017-11-20 13:40:23 -08:00
parent ffbc9dcf5d
commit 83d4209086
22 changed files with 1882 additions and 622 deletions

View File

@@ -16,6 +16,8 @@
package org.springframework.data.gemfire;
import static org.springframework.data.gemfire.util.CollectionUtils.nullSafeList;
import java.util.List;
import org.apache.geode.cache.FixedPartitionAttributes;
@@ -25,7 +27,7 @@ import org.apache.geode.cache.PartitionResolver;
import org.apache.geode.cache.partition.PartitionListener;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.data.gemfire.util.CollectionUtils;
import org.springframework.data.gemfire.support.AbstractFactoryBeanSupport;
/**
* Spring {@link FactoryBean} for creating {@link PartitionAttributes}.
@@ -35,101 +37,81 @@ import org.springframework.data.gemfire.util.CollectionUtils;
* @author Costin Leau
* @author David Turanski
* @author John Blum
* @see org.springframework.beans.factory.FactoryBean
* @see org.springframework.beans.factory.InitializingBean
* @see org.apache.geode.cache.FixedPartitionAttributes
* @see org.apache.geode.cache.PartitionAttributes
* @see org.apache.geode.cache.PartitionAttributesFactory
* @see org.apache.geode.cache.PartitionResolver
* @see org.apache.geode.cache.partition.PartitionListener
* @see org.springframework.beans.factory.FactoryBean
* @see org.springframework.beans.factory.InitializingBean
* @see org.springframework.data.gemfire.support.AbstractFactoryBeanSupport
*/
@SuppressWarnings({ "rawtypes", "unchecked", "unused" })
public class PartitionAttributesFactoryBean<K, V> implements FactoryBean<PartitionAttributes<K, V>>, InitializingBean {
@SuppressWarnings("unused")
public class PartitionAttributesFactoryBean<K, V> extends AbstractFactoryBeanSupport<PartitionAttributes<K, V>>
implements InitializingBean {
private List<PartitionListener> partitionListeners;
private PartitionAttributes<K, V> partitionAttributes;
private final PartitionAttributesFactory<K, V> partitionAttributesFactory =
new PartitionAttributesFactory<>();
private final PartitionAttributesFactory<K, V> partitionAttributesFactory = new PartitionAttributesFactory<>();
/**
* @inheritDoc
*/
@Override
public void afterPropertiesSet() throws Exception {
for (PartitionListener listener : CollectionUtils.nullSafeList(partitionListeners)) {
partitionAttributesFactory.addPartitionListener(listener);
}
nullSafeList(partitionListeners).forEach(partitionAttributesFactory::addPartitionListener);
this.partitionAttributes = partitionAttributesFactory.create();
}
/**
* @inheritDoc
*/
@Override
public PartitionAttributes getObject() throws Exception {
public PartitionAttributes<K, V> getObject() throws Exception {
return this.partitionAttributes;
}
/**
* @inheritDoc
*/
@Override
public Class<?> getObjectType() {
return (this.partitionAttributes != null ? this.partitionAttributes.getClass() : PartitionAttributes.class);
}
/**
* @inheritDoc
*/
@Override
public boolean isSingleton() {
return false;
}
public void setColocatedWith(String collocatedWith) {
partitionAttributesFactory.setColocatedWith(collocatedWith);
this.partitionAttributesFactory.setColocatedWith(collocatedWith);
}
public void setFixedPartitionAttributes(List<FixedPartitionAttributes> fixedPartitionAttributes) {
for (FixedPartitionAttributes fixedPartitionAttributesElement :
CollectionUtils.nullSafeList(fixedPartitionAttributes)) {
partitionAttributesFactory.addFixedPartitionAttributes(fixedPartitionAttributesElement);
}
nullSafeList(fixedPartitionAttributes).forEach(this.partitionAttributesFactory::addFixedPartitionAttributes);
}
public void setLocalMaxMemory(int mb) {
partitionAttributesFactory.setLocalMaxMemory(mb);
this.partitionAttributesFactory.setLocalMaxMemory(mb);
}
public void setPartitionListeners(List<PartitionListener> partitionListeners) {
this.partitionListeners = partitionListeners;
}
public void setPartitionResolver(PartitionResolver resolver) {
partitionAttributesFactory.setPartitionResolver(resolver);
public void setPartitionResolver(PartitionResolver<K, V> resolver) {
this.partitionAttributesFactory.setPartitionResolver(resolver);
}
public void setRecoveryDelay(long recoveryDelay) {
partitionAttributesFactory.setRecoveryDelay(recoveryDelay);
this.partitionAttributesFactory.setRecoveryDelay(recoveryDelay);
}
public void setRedundantCopies(int redundantCopies) {
partitionAttributesFactory.setRedundantCopies(redundantCopies);
this.partitionAttributesFactory.setRedundantCopies(redundantCopies);
}
public void setStartupRecoveryDelay(long startupRecoveryDelay) {
partitionAttributesFactory.setStartupRecoveryDelay(startupRecoveryDelay);
this.partitionAttributesFactory.setStartupRecoveryDelay(startupRecoveryDelay);
}
public void setTotalMaxMemory(long mb) {
partitionAttributesFactory.setTotalMaxMemory(mb);
public void setTotalMaxMemory(long megabytes) {
this.partitionAttributesFactory.setTotalMaxMemory(megabytes);
}
public void setTotalNumBuckets(int numBuckets) {
partitionAttributesFactory.setTotalNumBuckets(numBuckets);
this.partitionAttributesFactory.setTotalNumBuckets(numBuckets);
}
}

View File

@@ -35,35 +35,23 @@ import org.springframework.beans.factory.InitializingBean;
public class RegionAttributesFactoryBean extends AttributesFactory
implements FactoryBean<RegionAttributes>, InitializingBean {
private RegionAttributes attributes;
private RegionAttributes regionAttributes;
/**
* @inheritDoc
*/
@Override
public void afterPropertiesSet() throws Exception {
attributes = super.create();
this.regionAttributes = super.create();
}
/**
* @inheritDoc
*/
@Override
public RegionAttributes getObject() throws Exception {
return attributes;
return this.regionAttributes;
}
/**
* @inheritDoc
*/
@Override
public Class<?> getObjectType() {
return (attributes != null ? attributes.getClass() : RegionAttributes.class);
return this.regionAttributes != null ? this.regionAttributes.getClass() : RegionAttributes.class;
}
/**
* @inheritDoc
*/
@Override
public boolean isSingleton() {
return true;

View File

@@ -23,7 +23,6 @@ import static org.springframework.data.gemfire.util.CollectionUtils.nullSafeIter
import static org.springframework.data.gemfire.util.RuntimeExceptionFactory.newIllegalArgumentException;
import static org.springframework.data.gemfire.util.RuntimeExceptionFactory.newIllegalStateException;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@@ -277,10 +276,11 @@ public abstract class RegionFactoryBean<K, V> extends RegionLookupFactoryBean<K,
protected RegionFactory<K, V> createRegionFactory(Cache cache) {
if (this.shortcut != null) {
RegionFactory<K, V> regionFactory =
mergeRegionAttributes(cache.createRegionFactory(this.shortcut), this.attributes);
setDataPolicy(getDataPolicy(regionFactory));
setDataPolicy(getDataPolicy(regionFactory, this.shortcut));
return regionFactory;
}
@@ -310,7 +310,7 @@ public abstract class RegionFactoryBean<K, V> extends RegionLookupFactoryBean<K,
Optional.ofNullable(this.cacheWriter).ifPresent(regionFactory::setCacheWriter);
resolveDataPolicy(regionFactory, persistent, dataPolicy);
resolveDataPolicy(regionFactory, this.persistent, this.dataPolicy);
Optional.ofNullable(this.diskStoreName)
.filter(name -> isDiskStoreConfigurationAllowed())
@@ -323,7 +323,7 @@ public abstract class RegionFactoryBean<K, V> extends RegionLookupFactoryBean<K,
Optional.ofNullable(this.keyConstraint).ifPresent(regionFactory::setKeyConstraint);
Optional.ofNullable(this.scope).ifPresent(regionFactory::setScope);
Optional.ofNullable(getScope()).ifPresent(regionFactory::setScope);
Optional.ofNullable(this.valueConstraint).ifPresent(regionFactory::setValueConstraint);
@@ -375,17 +375,26 @@ public abstract class RegionFactoryBean<K, V> extends RegionLookupFactoryBean<K,
* @see org.apache.geode.cache.DataPolicy
*/
@SuppressWarnings({ "deprecation", "unchecked" })
DataPolicy getDataPolicy(RegionFactory regionFactory) {
return ((RegionAttributes) getFieldValue(getFieldValue(regionFactory, "attrsFactory",
AttributesFactory.class), "regionAttributes", null)).getDataPolicy();
DataPolicy getDataPolicy(RegionFactory regionFactory, RegionShortcut regionShortcut) {
return getFieldValue(regionFactory, "attrsFactory", AttributesFactory.class)
.flatMap(attributesFactory -> getFieldValue(attributesFactory,"regionAttributes", null))
.map(regionAttributes -> ((RegionAttributes<K, V>) regionAttributes).getDataPolicy())
.orElseGet(() -> RegionShortcutToDataPolicyConverter.INSTANCE.convert(regionShortcut));
}
/* (non-Javadoc) */
@SuppressWarnings("unchecked")
private <T> T getFieldValue(Object source, String fieldName, Class<T> targetType) {
Field field = ReflectionUtils.findField(source.getClass(), fieldName, targetType);
ReflectionUtils.makeAccessible(field);
return (T) ReflectionUtils.getField(field, source);
private <T> Optional<T> getFieldValue(Object source, String fieldName, Class<T> targetType) {
return Optional.ofNullable(source)
.map(Object::getClass)
.map(type -> ReflectionUtils.findField(type, fieldName, targetType))
.map(field -> {
ReflectionUtils.makeAccessible(field);
return field;
})
.map(field -> (T) ReflectionUtils.getField(field, source));
}
/**
@@ -412,8 +421,8 @@ public abstract class RegionFactoryBean<K, V> extends RegionLookupFactoryBean<K,
RegionAttributes<K, V> regionAttributes) {
if (regionAttributes != null) {
// NOTE this validation may not be strictly required depending on how the RegionAttributes were "created",
// but...
// NOTE: this validation may not be strictly necessary depending on how the RegionAttributes were "created",
validateRegionAttributes(regionAttributes);
regionFactory.setCloningEnabled(regionAttributes.getCloningEnabled());
@@ -428,7 +437,7 @@ public abstract class RegionFactoryBean<K, V> extends RegionLookupFactoryBean<K,
regionFactory.setEntryIdleTimeout(regionAttributes.getEntryIdleTimeout());
regionFactory.setEntryTimeToLive(regionAttributes.getEntryTimeToLive());
// NOTE EvictionAttributes are created by certain RegionShortcuts; need the null check!
// NOTE: EvictionAttributes are created by certain RegionShortcuts; need the null check!
if (isUserSpecifiedEvictionAttributes(regionAttributes)) {
regionFactory.setEvictionAttributes(regionAttributes.getEvictionAttributes());
}
@@ -464,9 +473,9 @@ public abstract class RegionFactoryBean<K, V> extends RegionLookupFactoryBean<K,
protected <K, V> void mergePartitionAttributes(RegionFactory<K, V> regionFactory,
RegionAttributes<K, V> regionAttributes) {
// NOTE PartitionAttributes are created by certain RegionShortcuts; need the null check since RegionAttributes
// NOTE: PartitionAttributes are created by certain RegionShortcuts; need the null check since RegionAttributes
// can technically return null!
// NOTE most likely, the PartitionAttributes will never be null since the PartitionRegionFactoryBean always
// NOTE: most likely, the PartitionAttributes will never be null since the PartitionRegionFactoryBean always
// sets a PartitionAttributesFactoryBean BeanBuilder on the RegionAttributesFactoryBean "partitionAttributes"
// property.
if (regionAttributes.getPartitionAttributes() != null) {
@@ -582,12 +591,12 @@ public abstract class RegionFactoryBean<K, V> extends RegionLookupFactoryBean<K,
if (resolvedDataPolicy.withPersistence()) {
Assert.isTrue(isPersistentUnspecified() || isPersistent(), String.format(
"Data Policy [%1$s] is invalid when persistent is false.", resolvedDataPolicy));
"Data Policy [%s] is invalid when persistent is false.", resolvedDataPolicy));
}
else {
// NOTE otherwise, the Data Policy is not persistent, so...
Assert.isTrue(isPersistentUnspecified() || isNotPersistent(), String.format(
"Data Policy [%1$s] is invalid when persistent is true.", resolvedDataPolicy));
"Data Policy [%s] is invalid when persistent is true.", resolvedDataPolicy));
}
}
@@ -630,15 +639,17 @@ public abstract class RegionFactoryBean<K, V> extends RegionLookupFactoryBean<K,
protected void resolveDataPolicy(RegionFactory<K, V> regionFactory, Boolean persistent, String dataPolicy) {
if (dataPolicy != null) {
DataPolicy resolvedDataPolicy = new DataPolicyConverter().convert(dataPolicy);
Assert.notNull(resolvedDataPolicy, String.format("Data Policy [%1$s] is invalid.", dataPolicy));
Assert.notNull(resolvedDataPolicy, String.format("Data Policy [%s] is invalid.", dataPolicy));
assertDataPolicyAndPersistentAttributesAreCompatible(resolvedDataPolicy);
regionFactory.setDataPolicy(resolvedDataPolicy);
setDataPolicy(resolvedDataPolicy);
}
else {
DataPolicy regionAttributesDataPolicy = getDataPolicy(getAttributes(), DataPolicy.DEFAULT);
DataPolicy resolvedDataPolicy = (isPersistent() && DataPolicy.DEFAULT.equals(regionAttributesDataPolicy)
? DataPolicy.PERSISTENT_REPLICATE : regionAttributesDataPolicy);

View File

@@ -0,0 +1,55 @@
/*
* Copyright 2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.gemfire;
import java.util.Optional;
import org.apache.geode.cache.DataPolicy;
import org.apache.geode.cache.RegionShortcut;
import org.springframework.core.convert.converter.Converter;
import org.springframework.lang.Nullable;
/**
* Spring {@link Converter} to convert a {@link RegionShortcut} into a {@link DataPolicy}.
*
* @author John Blum
* @see org.apache.geode.cache.DataPolicy
* @see org.apache.geode.cache.RegionShortcut
* @see org.springframework.core.convert.converter.Converter
* @see org.springframework.data.gemfire.RegionShortcutWrapper
* @since 2.0.2
*/
public class RegionShortcutToDataPolicyConverter implements Converter<RegionShortcut, DataPolicy> {
public static final RegionShortcutToDataPolicyConverter INSTANCE = new RegionShortcutToDataPolicyConverter();
/**
* Converts the given {@link RegionShortcut} into a corresponding {@link DataPolicy}.
*
* @param regionShortcut {@link RegionShortcut} to convert.
* @return a corresponding {@link DataPolicy} for the given {@link RegionShortcut}.
* @see org.apache.geode.cache.RegionShortcut
* @see org.apache.geode.cache.DataPolicy
*/
@Nullable @Override
public DataPolicy convert(RegionShortcut regionShortcut) {
return Optional.ofNullable(RegionShortcutWrapper.valueOf(regionShortcut))
.map(RegionShortcutWrapper::getDataPolicy)
.orElse(DataPolicy.DEFAULT);
}
}

View File

@@ -30,10 +30,11 @@ import org.springframework.util.ObjectUtils;
*/
@SuppressWarnings("unused")
public enum RegionShortcutWrapper {
LOCAL(RegionShortcut.LOCAL, DataPolicy.NORMAL),
LOCAL_HEAP_LRU(RegionShortcut.LOCAL_HEAP_LRU, DataPolicy.NORMAL),
LOCAL_OVERFLOW(RegionShortcut.LOCAL_OVERFLOW, DataPolicy.NORMAL),
LOCAL_PERSISTENT(RegionShortcut.LOCAL_PERSISTENT, DataPolicy.NORMAL),
LOCAL_PERSISTENT(RegionShortcut.LOCAL_PERSISTENT, DataPolicy.PERSISTENT_REPLICATE),
LOCAL_PERSISTENT_OVERFLOW(RegionShortcut.LOCAL_PERSISTENT_OVERFLOW, DataPolicy.PERSISTENT_REPLICATE),
PARTITION(RegionShortcut.PARTITION, DataPolicy.PARTITION),
PARTITION_HEAP_LRU(RegionShortcut.PARTITION_HEAP_LRU, DataPolicy.PARTITION),
@@ -65,6 +66,7 @@ public enum RegionShortcutWrapper {
}
public static RegionShortcutWrapper valueOf(RegionShortcut regionShortcut) {
for (RegionShortcutWrapper wrapper : values()) {
if (ObjectUtils.nullSafeEquals(wrapper.getRegionShortcut(), regionShortcut)) {
return wrapper;

View File

@@ -278,7 +278,7 @@ public class ClientRegionFactoryBean<K, V> extends RegionLookupFactoryBean<K, V>
else {
// NOTE the DataPolicy validation is based on the ClientRegionShortcut initialization logic
// in org.apache.geode.internal.cache.GemFireCacheImpl.initializeClientRegionShortcuts
throw newIllegalArgumentException("Data Policy [%s] is not valid for the client Region", dataPolicy);
throw newIllegalArgumentException("Data Policy [%s] is not valid for a client Region", dataPolicy);
}
}
else {

View File

@@ -0,0 +1,56 @@
/*
* Copyright 2017 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.gemfire.client;
import java.util.Optional;
import org.apache.geode.cache.DataPolicy;
import org.apache.geode.cache.client.ClientRegionShortcut;
import org.springframework.core.convert.converter.Converter;
import org.springframework.lang.Nullable;
/**
* Spring {@link Converter} to convert a {@link ClientRegionShortcut} into a {@link DataPolicy}.
*
* @author John Blum
* @see org.apache.geode.cache.DataPolicy
* @see org.apache.geode.cache.client.ClientRegionShortcut
* @see org.springframework.core.convert.converter.Converter
* @see org.springframework.data.gemfire.client.ClientRegionShortcutWrapper
* @since 2.0.2
*/
public class ClientRegionShortcutToDataPolicyConverter implements Converter<ClientRegionShortcut, DataPolicy> {
public static final ClientRegionShortcutToDataPolicyConverter INSTANCE =
new ClientRegionShortcutToDataPolicyConverter();
/**
* Converts the given {@link ClientRegionShortcut} into a corresponding {@link DataPolicy}.
*
* @param regionShortcut {@link ClientRegionShortcut} to convert.
* @return a corresponding {@link DataPolicy} for the given {@link ClientRegionShortcut}.
* @see org.apache.geode.cache.client.ClientRegionShortcut
* @see org.apache.geode.cache.DataPolicy
*/
@Nullable @Override
public DataPolicy convert(ClientRegionShortcut clientRegionShortcut) {
return Optional.ofNullable(ClientRegionShortcutWrapper.valueOf(clientRegionShortcut))
.map(ClientRegionShortcutWrapper::getDataPolicy)
.orElse(DataPolicy.DEFAULT);
}
}

View File

@@ -47,6 +47,7 @@ public enum ClientRegionShortcutWrapper {
private final DataPolicy dataPolicy;
public static ClientRegionShortcutWrapper valueOf(ClientRegionShortcut clientRegionShortcut) {
for (ClientRegionShortcutWrapper wrapper : values()) {
if (ObjectUtils.nullSafeEquals(wrapper.getClientRegionShortcut(), clientRegionShortcut)) {
return wrapper;

View File

@@ -65,7 +65,7 @@ import org.springframework.core.type.AnnotationMetadata;
import org.springframework.data.gemfire.client.ClientRegionFactoryBean;
import org.springframework.data.gemfire.config.annotation.support.AbstractAnnotationConfigSupport;
import org.springframework.data.gemfire.config.annotation.support.BeanDefinitionRegistryPostProcessorSupport;
import org.springframework.data.gemfire.config.annotation.support.GemFireCacheTypeAwareRegionFactoryBean;
import org.springframework.data.gemfire.config.annotation.support.CacheTypeAwareRegionFactoryBean;
import org.springframework.data.gemfire.config.xml.GemfireConstants;
import org.springframework.data.gemfire.util.CollectionUtils;
import org.springframework.lang.Nullable;
@@ -106,7 +106,7 @@ import org.springframework.util.StringUtils;
* @see org.springframework.data.gemfire.config.annotation.EnableCachingDefinedRegions
* @see org.springframework.data.gemfire.config.annotation.support.AbstractAnnotationConfigSupport
* @see org.springframework.data.gemfire.config.annotation.support.BeanDefinitionRegistryPostProcessorSupport
* @see org.springframework.data.gemfire.config.annotation.support.GemFireCacheTypeAwareRegionFactoryBean
* @see CacheTypeAwareRegionFactoryBean
* @since 2.0.0
*/
@Configuration
@@ -312,7 +312,7 @@ public class CachingDefinedRegionsConfiguration extends AbstractAnnotationConfig
if (!registry.containsBeanDefinition(cacheName)) {
BeanDefinitionBuilder builder =
BeanDefinitionBuilder.genericBeanDefinition(GemFireCacheTypeAwareRegionFactoryBean.class);
BeanDefinitionBuilder.genericBeanDefinition(CacheTypeAwareRegionFactoryBean.class);
builder.addPropertyReference("cache", GemfireConstants.DEFAULT_GEMFIRE_CACHE_NAME);
builder.addPropertyValue("clientRegionShortcut", resolveClientRegionShortcut());
@@ -352,8 +352,8 @@ public class CachingDefinedRegionsConfiguration extends AbstractAnnotationConfig
if (!beanFactory.containsBean(cacheName)) {
try {
GemFireCacheTypeAwareRegionFactoryBean<?, ?> regionFactoryBean =
new GemFireCacheTypeAwareRegionFactoryBean<>();
CacheTypeAwareRegionFactoryBean<?, ?> regionFactoryBean =
new CacheTypeAwareRegionFactoryBean<>();
GemFireCache gemfireCache =
beanFactory.getBean(GemfireConstants.DEFAULT_GEMFIRE_CACHE_NAME, GemFireCache.class);

View File

@@ -25,12 +25,15 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.apache.geode.cache.Region;
import org.apache.geode.cache.RegionShortcut;
import org.apache.geode.cache.client.ClientRegionShortcut;
import org.apache.geode.cache.client.Pool;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.core.annotation.AliasFor;
import org.springframework.data.gemfire.client.ClientRegionFactoryBean;
import org.springframework.data.gemfire.config.annotation.support.CacheTypeAwareRegionFactoryBean;
import org.springframework.data.gemfire.mapping.annotation.ClientRegion;
/**
@@ -39,7 +42,14 @@ import org.springframework.data.gemfire.mapping.annotation.ClientRegion;
* the application persistent entities.
*
* @author John Blum
* @see java.lang.annotation.Documented
* @see java.lang.annotation.Inherited
* @see java.lang.annotation.Retention
* @see java.lang.annotation.Target
* @see org.apache.geode.cache.Region
* @see org.apache.geode.cache.RegionShortcut
* @see org.apache.geode.cache.client.ClientRegionShortcut
* @see org.apache.geode.cache.client.Pool
* @see org.springframework.context.annotation.ComponentScan
* @see org.springframework.context.annotation.ComponentScan.Filter
* @see org.springframework.context.annotation.Import
@@ -48,7 +58,7 @@ import org.springframework.data.gemfire.mapping.annotation.ClientRegion;
* @see org.springframework.data.gemfire.client.ClientRegionFactoryBean
* @see org.springframework.data.gemfire.config.annotation.EntityDefinedRegionsConfiguration
* @see org.springframework.data.gemfire.config.annotation.IndexConfiguration
* @see org.springframework.data.gemfire.config.annotation.support.GemFireCacheTypeAwareRegionFactoryBean
* @see CacheTypeAwareRegionFactoryBean
* @see org.springframework.data.gemfire.mapping.annotation.ClientRegion
* @see org.springframework.data.gemfire.mapping.annotation.LocalRegion
* @see org.springframework.data.gemfire.mapping.annotation.PartitionRegion
@@ -61,6 +71,7 @@ import org.springframework.data.gemfire.mapping.annotation.ClientRegion;
@Inherited
@Documented
@Import(IndexConfiguration.class)
@SuppressWarnings("unused")
public @interface EnableEntityDefinedRegions {
/**
@@ -120,15 +131,35 @@ public @interface EnableEntityDefinedRegions {
ComponentScan.Filter[] includeFilters() default {};
/**
* When this annotation is applied in a cache client application, the {@literal poolName} attribute refers to
* the default name of the GemFire/Geode {@link Pool} assigned to the client {@link Region Region(s)}.
* When this annotation is applied to a cache client application, the {@literal clientRegionShortcut} attribute
* indicates the default data policy applied to client {@link Region Regions} where the persistent entities
* are only annotated with the generic {@link org.springframework.data.gemfire.mapping.annotation.Region}
* mapping annotation, or the non-data policy specific mapping annotation.
*
* This value can be overridden by annotating entities with th e{@link ClientRegion} annotation.
* Defaults to {@link ClientRegionShortcut#PROXY}.
*/
ClientRegionShortcut clientRegionShortcut() default ClientRegionShortcut.PROXY;
/**
* When this annotation is applied to a cache client application, the {@literal poolName} attribute refers to
* the default name of the GemFire/Geode {@link Pool} assigned to client {@link Region Region(s)}.
*
* This value can be overridden by annotating entities with the {@link ClientRegion} annotation.
*
* Defaults to {@literal DEFAULT}.
*/
String poolName() default ClientRegionFactoryBean.DEFAULT_POOL_NAME;
/**
* When this annotation is applied to a peer cache application, the {@literal serverRegionShortcut} attribute
* indicates the default data policy applied to server {@link Region Regions} where the persistent entities
* are only annotated with the generic {@link org.springframework.data.gemfire.mapping.annotation.Region}
* mapping annotation, or the non-data policy specific mapping annotation.
*
* Defaults to {@link RegionShortcut#PARTITION}.
*/
RegionShortcut serverRegionShortcut() default RegionShortcut.PARTITION;
/**
* Determines whether the created {@link Region} will have strongly-typed key and value constraints
* based on the ID and {@link Class} type of application persistent entity.

View File

@@ -22,11 +22,10 @@ import static org.springframework.data.gemfire.util.ArrayUtils.defaultIfEmpty;
import static org.springframework.data.gemfire.util.ArrayUtils.nullSafeArray;
import static org.springframework.data.gemfire.util.CollectionUtils.nullSafeMap;
import static org.springframework.data.gemfire.util.RuntimeExceptionFactory.newIllegalArgumentException;
import static org.springframework.data.gemfire.util.SpringUtils.safeGetValue;
import static org.springframework.data.gemfire.util.RuntimeExceptionFactory.newIllegalStateException;
import java.lang.annotation.Annotation;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
@@ -36,6 +35,8 @@ import java.util.regex.Pattern;
import java.util.stream.Collectors;
import org.apache.geode.cache.Region;
import org.apache.geode.cache.RegionShortcut;
import org.apache.geode.cache.Scope;
import org.apache.geode.cache.client.ClientRegionShortcut;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.BeanFactory;
@@ -55,16 +56,12 @@ import org.springframework.core.type.filter.AssignableTypeFilter;
import org.springframework.core.type.filter.RegexPatternTypeFilter;
import org.springframework.core.type.filter.TypeFilter;
import org.springframework.data.gemfire.FixedPartitionAttributesFactoryBean;
import org.springframework.data.gemfire.LocalRegionFactoryBean;
import org.springframework.data.gemfire.PartitionAttributesFactoryBean;
import org.springframework.data.gemfire.PartitionedRegionFactoryBean;
import org.springframework.data.gemfire.RegionAttributesFactoryBean;
import org.springframework.data.gemfire.RegionLookupFactoryBean;
import org.springframework.data.gemfire.ReplicatedRegionFactoryBean;
import org.springframework.data.gemfire.ScopeType;
import org.springframework.data.gemfire.client.ClientRegionFactoryBean;
import org.springframework.data.gemfire.config.annotation.support.AbstractAnnotationConfigSupport;
import org.springframework.data.gemfire.config.annotation.support.GemFireCacheTypeAwareRegionFactoryBean;
import org.springframework.data.gemfire.config.annotation.support.CacheTypeAwareRegionFactoryBean;
import org.springframework.data.gemfire.config.annotation.support.GemFireComponentClassTypeScanner;
import org.springframework.data.gemfire.config.xml.GemfireConstants;
import org.springframework.data.gemfire.mapping.GemfireMappingContext;
@@ -100,7 +97,7 @@ import org.springframework.util.StringUtils;
* @see org.springframework.data.gemfire.RegionAttributesFactoryBean
* @see org.springframework.data.gemfire.ReplicatedRegionFactoryBean
* @see org.springframework.data.gemfire.client.ClientRegionFactoryBean
* @see org.springframework.data.gemfire.config.annotation.support.GemFireCacheTypeAwareRegionFactoryBean
* @see CacheTypeAwareRegionFactoryBean
* @see org.springframework.data.gemfire.config.annotation.support.GemFireComponentClassTypeScanner
* @see org.springframework.data.gemfire.mapping.GemfireMappingContext
* @see org.springframework.data.gemfire.mapping.GemfirePersistentEntity
@@ -115,21 +112,11 @@ import org.springframework.util.StringUtils;
public class EntityDefinedRegionsConfiguration extends AbstractAnnotationConfigSupport
implements ImportBeanDefinitionRegistrar {
protected static final Class<? extends RegionLookupFactoryBean> DEFAULT_REGION_FACTORY_BEAN_CLASS =
GemFireCacheTypeAwareRegionFactoryBean.class;
protected static final ClientRegionShortcut DEFAULT_CLIENT_REGION_SHORTCUT = ClientRegionShortcut.PROXY;
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);
}
protected static final RegionShortcut DEFAULT_SERVER_REGION_SHORTCUT = RegionShortcut.PARTITION;
@Autowired(required = false)
private GemfireMappingContext mappingContext;
@Autowired(required = false)
@@ -167,17 +154,17 @@ public class EntityDefinedRegionsConfiguration extends AbstractAnnotationConfigS
AnnotationAttributes enableEntityDefinedRegionsAttributes = getAnnotationAttributes(importingClassMetadata);
String poolName = enableEntityDefinedRegionsAttributes.getString("poolName");
boolean strict = enableEntityDefinedRegionsAttributes.getBoolean("strict");
newGemFireComponentClassTypeScanner(importingClassMetadata, enableEntityDefinedRegionsAttributes).scan()
.forEach(persistentEntityClass -> {
.forEach(persistentEntityType -> {
GemfirePersistentEntity persistentEntity = getPersistentEntity(persistentEntityClass);
RegionBeanDefinitionMetadata regionMetadata =
RegionBeanDefinitionMetadata.with(getPersistentEntity(persistentEntityType))
.using(enableEntityDefinedRegionsAttributes);
registerRegionBeanDefinition(persistentEntity, poolName, strict, registry);
postProcess(importingClassMetadata, registry, persistentEntity);
registerRegionBeanDefinition(regionMetadata, registry);
postProcess(importingClassMetadata, registry,
regionMetadata.getPersistentEntity().orElse(null));
});
}
}
@@ -329,6 +316,7 @@ public class EntityDefinedRegionsConfiguration extends AbstractAnnotationConfigS
protected GemfireMappingContext resolveMappingContext() {
return Optional.ofNullable(this.mappingContext).orElseGet(() -> {
try {
this.mappingContext = getBeanFactory().getBean(GemfireMappingContext.class);
}
@@ -344,36 +332,24 @@ public class EntityDefinedRegionsConfiguration extends AbstractAnnotationConfigS
* Registers an individual bean definition in the Spring container for the {@link Region} determined from
* the application domain object, {@link GemfirePersistentEntity persistent entity}.
*
* @param persistentEntity {@link GemfirePersistentEntity} from which to the resolve the {@link Region}.
* @param strict boolean value indicating whether the key and value constraints on the {@link Region} should be set.
* @param regionMetadata {@link RegionBeanDefinitionMetadata} used to configure the {@link Region} bean definition.
* @param registry {@link BeanDefinitionRegistry} used to register the {@link Region} bean definition
* in the Spring context.
* @see org.springframework.beans.factory.support.BeanDefinitionRegistry
* @see org.springframework.data.gemfire.mapping.GemfirePersistentEntity
*/
protected void registerRegionBeanDefinition(GemfirePersistentEntity persistentEntity, String poolName,
boolean strict, BeanDefinitionRegistry registry) {
protected void registerRegionBeanDefinition(RegionBeanDefinitionMetadata regionMetadata,
BeanDefinitionRegistry registry) {
BeanDefinitionBuilder regionFactoryBeanBuilder =
BeanDefinitionBuilder.genericBeanDefinition(resolveRegionFactoryBeanClass(persistentEntity))
BeanDefinitionBuilder.genericBeanDefinition(CacheTypeAwareRegionFactoryBean.class)
.addPropertyReference("cache", GemfireConstants.DEFAULT_GEMFIRE_CACHE_NAME)
.addPropertyValue("regionConfigurers", resolveRegionConfigurers())
.addPropertyValue("close", false);
.addPropertyValue("close", false)
.addPropertyValue("regionConfigurers", resolveRegionConfigurers());
setRegionAttributes(persistentEntity, regionFactoryBeanBuilder, poolName, strict);
setRegionAttributes(regionFactoryBeanBuilder, regionMetadata);
registry.registerBeanDefinition(persistentEntity.getRegionName(),
regionFactoryBeanBuilder.getBeanDefinition());
}
/* (non-Javadoc) */
@SuppressWarnings("unchecked")
protected Class<? extends RegionLookupFactoryBean> resolveRegionFactoryBeanClass(
GemfirePersistentEntity persistentEntity) {
return Optional.<Class<? extends RegionLookupFactoryBean>>ofNullable(
regionAnnotationToRegionFactoryBeanClass.get(persistentEntity.getRegionAnnotationType()))
.orElse(DEFAULT_REGION_FACTORY_BEAN_CLASS);
registry.registerBeanDefinition(regionMetadata.getRegionName(), regionFactoryBeanBuilder.getBeanDefinition());
}
/* (non-Javadoc) */
@@ -385,34 +361,37 @@ public class EntityDefinedRegionsConfiguration extends AbstractAnnotationConfigS
Optional.of(getBeanFactory())
.filter(beanFactory -> beanFactory instanceof ListableBeanFactory)
.map(beanFactory -> {
Map<String, RegionConfigurer> beansOfType = ((ListableBeanFactory) beanFactory)
.getBeansOfType(RegionConfigurer.class, true, true);
return nullSafeMap(beansOfType).values().stream().collect(Collectors.toList());
})
.orElseGet(Collections::emptyList)
);
}
/* (non-Javadoc) */
protected BeanDefinitionBuilder setRegionAttributes(GemfirePersistentEntity persistentEntity,
BeanDefinitionBuilder regionFactoryBeanBuilder, String poolName, boolean strict) {
protected BeanDefinitionBuilder setRegionAttributes(BeanDefinitionBuilder regionFactoryBeanBuilder,
RegionBeanDefinitionMetadata regionMetadata) {
Optional.ofNullable(persistentEntity.getRegionAnnotation()).ifPresent(regionAnnotation -> {
Optional.<Annotation>ofNullable(regionMetadata.getRegionAnnotation()).ifPresent(regionAnnotation -> {
AnnotationAttributes regionAnnotationAttributes = getAnnotationAttributes(regionAnnotation);
if (strict) {
regionFactoryBeanBuilder.addPropertyValue("keyConstraint", resolveIdType(persistentEntity));
regionFactoryBeanBuilder.addPropertyValue("valueConstraint", resolveDomainType(persistentEntity));
}
regionFactoryBeanBuilder.addPropertyValue("clientRegionShortcut",
resolveClientRegionShortcut(regionMetadata, regionAnnotation, regionAnnotationAttributes));
regionFactoryBeanBuilder.addPropertyValue("serverRegionShortcut",
resolveServerRegionShortcut(regionMetadata, regionAnnotation, regionAnnotationAttributes));
if (regionAnnotationAttributes.containsKey("diskStoreName")) {
String diskStoreName = regionAnnotationAttributes.getString("diskStoreName");
setPropertyValueIfNotDefault(regionFactoryBeanBuilder, "diskStoreName", diskStoreName,
"");
setPropertyValueIfNotDefault(regionFactoryBeanBuilder, "diskStoreName",
diskStoreName, "");
if (StringUtils.hasText(diskStoreName)) {
regionFactoryBeanBuilder.addDependsOn(diskStoreName);
@@ -424,13 +403,19 @@ public class EntityDefinedRegionsConfiguration extends AbstractAnnotationConfigS
regionAnnotationAttributes.getBoolean("ignoreIfExists"));
}
if (regionAnnotationAttributes.containsKey("persistent")) {
setPropertyValueIfNotDefault(regionFactoryBeanBuilder, "persistent",
regionAnnotationAttributes.getBoolean("persistent"), false);
if (regionMetadata.isStrict()) {
regionFactoryBeanBuilder.addPropertyValue("keyConstraint",
regionMetadata.getRegionKeyConstraint());
regionFactoryBeanBuilder.addPropertyValue("valueConstraint",
regionMetadata.getRegionValueConstraint());
}
BeanDefinitionBuilder regionAttributesFactoryBeanBuilder =
resolveRegionAttributesFactoryBeanBuilder(regionAnnotation, regionFactoryBeanBuilder);
BeanDefinitionBuilder.genericBeanDefinition(RegionAttributesFactoryBean.class);
regionFactoryBeanBuilder.addPropertyValue("attributes",
regionAttributesFactoryBeanBuilder.getBeanDefinition());
if (regionAnnotationAttributes.containsKey("diskSynchronous")) {
setPropertyValueIfNotDefault(regionAttributesFactoryBeanBuilder, "diskSynchronous",
@@ -442,85 +427,70 @@ public class EntityDefinedRegionsConfiguration extends AbstractAnnotationConfigS
regionAnnotationAttributes.getBoolean("ignoreJta"), false);
}
setClientRegionAttributes(regionAnnotationAttributes, poolName, regionFactoryBeanBuilder);
setClientRegionAttributes(regionMetadata, regionAnnotationAttributes, regionFactoryBeanBuilder);
setPartitionRegionAttributes(regionAnnotationAttributes, regionFactoryBeanBuilder,
setPartitionRegionAttributes(regionMetadata, regionAnnotationAttributes, regionFactoryBeanBuilder,
regionAttributesFactoryBeanBuilder);
setReplicateRegionAttributes(regionAnnotationAttributes, regionFactoryBeanBuilder);
setReplicateRegionAttributes(regionMetadata, regionAnnotationAttributes, regionFactoryBeanBuilder);
});
return regionFactoryBeanBuilder;
}
/* (non-Javadoc) */
protected Class<?> resolveDomainType(GemfirePersistentEntity persistentEntity) {
return persistentEntity.getType();
protected ClientRegionShortcut resolveClientRegionShortcut(RegionBeanDefinitionMetadata regionMetadata,
Annotation regionAnnotation, AnnotationAttributes regionAnnotationAttributes) {
return ClientRegion.class.equals(regionAnnotation.annotationType())
? regionAnnotationAttributes.getEnum("shortcut")
: regionMetadata.resolveClientRegionShortcut(DEFAULT_CLIENT_REGION_SHORTCUT);
}
protected RegionShortcut resolveServerRegionShortcut(RegionBeanDefinitionMetadata regionMetadata,
Annotation regionAnnotation, AnnotationAttributes regionAnnotationAttributes) {
Class<? extends Annotation> regionAnnotationType = regionAnnotation.annotationType();
boolean persistent = (regionAnnotationAttributes.containsKey("persistent")
&& regionAnnotationAttributes.getBoolean("persistent"));
return LocalRegion.class.equals(regionAnnotationType)
? (persistent ? RegionShortcut.LOCAL_PERSISTENT : RegionShortcut.LOCAL)
: PartitionRegion.class.equals(regionAnnotationType)
? (persistent ? RegionShortcut.PARTITION_PERSISTENT : RegionShortcut.PARTITION)
: ReplicateRegion.class.equals(regionAnnotationType)
? (persistent ? RegionShortcut.REPLICATE_PERSISTENT : RegionShortcut.REPLICATE)
: regionMetadata.resolveServerRegionShortcut(DEFAULT_SERVER_REGION_SHORTCUT);
}
/* (non-Javadoc) */
@SuppressWarnings("unchecked")
protected Class<?> resolveIdType(GemfirePersistentEntity persistentEntity) {
protected BeanDefinitionBuilder setClientRegionAttributes(RegionBeanDefinitionMetadata regionMetadata,
AnnotationAttributes regionAnnotationAttributes, BeanDefinitionBuilder regionFactoryBeanBuilder) {
return Optional.ofNullable(persistentEntity.getIdProperty())
.map(idProperty -> ((GemfirePersistentProperty) idProperty).getActualType())
.orElse((Class) Object.class);
}
String resolvedPoolName = regionAnnotationAttributes.containsKey("poolName")
? regionAnnotationAttributes.getString("poolName")
: regionMetadata.getPoolName().orElse(ClientRegionFactoryBean.DEFAULT_POOL_NAME);
/* (non-Javadoc) */
protected BeanDefinitionBuilder resolveRegionAttributesFactoryBeanBuilder(Annotation regionAnnotation,
BeanDefinitionBuilder regionFactoryBeanBuilder) {
BeanDefinitionBuilder regionAttributesFactoryBeanBuilder = regionFactoryBeanBuilder;
if (!ClientRegion.class.isAssignableFrom(regionAnnotation.annotationType())) {
regionAttributesFactoryBeanBuilder =
BeanDefinitionBuilder.genericBeanDefinition(RegionAttributesFactoryBean.class);
regionFactoryBeanBuilder.addPropertyValue("attributes",
regionAttributesFactoryBeanBuilder.getBeanDefinition());
}
return regionAttributesFactoryBeanBuilder;
}
/* (non-Javadoc) */
protected BeanDefinitionBuilder setClientRegionAttributes(AnnotationAttributes regionAnnotationAttributes,
String poolName, BeanDefinitionBuilder regionFactoryBeanBuilder) {
if (isPoolNameConfigured(regionAnnotationAttributes, poolName)) {
setPropertyValueIfNotDefault(regionFactoryBeanBuilder, "poolName",
regionAnnotationAttributes.getString("poolName"), null);
}
if (regionAnnotationAttributes.containsKey("shortcut")) {
setPropertyValueIfNotDefault(regionFactoryBeanBuilder, "shortcut",
regionAnnotationAttributes.getEnum("shortcut"), ClientRegionShortcut.PROXY);
}
setPropertyValueIfNotDefault(regionFactoryBeanBuilder, "poolName",
resolvedPoolName, ClientRegionFactoryBean.DEFAULT_POOL_NAME);
return regionFactoryBeanBuilder;
}
private boolean isPoolNameConfigured(AnnotationAttributes regionAnnotationAttributes, String poolName) {
return (regionAnnotationAttributes.containsKey("poolName")
|| !ClientRegionFactoryBean.DEFAULT_POOL_NAME.equals(poolName));
}
private String resolvePoolName(AnnotationAttributes regionAnnotationAttributes, String poolName) {
return safeGetValue(() -> regionAnnotationAttributes.getString("poolName"), poolName);
}
/* (non-Javadoc) */
protected BeanDefinitionBuilder setPartitionRegionAttributes(AnnotationAttributes regionAnnotationAttributes,
BeanDefinitionBuilder regionFactoryBeanBuilder, BeanDefinitionBuilder regionAttributesFactoryBeanBuilder) {
protected BeanDefinitionBuilder setPartitionRegionAttributes(RegionBeanDefinitionMetadata regionMetadata,
AnnotationAttributes regionAnnotationAttributes, BeanDefinitionBuilder regionFactoryBeanBuilder,
BeanDefinitionBuilder regionAttributesFactoryBeanBuilder) {
if (regionAnnotationAttributes.containsKey("redundantCopies")) {
BeanDefinitionBuilder partitionAttributesFactoryBeanBuilder =
BeanDefinitionBuilder.genericBeanDefinition(PartitionAttributesFactoryBean.class);
String collocatedWith = regionAnnotationAttributes.getString("collocatedWith");
setPropertyValueIfNotDefault(partitionAttributesFactoryBeanBuilder, "colocatedWith", collocatedWith, "");
setPropertyValueIfNotDefault(partitionAttributesFactoryBeanBuilder, "colocatedWith",
collocatedWith, "");
if (StringUtils.hasText(collocatedWith)) {
regionFactoryBeanBuilder.addDependsOn(collocatedWith);
@@ -554,10 +524,12 @@ public class EntityDefinedRegionsConfiguration extends AbstractAnnotationConfigS
new ManagedList<BeanDefinition>(fixedPartitions.length);
for (PartitionRegion.FixedPartition fixedPartition : fixedPartitions) {
BeanDefinitionBuilder fixedPartitionAttributesFactoryBeanBuilder =
BeanDefinitionBuilder.genericBeanDefinition(FixedPartitionAttributesFactoryBean.class);
fixedPartitionAttributesFactoryBeanBuilder.addPropertyValue("partitionName", fixedPartition.name());
fixedPartitionAttributesFactoryBeanBuilder.addPropertyValue("partitionName",
fixedPartition.name());
setPropertyValueIfNotDefault(fixedPartitionAttributesFactoryBeanBuilder, "primary",
fixedPartition.primary(), false);
@@ -565,25 +537,25 @@ public class EntityDefinedRegionsConfiguration extends AbstractAnnotationConfigS
setPropertyValueIfNotDefault(fixedPartitionAttributesFactoryBeanBuilder, "numBuckets",
fixedPartition.numBuckets(), 1);
fixedPartitionAttributesFactoryBeans.add(
fixedPartitionAttributesFactoryBeanBuilder.getBeanDefinition());
fixedPartitionAttributesFactoryBeans
.add(fixedPartitionAttributesFactoryBeanBuilder.getBeanDefinition());
}
partitionAttributesFactoryBeanBuilder.addPropertyValue("fixedPartitionAttributes",
fixedPartitionAttributesFactoryBeans);
partitionAttributesFactoryBeanBuilder
.addPropertyValue("fixedPartitionAttributes", fixedPartitionAttributesFactoryBeans);
}
return partitionAttributesFactoryBeanBuilder;
}
/* (non-Javadoc) */
protected BeanDefinitionBuilder setReplicateRegionAttributes(AnnotationAttributes regionAnnotationAttributes,
BeanDefinitionBuilder regionFactoryBeanBuilder) {
protected BeanDefinitionBuilder setReplicateRegionAttributes(RegionBeanDefinitionMetadata regionMetadata,
AnnotationAttributes regionAnnotationAttributes, BeanDefinitionBuilder regionFactoryBeanBuilder) {
if (regionAnnotationAttributes.containsKey("scope")) {
setPropertyValueIfNotDefault(regionFactoryBeanBuilder, "scope",
regionAnnotationAttributes.<ScopeType>getEnum("scope").getScope(),
ScopeType.DISTRIBUTED_NO_ACK);
Scope.DISTRIBUTED_NO_ACK);
}
return regionFactoryBeanBuilder;
@@ -624,4 +596,125 @@ public class EntityDefinedRegionsConfiguration extends AbstractAnnotationConfigS
return persistentEntity;
}
/**
* The {@link RegionBeanDefinitionMetadata} class encapsulates details for creating a {@link Region}
* from application persistent entities. The details are captured during a persistent entity component scan.
*
* @see org.springframework.data.gemfire.mapping.GemfirePersistentEntity
*/
protected static class RegionBeanDefinitionMetadata {
/**
* Factory method used to construct a new instance of the {@link RegionBeanDefinitionMetadata}.
*
* @return a new instance of {@link RegionBeanDefinitionMetadata}.
*/
protected static RegionBeanDefinitionMetadata with(GemfirePersistentEntity<?> persistentEntity) {
return new RegionBeanDefinitionMetadata(persistentEntity);
}
private boolean strict;
private ClientRegionShortcut clientRegionShortcut;
private GemfirePersistentEntity<?> persistentEntity;
private RegionShortcut serverRegionShortcut;
private String poolName;
protected RegionBeanDefinitionMetadata(GemfirePersistentEntity<?> persistentEntity) {
this.persistentEntity = Optional.ofNullable(persistentEntity)
.orElseThrow(() -> newIllegalArgumentException("GemfirePeristentEntity is required"));
}
protected boolean isStrict() {
return this.strict;
}
protected Optional<ClientRegionShortcut> getClientRegionShortcut() {
return Optional.ofNullable(this.clientRegionShortcut);
}
protected ClientRegionShortcut resolveClientRegionShortcut(ClientRegionShortcut defaultClientRegionShortcut) {
return getClientRegionShortcut().orElse(defaultClientRegionShortcut);
}
protected Optional<GemfirePersistentEntity<?>> getPersistentEntity() {
return Optional.ofNullable(this.persistentEntity);
}
protected GemfirePersistentEntity<?> resolvePersistentEntity() {
return getPersistentEntity().orElseThrow(() ->
newIllegalStateException("GemfirePersistentEntity could not be resolved"));
}
protected Optional<String> getPoolName() {
return Optional.ofNullable(this.poolName).filter(StringUtils::hasText);
}
protected <T extends Annotation> T getRegionAnnotation() {
return resolvePersistentEntity().getRegionAnnotation();
}
@SuppressWarnings("unchecked")
protected Class<?> getRegionKeyConstraint() {
return Optional.ofNullable(resolvePersistentEntity().getIdProperty())
.map(idProperty -> ((GemfirePersistentProperty) idProperty).getActualType())
.orElse((Class) Object.class);
}
protected String getRegionName() {
return resolvePersistentEntity().getRegionName();
}
@SuppressWarnings("all")
protected Class<?> getRegionValueConstraint() {
return Optional.ofNullable(resolvePersistentEntity().getType())
.orElse((Class) Object.class);
}
protected Optional<RegionShortcut> getServerRegionShortcut() {
return Optional.ofNullable(this.serverRegionShortcut);
}
protected RegionShortcut resolveServerRegionShortcut(RegionShortcut defaultServerRegionShortcut) {
return getServerRegionShortcut().orElse(defaultServerRegionShortcut);
}
protected RegionBeanDefinitionMetadata is(boolean strict) {
this.strict = strict;
return this;
}
protected RegionBeanDefinitionMetadata using(AnnotationAttributes enableEntityDefinedRegionsAttributes) {
return Optional.ofNullable(enableEntityDefinedRegionsAttributes)
.map(it ->
this.using(it.<ClientRegionShortcut>getEnum("clientRegionShortcut"))
.using(it.getString("poolName"))
.using(it.<RegionShortcut>getEnum("serverRegionShortcut"))
.is(it.getBoolean("strict"))
)
.orElse(this);
}
protected RegionBeanDefinitionMetadata using(ClientRegionShortcut clientRegionShortcut) {
this.clientRegionShortcut = clientRegionShortcut;
return this;
}
protected RegionBeanDefinitionMetadata using(RegionShortcut serverRegionShortcut) {
this.serverRegionShortcut = serverRegionShortcut;
return this;
}
protected RegionBeanDefinitionMetadata using(String poolName) {
this.poolName = poolName;
return this;
}
}
}

View File

@@ -20,6 +20,7 @@ import org.apache.geode.cache.Region;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.gemfire.RegionFactoryBean;
import org.springframework.data.gemfire.client.ClientRegionFactoryBean;
import org.springframework.data.gemfire.config.annotation.support.CacheTypeAwareRegionFactoryBean;
/**
* The {@link RegionConfigurer} interface defines a contract for implementations to customize the configuration
@@ -31,7 +32,7 @@ import org.springframework.data.gemfire.client.ClientRegionFactoryBean;
* @see org.springframework.data.gemfire.RegionFactoryBean
* @see org.springframework.data.gemfire.client.ClientRegionFactoryBean
* @see org.springframework.data.gemfire.config.annotation.EnableEntityDefinedRegions
* @see org.springframework.data.gemfire.config.annotation.support.GemFireCacheTypeAwareRegionFactoryBean
* @see CacheTypeAwareRegionFactoryBean
* @since 1.1.0
*/
public interface RegionConfigurer {

View File

@@ -24,38 +24,55 @@ import java.util.Collections;
import java.util.List;
import java.util.Optional;
import org.apache.geode.cache.Cache;
import org.apache.geode.cache.DataPolicy;
import org.apache.geode.cache.GemFireCache;
import org.apache.geode.cache.Region;
import org.apache.geode.cache.RegionAttributes;
import org.apache.geode.cache.RegionShortcut;
import org.apache.geode.cache.Scope;
import org.apache.geode.cache.client.ClientCache;
import org.apache.geode.cache.client.ClientRegionShortcut;
import org.apache.geode.cache.client.PoolManager;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.data.gemfire.GemfireUtils;
import org.springframework.data.gemfire.GenericRegionFactoryBean;
import org.springframework.data.gemfire.LocalRegionFactoryBean;
import org.springframework.data.gemfire.PartitionedRegionFactoryBean;
import org.springframework.data.gemfire.RegionFactoryBean;
import org.springframework.data.gemfire.RegionLookupFactoryBean;
import org.springframework.data.gemfire.RegionShortcutWrapper;
import org.springframework.data.gemfire.ReplicatedRegionFactoryBean;
import org.springframework.data.gemfire.client.ClientRegionFactoryBean;
import org.springframework.data.gemfire.config.annotation.RegionConfigurer;
import org.springframework.util.StringUtils;
/**
* The {@link GemFireCacheTypeAwareRegionFactoryBean} class is a smart Spring {@link FactoryBean} that knows how to
* create a client or server {@link Region} depending on whether the {@link GemFireCache} is
* a {@link org.apache.geode.cache.client.ClientCache} or a peer {@link org.apache.geode.cache.Cache}.
* The {@link CacheTypeAwareRegionFactoryBean} class is a smart Spring {@link FactoryBean} that knows how to
* create a client or server {@link Region} depending on whether the {@link GemFireCache} is a {@link ClientCache}
* or a peer {@link Cache}.
*
* @author John Blum
* @see org.apache.geode.cache.Cache
* @see org.apache.geode.cache.DataPolicy
* @see org.apache.geode.cache.GemFireCache
* @see org.apache.geode.cache.Region
* @see org.apache.geode.cache.RegionAttributes
* @see org.apache.geode.cache.RegionShortcut
* @see org.apache.geode.cache.Scope
* @see org.apache.geode.cache.client.ClientCache
* @see org.apache.geode.cache.client.ClientRegionShortcut
* @see org.springframework.data.gemfire.GenericRegionFactoryBean
* @see org.springframework.data.gemfire.RegionLookupFactoryBean
* @see org.springframework.data.gemfire.LocalRegionFactoryBean
* @see org.springframework.data.gemfire.PartitionedRegionFactoryBean
* @see org.springframework.data.gemfire.RegionFactoryBean
* @see org.springframework.data.gemfire.RegionLookupFactoryBean
* @see org.springframework.data.gemfire.ReplicatedRegionFactoryBean
* @see org.springframework.data.gemfire.client.ClientRegionFactoryBean
* @see org.springframework.data.gemfire.config.annotation.RegionConfigurer
* @since 1.9.0
*/
@SuppressWarnings("unused")
public class GemFireCacheTypeAwareRegionFactoryBean<K, V> extends RegionLookupFactoryBean<K, V> {
public class CacheTypeAwareRegionFactoryBean<K, V> extends RegionLookupFactoryBean<K, V> {
private GemFireCache gemfireCache;
@@ -74,6 +91,9 @@ public class GemFireCacheTypeAwareRegionFactoryBean<K, V> extends RegionLookupFa
private RegionShortcut serverRegionShortcut;
private Scope scope;
private String diskStoreName;
private String poolName;
private String regionName;
@@ -88,7 +108,7 @@ public class GemFireCacheTypeAwareRegionFactoryBean<K, V> extends RegionLookupFa
}
/**
* Constructs a new client {@link Region} using the {@link ClientRegionFactoryBean}.
* Constructs, configures and initialize\s a new client {@link Region} using the {@link ClientRegionFactoryBean}.
*
* @param gemfireCache reference to the {@link GemFireCache} used to create/initialize the factory
* used to create the client {@link Region}.
@@ -98,22 +118,25 @@ public class GemFireCacheTypeAwareRegionFactoryBean<K, V> extends RegionLookupFa
* @see org.springframework.data.gemfire.client.ClientRegionFactoryBean
* @see org.apache.geode.cache.GemFireCache
* @see org.apache.geode.cache.Region
* @see #newClientRegionFactoryBean()
*/
protected Region<K, V> newClientRegion(GemFireCache gemfireCache, String regionName) throws Exception {
ClientRegionFactoryBean<K, V> clientRegionFactory = new ClientRegionFactoryBean<>();
ClientRegionFactoryBean<K, V> clientRegionFactory = newClientRegionFactoryBean();
clientRegionFactory.setAttributes(getRegionAttributes());
clientRegionFactory.setBeanFactory(getBeanFactory());
clientRegionFactory.setCache(gemfireCache);
clientRegionFactory.setClose(isClose());
clientRegionFactory.setDiskStoreName(getDiskStoreName());
clientRegionFactory.setKeyConstraint(getKeyConstraint());
clientRegionFactory.setLookupEnabled(getLookupEnabled());
clientRegionFactory.setRegionConfigurers(this.regionConfigurers);
clientRegionFactory.setRegionName(regionName);
clientRegionFactory.setShortcut(getClientRegionShortcut());
clientRegionFactory.setValueConstraint(getValueConstraint());
resolvePoolName().ifPresent(clientRegionFactory::setPoolName);
getPoolName().ifPresent(clientRegionFactory::setPoolName);
clientRegionFactory.afterPropertiesSet();
@@ -121,7 +144,20 @@ public class GemFireCacheTypeAwareRegionFactoryBean<K, V> extends RegionLookupFa
}
/**
* Constructs a new server {@link Region} using the {@link GenericRegionFactoryBean}.
* Constructs a new instance of the {@link ClientRegionFactoryBean}.
*
* @param <K> {@link Class type} of the created {@link Region Region's} key.
* @param <V> {@link Class type} of the created {@link Region Region's} value.
* @return a new instance of the {@link ClientRegionFactoryBean}.
* @see org.springframework.data.gemfire.client.ClientRegionFactoryBean
*/
protected <K, V> ClientRegionFactoryBean<K, V> newClientRegionFactoryBean() {
return new ClientRegionFactoryBean<>();
}
/**
* Constructs, configures and initializes a new server {@link Region} using a sub-class
* of {@link RegionFactoryBean}.
*
* @param gemfireCache reference to the {@link GemFireCache} used to create/initialize the factory
* used to create the server {@link Region}.
@@ -131,17 +167,20 @@ public class GemFireCacheTypeAwareRegionFactoryBean<K, V> extends RegionLookupFa
* @see org.springframework.data.gemfire.GenericRegionFactoryBean
* @see org.apache.geode.cache.GemFireCache
* @see org.apache.geode.cache.Region
* @see #newRegionFactoryBean()
*/
protected Region<K, V> newServerRegion(GemFireCache gemfireCache, String regionName) throws Exception {
GenericRegionFactoryBean<K, V> serverRegionFactory = new GenericRegionFactoryBean<>();
RegionFactoryBean<K, V> serverRegionFactory = newRegionFactoryBean();
serverRegionFactory.setAttributes(getRegionAttributes());
serverRegionFactory.setBeanFactory(getBeanFactory());
serverRegionFactory.setCache(gemfireCache);
serverRegionFactory.setClose(isClose());
serverRegionFactory.setDataPolicy(getDataPolicy());
serverRegionFactory.setDiskStoreName(getDiskStoreName());
serverRegionFactory.setKeyConstraint(getKeyConstraint());
serverRegionFactory.setLookupEnabled(getLookupEnabled());
serverRegionFactory.setRegionConfigurers(this.regionConfigurers);
serverRegionFactory.setRegionName(regionName);
serverRegionFactory.setShortcut(getServerRegionShortcut());
@@ -152,6 +191,39 @@ public class GemFireCacheTypeAwareRegionFactoryBean<K, V> extends RegionLookupFa
return serverRegionFactory.getObject();
}
/**
* Constructs a {@link Class sub-type} of the {@link RegionFactoryBean} class based on
* the {@link #getServerRegionShortcut()} and {@link #getDataPolicy()}.
*
* @return a new instance of the {@link RegionFactoryBean}.
* @see org.springframework.data.gemfire.LocalRegionFactoryBean
* @see org.springframework.data.gemfire.PartitionedRegionFactoryBean
* @see org.springframework.data.gemfire.ReplicatedRegionFactoryBean
* @see org.springframework.data.gemfire.RegionFactoryBean
*/
protected RegionFactoryBean<K, V> newRegionFactoryBean() {
RegionShortcutWrapper regionShortcutWrapper = RegionShortcutWrapper.valueOf(getServerRegionShortcut());
DataPolicy resolvedDataPolicy = Optional.of(regionShortcutWrapper)
.map(RegionShortcutWrapper::getDataPolicy)
.orElseGet(this::getDataPolicy);
if (regionShortcutWrapper.isLocal()) {
return new LocalRegionFactoryBean<>();
}
else if (resolvedDataPolicy.withPartitioning()) {
return new PartitionedRegionFactoryBean<>();
}
else if (resolvedDataPolicy.withReplication()) {
ReplicatedRegionFactoryBean<K, V> replicatedRegionFactoryBean = new ReplicatedRegionFactoryBean<>();
replicatedRegionFactoryBean.setScope(getScope());
return replicatedRegionFactoryBean;
}
return new GenericRegionFactoryBean<>();
}
public void setAttributes(RegionAttributes<K, V> regionAttributes) {
this.regionAttributes = regionAttributes;
}
@@ -188,6 +260,14 @@ public class GemFireCacheTypeAwareRegionFactoryBean<K, V> extends RegionLookupFa
return Optional.ofNullable(this.dataPolicy).orElse(DataPolicy.DEFAULT);
}
public void setDiskStoreName(String diskStoreName) {
this.diskStoreName = diskStoreName;
}
protected String getDiskStoreName() {
return this.diskStoreName;
}
public void setKeyConstraint(Class<K> keyConstraint) {
this.keyConstraint = keyConstraint;
}
@@ -200,17 +280,12 @@ public class GemFireCacheTypeAwareRegionFactoryBean<K, V> extends RegionLookupFa
this.poolName = poolName;
}
protected String getPoolName() {
return Optional.ofNullable(this.poolName).filter(StringUtils::hasText)
.orElse(ClientRegionFactoryBean.GEMFIRE_POOL_NAME);
protected Optional<String> getPoolName() {
return Optional.ofNullable(this.poolName).filter(StringUtils::hasText);
}
protected Optional<String> resolvePoolName() {
return Optional.of(getPoolName()).filter(this::isPoolResolvable);
}
private boolean isPoolResolvable(String poolName) {
return (getBeanFactory().containsBean(poolName) || (PoolManager.find(poolName) != null));
protected String resolvePoolName() {
return getPoolName().orElse(null);
}
/**
@@ -238,6 +313,14 @@ public class GemFireCacheTypeAwareRegionFactoryBean<K, V> extends RegionLookupFa
this.regionConfigurers = Optional.ofNullable(regionConfigurers).orElseGet(Collections::emptyList);
}
public void setScope(Scope scope) {
this.scope = scope;
}
protected Scope getScope() {
return this.scope;
}
public void setServerRegionShortcut(RegionShortcut shortcut) {
this.serverRegionShortcut = shortcut;
}

View File

@@ -16,8 +16,6 @@
package org.springframework.data.gemfire.mapping;
import static org.springframework.data.gemfire.util.SpringUtils.defaultIfEmpty;
import java.lang.annotation.Annotation;
import java.util.Optional;
@@ -30,6 +28,7 @@ import org.springframework.data.mapping.PersistentEntity;
import org.springframework.data.mapping.PersistentProperty;
import org.springframework.data.mapping.model.BasicPersistentEntity;
import org.springframework.data.util.TypeInformation;
import org.springframework.util.StringUtils;
/**
* {@link PersistentEntity} implementation adding custom GemFire persistent entity related metadata, such as the
@@ -50,9 +49,11 @@ public class GemfirePersistentEntity<T> extends BasicPersistentEntity<T, Gemfire
/* (non-Javadoc) */
protected static Annotation resolveRegionAnnotation(Class<?> persistentEntityType) {
for (Class<? extends Annotation> regionAnnotationType : Region.REGION_ANNOTATION_TYPES) {
Annotation regionAnnotation = AnnotatedElementUtils.getMergedAnnotation(
persistentEntityType, regionAnnotationType);
Annotation regionAnnotation =
AnnotatedElementUtils.getMergedAnnotation(persistentEntityType, regionAnnotationType);
if (regionAnnotation != null) {
return regionAnnotation;
@@ -64,11 +65,11 @@ public class GemfirePersistentEntity<T> extends BasicPersistentEntity<T, Gemfire
/* (non-Javadoc) */
protected static String resolveRegionName(Class<?> persistentEntityType, Annotation regionAnnotation) {
String regionName = Optional.ofNullable(regionAnnotation)
.map((annotation) -> getAnnotationAttributeStringValue(annotation, "value"))
.orElse(null);
return defaultIfEmpty(regionName, persistentEntityType.getSimpleName());
Optional<String> regionName = Optional.ofNullable(regionAnnotation)
.map((annotation) -> getAnnotationAttributeStringValue(annotation, "value"));
return regionName.filter(StringUtils::hasText).orElse(persistentEntityType.getSimpleName());
}
/* (non-Javadoc) */
@@ -86,6 +87,7 @@ public class GemfirePersistentEntity<T> extends BasicPersistentEntity<T, Gemfire
* @see org.springframework.data.util.TypeInformation
*/
public GemfirePersistentEntity(TypeInformation<T> information) {
super(information);
Class<T> rawType = information.getType();