diff --git a/src/main/java/org/springframework/data/gemfire/client/ClientCacheFactoryBean.java b/src/main/java/org/springframework/data/gemfire/client/ClientCacheFactoryBean.java index 37fd06dc..a16a69c0 100644 --- a/src/main/java/org/springframework/data/gemfire/client/ClientCacheFactoryBean.java +++ b/src/main/java/org/springframework/data/gemfire/client/ClientCacheFactoryBean.java @@ -337,6 +337,7 @@ public class ClientCacheFactoryBean extends CacheFactoryBean implements Applicat * @see #findPool(String) */ Pool resolvePool() { + Pool localPool = getPool(); if (localPool == null) { @@ -411,6 +412,7 @@ public class ClientCacheFactoryBean extends CacheFactoryBean implements Applicat */ @Override public void onApplicationEvent(ContextRefreshedEvent event) { + if (isReadyForEvents()) { try { this.fetchCache().readyForEvents(); @@ -760,6 +762,7 @@ public class ClientCacheFactoryBean extends CacheFactoryBean implements Applicat * @see #getReadyForEvents() */ public boolean isReadyForEvents() { + Boolean readyForEvents = getReadyForEvents(); if (readyForEvents != null) { diff --git a/src/main/java/org/springframework/data/gemfire/client/ClientRegionFactoryBean.java b/src/main/java/org/springframework/data/gemfire/client/ClientRegionFactoryBean.java index db7a42bc..e12cdd45 100644 --- a/src/main/java/org/springframework/data/gemfire/client/ClientRegionFactoryBean.java +++ b/src/main/java/org/springframework/data/gemfire/client/ClientRegionFactoryBean.java @@ -40,6 +40,7 @@ import org.apache.geode.cache.client.ClientCache; import org.apache.geode.cache.client.ClientRegionFactory; import org.apache.geode.cache.client.ClientRegionShortcut; import org.apache.geode.cache.client.Pool; +import org.apache.geode.cache.client.PoolManager; import org.springframework.beans.BeansException; import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.FactoryBean; @@ -75,6 +76,9 @@ import org.springframework.util.StringUtils; @SuppressWarnings("unused") public class ClientRegionFactoryBean extends RegionLookupFactoryBean implements DisposableBean { + public static final String DEFAULT_POOL_NAME = "DEFAULT"; + public static final String GEMFIRE_POOL_NAME = GemfireConstants.DEFAULT_GEMFIRE_POOL_NAME; + private boolean close = false; private boolean destroy = false; @@ -278,8 +282,7 @@ public class ClientRegionFactoryBean extends RegionLookupFactoryBean } } else { - resolvedShortcut = (isPersistent() ? ClientRegionShortcut.LOCAL_PERSISTENT - : ClientRegionShortcut.LOCAL); + resolvedShortcut = (isPersistent() ? ClientRegionShortcut.LOCAL_PERSISTENT : ClientRegionShortcut.LOCAL); } } @@ -292,14 +295,17 @@ public class ClientRegionFactoryBean extends RegionLookupFactoryBean /* (non-Javadoc) */ private String resolvePoolName() { - String poolName = this.poolName; + return Optional.of(getPoolName()).filter(this::isPoolResolvable).orElse(DEFAULT_POOL_NAME); + } - if (!StringUtils.hasText(poolName)) { - String defaultPoolName = GemfireConstants.DEFAULT_GEMFIRE_POOL_NAME; - poolName = (getBeanFactory().containsBean(defaultPoolName) ? defaultPoolName : poolName); - } + /* (non-Javadoc) */ + private String getPoolName() { + return Optional.ofNullable(this.poolName).filter(StringUtils::hasText).orElse(GEMFIRE_POOL_NAME); + } - return poolName; + /* (non-Javadoc) */ + private boolean isPoolResolvable(String poolName) { + return (getBeanFactory().containsBean(poolName) || (PoolManager.find(poolName) != null)); } /* (non-Javadoc) */ @@ -424,6 +430,7 @@ public class ClientRegionFactoryBean extends RegionLookupFactoryBean private Region registerInterests(Region region) { stream(nullSafeArray(this.interests, Interest.class)).forEach(interest -> { + if (interest.isRegexType()) { region.registerInterestRegex((String) interest.getKey(), interest.getPolicy(), interest.isDurable(), interest.isReceiveValues()); @@ -447,6 +454,7 @@ public class ClientRegionFactoryBean extends RegionLookupFactoryBean public void destroy() throws Exception { Optional.ofNullable(getObject()).ifPresent(region -> { + if (isClose()) { if (!region.getRegionService().isClosed()) { try { diff --git a/src/main/java/org/springframework/data/gemfire/client/PoolFactoryBean.java b/src/main/java/org/springframework/data/gemfire/client/PoolFactoryBean.java index 1a11b3f0..8410e2aa 100644 --- a/src/main/java/org/springframework/data/gemfire/client/PoolFactoryBean.java +++ b/src/main/java/org/springframework/data/gemfire/client/PoolFactoryBean.java @@ -290,6 +290,7 @@ public class PoolFactoryBean extends AbstractFactoryBeanSupport implements protected PoolFactory configure(PoolFactory poolFactory) { Optional.ofNullable(poolFactory).ifPresent(it -> { + it.setFreeConnectionTimeout(this.freeConnectionTimeout); it.setIdleTimeout(this.idleTimeout); it.setLoadConditioningInterval(this.loadConditioningInterval); @@ -395,7 +396,9 @@ public class PoolFactoryBean extends AbstractFactoryBeanSupport implements /* (non-Javadoc) */ public Pool getPool() { + return Optional.ofNullable(this.pool).orElseGet(() -> new PoolAdapter() { + @Override public boolean isDestroyed() { Pool pool = PoolFactoryBean.this.pool; diff --git a/src/main/java/org/springframework/data/gemfire/config/annotation/EnableEntityDefinedRegions.java b/src/main/java/org/springframework/data/gemfire/config/annotation/EnableEntityDefinedRegions.java index 3675fe60..b9672545 100644 --- a/src/main/java/org/springframework/data/gemfire/config/annotation/EnableEntityDefinedRegions.java +++ b/src/main/java/org/springframework/data/gemfire/config/annotation/EnableEntityDefinedRegions.java @@ -25,10 +25,13 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import org.apache.geode.cache.Region; +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.mapping.annotation.ClientRegion; /** * The {@link EnableEntityDefinedRegions} annotation marks a Spring {@link Configuration @Configuration} application @@ -46,6 +49,11 @@ import org.springframework.core.annotation.AliasFor; * @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 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.Region + * @see org.springframework.data.gemfire.mapping.annotation.ReplicateRegion * @since 1.9.0 */ @Target(ElementType.TYPE) @@ -111,6 +119,16 @@ 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)}. + * + * This value can be overridden by annotating entities with th e{@link ClientRegion} annotation. + * + * Defaults to {@literal DEFAULT}. + */ + String poolName() default ClientRegionFactoryBean.DEFAULT_POOL_NAME; + /** * Determines whether the created {@link Region} will have strongly-typed key and value constraints * based on the ID and {@link Class} type of application persistent entity. diff --git a/src/main/java/org/springframework/data/gemfire/config/annotation/EnablePool.java b/src/main/java/org/springframework/data/gemfire/config/annotation/EnablePool.java index efcdfe32..9128cfc3 100644 --- a/src/main/java/org/springframework/data/gemfire/config/annotation/EnablePool.java +++ b/src/main/java/org/springframework/data/gemfire/config/annotation/EnablePool.java @@ -146,9 +146,9 @@ public @interface EnablePool { /** * Specifies the {@link String name} of the client {@link Pool} in Pivotal GemFire/Apache Geode, which is also - * used as the Spring bean name in the container as well as the name - * (e.g. {@literal spring.data.gemfire.pool..max-connections} used in the resolution of {@link Pool} - * properties from {@literal application.properties} that are specific to this {@link Pool}. + * used as the name of the bean registered in the Spring container as well as the name used in the resolution + * of {@link Pool} properties from {@literal application.properties} + * (e.g. {@literal spring.data.gemfire.pool..max-connections}), that are specific to this {@link Pool}. */ String name(); diff --git a/src/main/java/org/springframework/data/gemfire/config/annotation/EntityDefinedRegionsConfiguration.java b/src/main/java/org/springframework/data/gemfire/config/annotation/EntityDefinedRegionsConfiguration.java index 04e65921..480d69e9 100644 --- a/src/main/java/org/springframework/data/gemfire/config/annotation/EntityDefinedRegionsConfiguration.java +++ b/src/main/java/org/springframework/data/gemfire/config/annotation/EntityDefinedRegionsConfiguration.java @@ -22,6 +22,7 @@ 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 java.lang.annotation.Annotation; import java.util.Collections; @@ -37,10 +38,7 @@ import java.util.stream.Collectors; 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.ListableBeanFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.config.BeanDefinition; @@ -50,7 +48,6 @@ 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; @@ -66,6 +63,7 @@ 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.GemFireComponentClassTypeScanner; import org.springframework.data.gemfire.config.xml.GemfireConstants; @@ -76,7 +74,7 @@ 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.data.gemfire.util.SpringUtils; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.util.ObjectUtils; @@ -91,9 +89,6 @@ import org.springframework.util.StringUtils; * @see java.lang.ClassLoader * @see java.lang.annotation.Annotation * @see org.apache.geode.cache.Region - * @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 @@ -117,8 +112,8 @@ import org.springframework.util.StringUtils; * @since 1.9.0 */ @SuppressWarnings("unused") -public class EntityDefinedRegionsConfiguration - implements BeanClassLoaderAware, BeanFactoryAware, ImportBeanDefinitionRegistrar { +public class EntityDefinedRegionsConfiguration extends AbstractAnnotationConfigSupport + implements ImportBeanDefinitionRegistrar { protected static final Class DEFAULT_REGION_FACTORY_BEAN_CLASS = GemFireCacheTypeAwareRegionFactoryBean.class; @@ -135,10 +130,6 @@ public class EntityDefinedRegionsConfiguration DEFAULT_REGION_FACTORY_BEAN_CLASS); } - private BeanFactory beanFactory; - - private ClassLoader beanClassLoader; - private GemfireMappingContext mappingContext; @Autowired(required = false) @@ -154,112 +145,20 @@ public class EntityDefinedRegionsConfiguration * @see java.lang.annotation.Annotation * @see java.lang.Class */ + @Override protected Class getAnnotationType() { return EnableEntityDefinedRegions.class; } /** - * Returns the name of the {@link Annotation} type that configures and creates {@link Region Regions} - * for application persistent entities. + * Registers {@link Region} bean definitions in the Spring context for all application domain object + * that have been identified as {@link GemfirePersistentEntity 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); - } - - /* (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 + * @param importingClassMetadata {@link Class} with the {@link EnableEntityDefinedRegions} annotation. + * @param registry {@link BeanDefinitionRegistry} used to register the {@link Region} bean definitions + * in the Spring context. + * @see org.springframework.beans.factory.support.BeanDefinitionRegistry + * @see org.springframework.core.type.AnnotationMetadata */ @Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { @@ -268,6 +167,8 @@ public class EntityDefinedRegionsConfiguration AnnotationAttributes enableEntityDefinedRegionsAttributes = getAnnotationAttributes(importingClassMetadata); + String poolName = enableEntityDefinedRegionsAttributes.getString("poolName"); + boolean strict = enableEntityDefinedRegionsAttributes.getBoolean("strict"); newGemFireComponentClassTypeScanner(importingClassMetadata, enableEntityDefinedRegionsAttributes).scan() @@ -275,7 +176,7 @@ public class EntityDefinedRegionsConfiguration GemfirePersistentEntity persistentEntity = getPersistentEntity(persistentEntityClass); - registerRegionBeanDefinition(persistentEntity, strict, registry); + registerRegionBeanDefinition(persistentEntity, poolName, strict, registry); postProcess(importingClassMetadata, registry, persistentEntity); }); } @@ -291,7 +192,7 @@ public class EntityDefinedRegionsConfiguration return GemFireComponentClassTypeScanner.from(resolvedBasePackages).with(resolveBeanClassLoader()) .withExcludes(resolveExcludes(enableEntityDefinedRegionsAttributes)) .withIncludes(resolveIncludes(enableEntityDefinedRegionsAttributes)) - .withIncludes(regionAnnotatedPersistentEntityTypeFilters()); + .withIncludes(resolveRegionAnnotatedPersistentEntityTypeFilters()); } /* (non-Javadoc) */ @@ -316,12 +217,6 @@ public class EntityDefinedRegionsConfiguration return resolvedBasePackages; } - /* (non-Javadoc) */ - protected ClassLoader resolveBeanClassLoader() { - return Optional.ofNullable(this.beanClassLoader) - .orElseGet(() -> Thread.currentThread().getContextClassLoader()); - } - /* (non-Javadoc) */ protected Iterable resolveExcludes(AnnotationAttributes enableEntityDefinedRegionsAttributes) { return parseFilters(enableEntityDefinedRegionsAttributes.getAnnotationArray("excludeFilters")); @@ -333,25 +228,31 @@ public class EntityDefinedRegionsConfiguration } /* (non-Javadoc) */ - private Iterable parseFilters(AnnotationAttributes[] componentScanFilterAttributes) { + @SuppressWarnings("unchecked") + protected Iterable resolveRegionAnnotatedPersistentEntityTypeFilters() { - Set typeFilters = new HashSet<>(); - - stream(nullSafeArray(componentScanFilterAttributes, AnnotationAttributes.class)) - .forEach(filterAttributes -> CollectionUtils.addAll(typeFilters, typeFiltersFor(filterAttributes))); - - return typeFilters; + return org.springframework.data.gemfire.mapping.annotation.Region.REGION_ANNOTATION_TYPES.stream() + .map(AnnotationTypeFilter::new) + .collect(Collectors.toSet()); + } + + private Iterable parseFilters(AnnotationAttributes[] componentScanFilterAttributes) { + + return stream(nullSafeArray(componentScanFilterAttributes, AnnotationAttributes.class)) + .flatMap(filterAttributes -> typeFiltersFor(filterAttributes).stream()) + .collect(Collectors.toSet()); } - /* (non-Javadoc) */ @SuppressWarnings("unchecked") - private Iterable typeFiltersFor(AnnotationAttributes filterAttributes) { + private Set typeFiltersFor(AnnotationAttributes filterAttributes) { Set typeFilters = new HashSet<>(); + FilterType filterType = filterAttributes.getEnum("type"); stream(nullSafeArray(filterAttributes.getClassArray("value"), Class.class)) .forEach(filterClass -> { + switch (filterType) { case ANNOTATION: Assert.isAssignable(Annotation.class, filterClass, @@ -384,7 +285,7 @@ public class EntityDefinedRegionsConfiguration "Illegal filter type [%s] when 'patterns' are specified", filterType); } } - }); + }); return typeFilters; } @@ -397,29 +298,61 @@ public class EntityDefinedRegionsConfiguration * @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]; - } + + return SpringUtils.safeGetValue(() -> + nullSafeArray(filterAttributes.getStringArray("pattern"), String.class), () -> new String[0]); } - /* (non-Javadoc) */ - @SuppressWarnings("unchecked") - protected Iterable regionAnnotatedPersistentEntityTypeFilters() { - - Set regionAnnotatedPersistentEntityTypeFilters = new HashSet<>(); - - org.springframework.data.gemfire.mapping.annotation.Region.REGION_ANNOTATION_TYPES.forEach( - annotationType -> regionAnnotatedPersistentEntityTypeFilters.add(new AnnotationTypeFilter(annotationType))); - - return regionAnnotatedPersistentEntityTypeFilters; + /** + * Returns the associated {@link GemfirePersistentEntity persistent entity} for the given application + * domain object type. + * + * @param persistentEntityType {@link Class type} of the application domain object used to lookup + * the {@link GemfirePersistentEntity persistent entity} from the {@link @GemfireMappingContext mapping context}. + * @return the {@link GemfirePersistentEntity persistent entity} for the given application domain object type. + * @see org.springframework.data.gemfire.mapping.GemfirePersistentEntity + * @see java.lang.Class + */ + protected GemfirePersistentEntity getPersistentEntity(Class persistentEntityType) { + return resolveMappingContext().getPersistentEntity(persistentEntityType); } - /* (non-Javadoc) */ - protected void registerRegionBeanDefinition(GemfirePersistentEntity persistentEntity, boolean strict, - BeanDefinitionRegistry registry) { + /** + * Resolves the {@link GemfireMappingContext mapping context} by returning the configured + * {@link GemfireMappingContext mapping context} if present, or attempts to lookup + * the {@link GemfireMappingContext mapping context} from the configured {@link BeanFactory}. + * If the lookup is unsuccessful, then this method will return a new {@link GemfireMappingContext mapping context}. + * + * @return the resolved {@link GemfireMappingContext mapping context}. + * @see org.springframework.data.gemfire.mapping.GemfireMappingContext + */ + protected GemfireMappingContext resolveMappingContext() { + + return Optional.ofNullable(this.mappingContext).orElseGet(() -> { + try { + this.mappingContext = beanFactory().getBean(GemfireMappingContext.class); + } + catch (Throwable ignore) { + this.mappingContext = new GemfireMappingContext(); + } + + return this.mappingContext; + }); + } + + /** + * 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 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) { BeanDefinitionBuilder regionFactoryBeanBuilder = BeanDefinitionBuilder.genericBeanDefinition(resolveRegionFactoryBeanClass(persistentEntity)) @@ -427,19 +360,29 @@ public class EntityDefinedRegionsConfiguration .addPropertyValue("regionConfigurers", resolveRegionConfigurers()) .addPropertyValue("close", false); - setRegionAttributes(persistentEntity, regionFactoryBeanBuilder, strict); + setRegionAttributes(persistentEntity, regionFactoryBeanBuilder, poolName, strict); registry.registerBeanDefinition(persistentEntity.getRegionName(), regionFactoryBeanBuilder.getBeanDefinition()); } /* (non-Javadoc) */ - private List resolveRegionConfigurers() { + @SuppressWarnings("unchecked") + protected Class resolveRegionFactoryBeanClass( + GemfirePersistentEntity persistentEntity) { + + return Optional.>ofNullable( + regionAnnotationToRegionFactoryBeanClass.get(persistentEntity.getRegionAnnotationType())) + .orElse(DEFAULT_REGION_FACTORY_BEAN_CLASS); + } + + /* (non-Javadoc) */ + protected List resolveRegionConfigurers() { return Optional.ofNullable(this.regionConfigurers) .filter(regionConfigurers -> !regionConfigurers.isEmpty()) .orElseGet(() -> - Optional.ofNullable(this.beanFactory) + Optional.ofNullable(beanFactory()) .filter(beanFactory -> beanFactory instanceof ListableBeanFactory) .map(beanFactory -> { Map beansOfType = ((ListableBeanFactory) beanFactory) @@ -451,21 +394,12 @@ public class EntityDefinedRegionsConfiguration ); } - /* (non-Javadoc) */ - @SuppressWarnings("unchecked") - protected Class resolveRegionFactoryBeanClass( - GemfirePersistentEntity persistentEntity) { - - return Optional.>ofNullable( - regionAnnotationToRegionFactoryBeanClass.get(persistentEntity.getRegionAnnotationType())) - .orElse(DEFAULT_REGION_FACTORY_BEAN_CLASS); - } - /* (non-Javadoc) */ protected BeanDefinitionBuilder setRegionAttributes(GemfirePersistentEntity persistentEntity, - BeanDefinitionBuilder regionFactoryBeanBuilder, boolean strict) { + BeanDefinitionBuilder regionFactoryBeanBuilder, String poolName, boolean strict) { Optional.ofNullable(persistentEntity.getRegionAnnotation()).ifPresent(regionAnnotation -> { + AnnotationAttributes regionAnnotationAttributes = getAnnotationAttributes(regionAnnotation); if (strict) { @@ -474,10 +408,11 @@ 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); @@ -507,7 +442,7 @@ public class EntityDefinedRegionsConfiguration regionAnnotationAttributes.getBoolean("ignoreJta"), false); } - setClientRegionAttributes(regionAnnotationAttributes, regionFactoryBeanBuilder); + setClientRegionAttributes(regionAnnotationAttributes, poolName, regionFactoryBeanBuilder); setPartitionRegionAttributes(regionAnnotationAttributes, regionFactoryBeanBuilder, regionAttributesFactoryBeanBuilder); @@ -520,7 +455,7 @@ public class EntityDefinedRegionsConfiguration /* (non-Javadoc) */ protected Class resolveDomainType(GemfirePersistentEntity persistentEntity) { - return Optional.ofNullable(persistentEntity.getType()).orElse(Object.class); + return persistentEntity.getType(); } /* (non-Javadoc) */ @@ -551,9 +486,9 @@ public class EntityDefinedRegionsConfiguration /* (non-Javadoc) */ protected BeanDefinitionBuilder setClientRegionAttributes(AnnotationAttributes regionAnnotationAttributes, - BeanDefinitionBuilder regionFactoryBeanBuilder) { + String poolName, BeanDefinitionBuilder regionFactoryBeanBuilder) { - if (regionAnnotationAttributes.containsKey("poolName")) { + if (isPoolNameConfigured(regionAnnotationAttributes, poolName)) { setPropertyValueIfNotDefault(regionFactoryBeanBuilder, "poolName", regionAnnotationAttributes.getString("poolName"), null); } @@ -566,6 +501,15 @@ public class EntityDefinedRegionsConfiguration 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) { diff --git a/src/main/java/org/springframework/data/gemfire/config/annotation/IndexConfiguration.java b/src/main/java/org/springframework/data/gemfire/config/annotation/IndexConfiguration.java index d274f5db..8bc0340b 100644 --- a/src/main/java/org/springframework/data/gemfire/config/annotation/IndexConfiguration.java +++ b/src/main/java/org/springframework/data/gemfire/config/annotation/IndexConfiguration.java @@ -275,7 +275,7 @@ public class IndexConfiguration extends EntityDefinedRegionsConfiguration { return Optional.ofNullable(this.indexConfigurers) .filter(indexConfigurers -> !indexConfigurers.isEmpty()) .orElseGet(() -> - Optional.of(getBeanFactory()) + Optional.of(beanFactory()) .filter(beanFactory -> beanFactory instanceof ListableBeanFactory) .map(beanFactory -> { Map beansOfType = ((ListableBeanFactory) beanFactory) diff --git a/src/main/java/org/springframework/data/gemfire/config/annotation/support/AbstractAnnotationConfigSupport.java b/src/main/java/org/springframework/data/gemfire/config/annotation/support/AbstractAnnotationConfigSupport.java index 5bff35ec..c55214c6 100644 --- a/src/main/java/org/springframework/data/gemfire/config/annotation/support/AbstractAnnotationConfigSupport.java +++ b/src/main/java/org/springframework/data/gemfire/config/annotation/support/AbstractAnnotationConfigSupport.java @@ -20,6 +20,7 @@ package org.springframework.data.gemfire.config.annotation.support; import static org.springframework.data.gemfire.util.RuntimeExceptionFactory.newIllegalArgumentException; import static org.springframework.data.gemfire.util.RuntimeExceptionFactory.newIllegalStateException; +import java.lang.annotation.Annotation; import java.util.ArrayList; import java.util.List; import java.util.Objects; @@ -40,7 +41,10 @@ import org.springframework.context.EnvironmentAware; import org.springframework.context.expression.BeanFactoryAccessor; import org.springframework.context.expression.EnvironmentAccessor; import org.springframework.context.expression.MapAccessor; +import org.springframework.core.annotation.AnnotationAttributes; +import org.springframework.core.annotation.AnnotationUtils; import org.springframework.core.env.Environment; +import org.springframework.core.type.AnnotationMetadata; import org.springframework.expression.EvaluationContext; import org.springframework.expression.spel.support.StandardEvaluationContext; import org.springframework.expression.spel.support.StandardTypeConverter; @@ -186,12 +190,39 @@ public abstract class AbstractAnnotationConfigSupport return LogFactory.getLog(getClass()); } + /* (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)); + } + /** * Returns the cache application {@link java.lang.annotation.Annotation} type pertaining to this configuration. * * @return the cache application {@link java.lang.annotation.Annotation} type used by this application. */ - protected abstract Class getAnnotationType(); + protected abstract Class getAnnotationType(); /** * Returns the fully-qualified {@link Class#getName() class name} of the cache application @@ -238,6 +269,19 @@ public abstract class AbstractAnnotationConfigSupport return this.beanClassLoader; } + /** + * Resolves the {@link ClassLoader bean ClassLoader} to the configured {@link ClassLoader} + * or the {@link Thread#getContextClassLoader() Thread Context ClassLoader}. + * + * @return the configured {@link ClassLoader} or the + * {@link Thread#getContextClassLoader() Thread Context ClassLoader}. + * @see java.lang.Thread#getContextClassLoader() + * @see #beanClassLoader() + */ + protected ClassLoader resolveBeanClassLoader() { + return Optional.ofNullable(beanClassLoader()).orElseGet(() -> Thread.currentThread().getContextClassLoader()); + } + /** * {@inheritDoc} */ @@ -282,8 +326,10 @@ public abstract class AbstractAnnotationConfigSupport } /** + * Returns a reference to the {@link EvaluationContext} used to evaluate SpEL expressions. * - * @return + * @return a reference to the {@link EvaluationContext} used to evaluate SpEL expressions. + * @see org.springframework.expression.EvaluationContext */ protected EvaluationContext evaluationContext() { return this.evaluationContext; diff --git a/src/main/java/org/springframework/data/gemfire/config/annotation/support/EmbeddedServiceConfigurationSupport.java b/src/main/java/org/springframework/data/gemfire/config/annotation/support/EmbeddedServiceConfigurationSupport.java index 5edb7d42..4730508f 100644 --- a/src/main/java/org/springframework/data/gemfire/config/annotation/support/EmbeddedServiceConfigurationSupport.java +++ b/src/main/java/org/springframework/data/gemfire/config/annotation/support/EmbeddedServiceConfigurationSupport.java @@ -132,11 +132,6 @@ public abstract class EmbeddedServiceConfigurationSupport extends AbstractAnnota return !CollectionUtils.isEmpty(properties); } - /* (non-Javadoc) */ - protected Map getAnnotationAttributes(AnnotationMetadata importingClassMetadata) { - return importingClassMetadata.getAnnotationAttributes(getAnnotationTypeName()); - } - /* (non-Javadoc) */ protected void registerGemFirePropertiesBeanPostProcessor(BeanDefinitionRegistry registry, Properties customGemFireProperties) { diff --git a/src/main/java/org/springframework/data/gemfire/config/annotation/support/GemFireCacheTypeAwareRegionFactoryBean.java b/src/main/java/org/springframework/data/gemfire/config/annotation/support/GemFireCacheTypeAwareRegionFactoryBean.java index cbc4bd9d..6b58f267 100644 --- a/src/main/java/org/springframework/data/gemfire/config/annotation/support/GemFireCacheTypeAwareRegionFactoryBean.java +++ b/src/main/java/org/springframework/data/gemfire/config/annotation/support/GemFireCacheTypeAwareRegionFactoryBean.java @@ -30,13 +30,13 @@ import org.apache.geode.cache.Region; import org.apache.geode.cache.RegionAttributes; import org.apache.geode.cache.RegionShortcut; 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.RegionLookupFactoryBean; import org.springframework.data.gemfire.client.ClientRegionFactoryBean; import org.springframework.data.gemfire.config.annotation.RegionConfigurer; -import org.springframework.data.gemfire.config.xml.GemfireConstants; import org.springframework.util.StringUtils; /** @@ -47,7 +47,6 @@ import org.springframework.util.StringUtils; * @author John Blum * @see org.apache.geode.cache.GemFireCache * @see org.apache.geode.cache.Region - * @see org.springframework.beans.factory.FactoryBean * @see org.springframework.data.gemfire.GenericRegionFactoryBean * @see org.springframework.data.gemfire.RegionLookupFactoryBean * @see org.springframework.data.gemfire.RegionFactoryBean @@ -109,7 +108,7 @@ public class GemFireCacheTypeAwareRegionFactoryBean extends RegionLookupFa clientRegionFactory.setCache(gemfireCache); clientRegionFactory.setClose(isClose()); clientRegionFactory.setKeyConstraint(getKeyConstraint()); - clientRegionFactory.setPoolName(getPoolName()); + clientRegionFactory.setPoolName(resolvePoolName()); clientRegionFactory.setRegionConfigurers(this.regionConfigurers); clientRegionFactory.setRegionName(regionName); clientRegionFactory.setShortcut(getClientRegionShortcut()); @@ -137,6 +136,7 @@ public class GemFireCacheTypeAwareRegionFactoryBean extends RegionLookupFa GenericRegionFactoryBean serverRegionFactory = new GenericRegionFactoryBean<>(); serverRegionFactory.setAttributes(getRegionAttributes()); + serverRegionFactory.setBeanFactory(getBeanFactory()); serverRegionFactory.setCache(gemfireCache); serverRegionFactory.setClose(isClose()); serverRegionFactory.setDataPolicy(getDataPolicy()); @@ -201,7 +201,16 @@ public class GemFireCacheTypeAwareRegionFactoryBean extends RegionLookupFa protected String getPoolName() { return Optional.ofNullable(this.poolName).filter(StringUtils::hasText) - .orElse(GemfireConstants.DEFAULT_GEMFIRE_POOL_NAME); + .orElse(ClientRegionFactoryBean.GEMFIRE_POOL_NAME); + } + + protected String resolvePoolName() { + return Optional.of(getPoolName()).filter(this::isPoolResolvable) + .orElse(ClientRegionFactoryBean.DEFAULT_POOL_NAME); + } + + private boolean isPoolResolvable(String poolName) { + return (getBeanFactory().containsBean(poolName) || (PoolManager.find(poolName) != null)); } /** diff --git a/src/main/java/org/springframework/data/gemfire/config/annotation/support/GemFireComponentClassTypeScanner.java b/src/main/java/org/springframework/data/gemfire/config/annotation/support/GemFireComponentClassTypeScanner.java index 91753d0c..fccc6d3d 100644 --- a/src/main/java/org/springframework/data/gemfire/config/annotation/support/GemFireComponentClassTypeScanner.java +++ b/src/main/java/org/springframework/data/gemfire/config/annotation/support/GemFireComponentClassTypeScanner.java @@ -17,23 +17,29 @@ package org.springframework.data.gemfire.config.annotation.support; +import static java.util.stream.StreamSupport.stream; +import static org.springframework.data.gemfire.util.ArrayUtils.nullSafeArray; +import static org.springframework.data.gemfire.util.CollectionUtils.asSet; +import static org.springframework.data.gemfire.util.CollectionUtils.nullSafeIterable; + import java.util.Collections; import java.util.HashSet; import java.util.Iterator; +import java.util.Optional; import java.util.Set; +import java.util.concurrent.ConcurrentSkipListSet; +import java.util.stream.Collectors; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider; import org.springframework.core.env.Environment; import org.springframework.core.env.StandardEnvironment; import org.springframework.core.type.filter.TypeFilter; -import org.springframework.data.gemfire.util.ArrayUtils; -import org.springframework.data.gemfire.util.CollectionUtils; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; +import org.springframework.util.StringUtils; /** * The {@link GemFireComponentClassTypeScanner} class is a classpath component scanner used to search @@ -44,6 +50,7 @@ import org.springframework.util.ClassUtils; * @see org.springframework.context.ConfigurableApplicationContext * @see org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider * @see org.springframework.core.env.Environment + * @see org.springframework.core.type.filter.TypeFilter * @since 1.9.0 */ @SuppressWarnings("unused") @@ -59,8 +66,7 @@ public class GemFireComponentClassTypeScanner implements Iterable { * @see #GemFireComponentClassTypeScanner(Set) */ public static GemFireComponentClassTypeScanner from(String... basePackages) { - return new GemFireComponentClassTypeScanner(CollectionUtils.asSet( - ArrayUtils.nullSafeArray(basePackages, String.class))); + return new GemFireComponentClassTypeScanner(asSet(nullSafeArray(basePackages, String.class))); } /** @@ -73,21 +79,16 @@ public class GemFireComponentClassTypeScanner implements Iterable { * @see #GemFireComponentClassTypeScanner(Set) */ public static GemFireComponentClassTypeScanner from(Iterable basePackages) { - Set basePackageSet = new HashSet(); - - for (String basePackage : CollectionUtils.nullSafeIterable(basePackages)) { - basePackageSet.add(basePackage); - } - - return new GemFireComponentClassTypeScanner(basePackageSet); + return new GemFireComponentClassTypeScanner(stream(basePackages.spliterator(), false) + .collect(Collectors.toSet())); } private ClassLoader entityClassLoader; private ConfigurableApplicationContext applicationContext; - private Set excludes = new HashSet(); - private Set includes = new HashSet(); + private Set excludes = new HashSet<>(); + private Set includes = new HashSet<>(); protected final Log log = LogFactory.getLog(getClass()); @@ -102,7 +103,7 @@ public class GemFireComponentClassTypeScanner implements Iterable { * @see java.util.Set */ protected GemFireComponentClassTypeScanner(Set basePackages) { - Assert.notEmpty(basePackages, "Base packages must be specified"); + Assert.notEmpty(basePackages, "Base packages is required"); this.basePackages = basePackages; } @@ -120,21 +121,24 @@ public class GemFireComponentClassTypeScanner implements Iterable { * Returns an unmodifiable {@link Set} of base packages to scan for GemFire components. * * @return an unmodifiable {@link Set} of base packages to scan for GemFire components. + * @see java.util.Set */ protected Set getBasePackages() { return Collections.unmodifiableSet(this.basePackages); } /** - * Returns a reference to the {@link ClassLoader} to find and load GemFire application persistent entity classes. + * Returns a reference to the {@link ClassLoader} used to find and load GemFire application + * persistent entity classes. * - * @return a {@link ClassLoader} to find and load GemFire application persistent entity classes. + * @return the {@link ClassLoader} used to find and load GemFire application persistent entity classes. * @see org.springframework.beans.factory.config.ConfigurableBeanFactory#getBeanClassLoader() * @see java.lang.Thread#getContextClassLoader() * @see java.lang.ClassLoader * @see #getApplicationContext() */ protected ClassLoader getEntityClassLoader() { + ConfigurableApplicationContext applicationContext = getApplicationContext(); return (this.entityClassLoader != null ? this.entityClassLoader @@ -152,8 +156,10 @@ public class GemFireComponentClassTypeScanner implements Iterable { * @see #getApplicationContext() */ protected Environment getEnvironment() { - ConfigurableApplicationContext applicationContext = getApplicationContext(); - return (applicationContext != null ? applicationContext.getEnvironment() : new StandardEnvironment()); + + return Optional.ofNullable(getApplicationContext()) + .map(ConfigurableApplicationContext::getEnvironment) + .orElse(new StandardEnvironment()); } /** @@ -162,6 +168,7 @@ public class GemFireComponentClassTypeScanner implements Iterable { * * @return a collection of {@link TypeFilter} objects * @see org.springframework.core.type.filter.TypeFilter + * @see java.lang.Iterable */ protected Iterable getExcludes() { return this.excludes; @@ -173,46 +180,49 @@ public class GemFireComponentClassTypeScanner implements Iterable { * * @return a collection of {@link TypeFilter} objects * @see org.springframework.core.type.filter.TypeFilter + * @see java.lang.Iterable */ protected Iterable getIncludes() { return this.includes; } - /** - * @inheritDoc - */ @Override public Iterator iterator() { return getBasePackages().iterator(); } /** - * Scans the {@link Set} of base packages searching for GemFire application components accepted by the filters - * of this scanner. + * Scans the {@link Set} of base packages searching for GemFire application components + * accepted by the filters of this scanner. * - * @return a {@link Set} of GemFire application component {@link Class} types. + * @return a {@link Set} of GemFire application component {@link Class} types found on the classpath. * @see #newClassPathScanningCandidateComponentProvider(boolean) * @see java.util.Set */ public Set> scan() { - Set> componentClasses = new HashSet>(); + + Set> componentClasses = new ConcurrentSkipListSet<>(); ClassLoader entityClassLoader = getEntityClassLoader(); ClassPathScanningCandidateComponentProvider componentProvider = newClassPathScanningCandidateComponentProvider(); - for (String packageName : this) { - for (BeanDefinition beanDefinition : componentProvider.findCandidateComponents(packageName)) { - try { - componentClasses.add(ClassUtils.forName(beanDefinition.getBeanClassName(), entityClassLoader)); - } - catch (ClassNotFoundException ignore) { - log.warn(String.format("Class not found for component type [%s]", - beanDefinition.getBeanClassName())); - } - } - } + stream(this.spliterator(), true) + .flatMap(packageName -> componentProvider.findCandidateComponents(packageName).stream()) + .forEach(beanDefinition -> { + Optional.ofNullable(beanDefinition.getBeanClassName()) + .filter(StringUtils::hasText) + .ifPresent(beanClassName -> { + try { + componentClasses.add(ClassUtils.forName(beanClassName, entityClassLoader)); + } + catch (ClassNotFoundException ignore) { + log.warn(String.format("Class for component type [%s] not found", + beanDefinition.getBeanClassName())); + } + }); + }); return componentClasses; } @@ -245,13 +255,8 @@ public class GemFireComponentClassTypeScanner implements Iterable { ClassPathScanningCandidateComponentProvider componentProvider = new ClassPathScanningCandidateComponentProvider(useDefaultFilters, getEnvironment()); - for (TypeFilter exclude : excludes) { - componentProvider.addExcludeFilter(exclude); - } - - for (TypeFilter include : includes) { - componentProvider.addIncludeFilter(include); - } + this.excludes.forEach(componentProvider::addExcludeFilter); + this.includes.forEach(componentProvider::addIncludeFilter); return componentProvider; } @@ -270,29 +275,23 @@ public class GemFireComponentClassTypeScanner implements Iterable { /* (non-Javadoc) */ public GemFireComponentClassTypeScanner withExcludes(TypeFilter... excludes) { - return withExcludes(CollectionUtils.asSet(ArrayUtils.nullSafeArray(excludes, TypeFilter.class))); + return withExcludes(asSet(nullSafeArray(excludes, TypeFilter.class))); } /* (non-Javadoc) */ public GemFireComponentClassTypeScanner withExcludes(Iterable excludes) { - for (TypeFilter exclude : CollectionUtils.nullSafeIterable(excludes)) { - this.excludes.add(exclude); - } - + stream(nullSafeIterable(excludes).spliterator(), false).forEach(this.excludes::add); return this; } /* (non-Javadoc) */ public GemFireComponentClassTypeScanner withIncludes(TypeFilter... includes) { - return withIncludes(CollectionUtils.asSet(ArrayUtils.nullSafeArray(includes, TypeFilter.class))); + return withIncludes(asSet(nullSafeArray(includes, TypeFilter.class))); } /* (non-Javadoc) */ public GemFireComponentClassTypeScanner withIncludes(Iterable includes) { - for (TypeFilter include : CollectionUtils.nullSafeIterable(includes)) { - this.includes.add(include); - } - + stream(nullSafeIterable(includes).spliterator(), false).forEach(this.includes::add); return this; } } diff --git a/src/main/java/org/springframework/data/gemfire/mapping/annotation/ClientRegion.java b/src/main/java/org/springframework/data/gemfire/mapping/annotation/ClientRegion.java index a0e63cad..c231110d 100644 --- a/src/main/java/org/springframework/data/gemfire/mapping/annotation/ClientRegion.java +++ b/src/main/java/org/springframework/data/gemfire/mapping/annotation/ClientRegion.java @@ -28,7 +28,7 @@ import java.lang.annotation.Target; import org.apache.geode.cache.client.ClientRegionShortcut; import org.apache.geode.cache.client.Pool; import org.springframework.core.annotation.AliasFor; -import org.springframework.data.gemfire.config.xml.GemfireConstants; +import org.springframework.data.gemfire.client.ClientRegionFactoryBean; /** * {@link Annotation} defining the Client {@link Region} in which the application persistent entity will be stored. @@ -82,7 +82,7 @@ public @interface ClientRegion { String diskStoreName() default ""; /** - * Determines whether disk-based operations (used in overflow and persistent) are synchronous or asynchronous. + * Determines whether disk-based operations (used in overflow and persistence) are synchronous or asynchronous. * * Defaults to {@literal synchronous}. */ @@ -101,9 +101,9 @@ public @interface ClientRegion { * data access operations sent to the corresponding {@link org.apache.geode.cache.Region} * on the GemFire/Geode Server. * - * Defaults to {@literal gemfirePool}. + * Defaults to {@literal DEFAULT}. */ - String poolName() default GemfireConstants.DEFAULT_GEMFIRE_POOL_NAME; + String poolName() default ClientRegionFactoryBean.DEFAULT_POOL_NAME; /** * {@link ClientRegionShortcut} used by this persistent entity's client {@link org.apache.geode.cache.Region} diff --git a/src/main/java/org/springframework/data/gemfire/mapping/annotation/LocalRegion.java b/src/main/java/org/springframework/data/gemfire/mapping/annotation/LocalRegion.java index 8b320abc..6fcd183e 100644 --- a/src/main/java/org/springframework/data/gemfire/mapping/annotation/LocalRegion.java +++ b/src/main/java/org/springframework/data/gemfire/mapping/annotation/LocalRegion.java @@ -79,7 +79,7 @@ public @interface LocalRegion { String diskStoreName() default ""; /** - * Determines whether disk-based operations (used in overflow and persistent) are synchronous or asynchronous. + * Determines whether disk-based operations (used in overflow and persistence) are synchronous or asynchronous. * * Defaults to {@literal synchronous}. */ diff --git a/src/main/java/org/springframework/data/gemfire/mapping/annotation/PartitionRegion.java b/src/main/java/org/springframework/data/gemfire/mapping/annotation/PartitionRegion.java index f87099ee..b5647666 100644 --- a/src/main/java/org/springframework/data/gemfire/mapping/annotation/PartitionRegion.java +++ b/src/main/java/org/springframework/data/gemfire/mapping/annotation/PartitionRegion.java @@ -91,7 +91,7 @@ public @interface PartitionRegion { String diskStoreName() default ""; /** - * Determines whether disk-based operations (used in overflow and persistent) are synchronous or asynchronous. + * Determines whether disk-based operations (used in overflow and persistence) are synchronous or asynchronous. * * Defaults to {@literal synchronous}. */ diff --git a/src/main/java/org/springframework/data/gemfire/mapping/annotation/ReplicateRegion.java b/src/main/java/org/springframework/data/gemfire/mapping/annotation/ReplicateRegion.java index d3144832..9ab4108e 100644 --- a/src/main/java/org/springframework/data/gemfire/mapping/annotation/ReplicateRegion.java +++ b/src/main/java/org/springframework/data/gemfire/mapping/annotation/ReplicateRegion.java @@ -80,7 +80,7 @@ public @interface ReplicateRegion { String diskStoreName() default ""; /** - * Determines whether disk-based operations (used in overflow and persistent) are synchronous or asynchronous. + * Determines whether disk-based operations (used in overflow and persistence) are synchronous or asynchronous. * * Defaults to {@literal synchronous}. */ diff --git a/src/main/java/org/springframework/data/gemfire/util/SpringUtils.java b/src/main/java/org/springframework/data/gemfire/util/SpringUtils.java index d1055e30..d557670d 100644 --- a/src/main/java/org/springframework/data/gemfire/util/SpringUtils.java +++ b/src/main/java/org/springframework/data/gemfire/util/SpringUtils.java @@ -24,6 +24,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Optional; +import java.util.function.Function; import java.util.function.Supplier; import org.springframework.beans.factory.BeanFactory; @@ -87,17 +88,27 @@ public abstract class SpringUtils { } /* (non-Javadoc) */ - public static T safeGetValue(Supplier supplier) { - return safeGetValue(supplier, null); + public static T safeGetValue(Supplier valueSupplier) { + return safeGetValue(valueSupplier, (T) null); } /* (non-Javadoc) */ - public static T safeGetValue(Supplier supplier, T defaultValue) { + public static T safeGetValue(Supplier valueSupplier, T defaultValue) { + return safeGetValue(valueSupplier, (Supplier) () -> defaultValue); + } + + /* (non-Javadoc) */ + public static T safeGetValue(Supplier valueSupplier, Supplier defaultValueSupplier) { + return safeGetValue(valueSupplier, (Function) exception -> defaultValueSupplier.get()); + } + + /* (non-Javadoc) */ + public static T safeGetValue(Supplier valueSupplier, Function exceptionHandler) { try { - return supplier.get(); + return valueSupplier.get(); } - catch (Throwable ignore) { - return defaultValue; + catch (Throwable cause) { + return exceptionHandler.apply(cause); } } } diff --git a/src/test/java/org/springframework/data/gemfire/util/SpringUtilsUnitTests.java b/src/test/java/org/springframework/data/gemfire/util/SpringUtilsUnitTests.java index 04b38218..c49d6d6f 100644 --- a/src/test/java/org/springframework/data/gemfire/util/SpringUtilsUnitTests.java +++ b/src/test/java/org/springframework/data/gemfire/util/SpringUtilsUnitTests.java @@ -24,7 +24,10 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.springframework.data.gemfire.util.ArrayUtils.asArray; +import static org.springframework.data.gemfire.util.RuntimeExceptionFactory.newIllegalStateException; +import static org.springframework.data.gemfire.util.RuntimeExceptionFactory.newRuntimeException; +import java.util.function.Function; import java.util.function.Supplier; import org.junit.Test; @@ -205,19 +208,72 @@ public class SpringUtilsUnitTests { } @Test - public void safeGetValueReturnsSupplierValue() { - assertThat(SpringUtils.safeGetValue(() -> "test", null)).isEqualTo("test"); - } - - @Test - public void safeGetValueReturnsDefaultValue() { - assertThat(SpringUtils.safeGetValue(() -> { throw new RuntimeException("error"); }, "test")) - .isEqualTo("test"); + public void safeGetValueReturnsSuppliedValue() { + assertThat(SpringUtils.safeGetValue(() -> "test")).isEqualTo("test"); } @Test public void safeGetValueReturnsNull() { - assertThat(SpringUtils.safeGetValue(() -> { throw new RuntimeException("error"); }, "test")) + assertThat(SpringUtils.safeGetValue(() -> { throw newRuntimeException("error"); })).isNull(); + } + + @Test + public void safeGetValueReturnsDefaultValue() { + assertThat(SpringUtils.safeGetValue(() -> { throw newRuntimeException("error"); }, "test")) .isEqualTo("test"); } + + @Test + public void safeGetValueReturnsSuppliedDefaultValue() { + + Supplier exceptionThrowingSupplier = () -> { throw newRuntimeException("error"); }; + Supplier defaultValueSupplier = () -> "test"; + + assertThat(SpringUtils.safeGetValue(exceptionThrowingSupplier, defaultValueSupplier)).isEqualTo("test"); + } + + @Test + public void safeGetValueHandlesExceptionReturnsValue() { + + Supplier exceptionThrowingSupplier = () -> { throw newRuntimeException("error"); }; + + Function exceptionHandler = exception -> { + + assertThat(exception).isInstanceOf(RuntimeException.class); + assertThat(exception).hasMessage("error"); + assertThat(exception).hasNoCause(); + + return "test"; + }; + + assertThat(SpringUtils.safeGetValue(exceptionThrowingSupplier, exceptionHandler)).isEqualTo("test"); + } + + @Test(expected = IllegalStateException.class) + public void safeGetValueHandlesExceptionAndCanThrowException() { + + Supplier exceptionThrowingSupplier = () -> { throw newRuntimeException("error"); }; + + Function exceptionHandler = exception -> { + + assertThat(exception).isInstanceOf(RuntimeException.class); + assertThat(exception).hasMessage("error"); + assertThat(exception).hasNoCause(); + + throw newIllegalStateException(exception, "test"); + }; + + try { + SpringUtils.safeGetValue(exceptionThrowingSupplier, exceptionHandler); + } + catch (IllegalStateException expected) { + + assertThat(expected).hasMessage("test"); + assertThat(expected).hasCauseInstanceOf(RuntimeException.class); + assertThat(expected.getCause()).hasMessage("error"); + assertThat(expected.getCause()).hasNoCause(); + + throw expected; + } + } }