From 1bd20457ee0adbdce320de01511c9852b4feac5d Mon Sep 17 00:00:00 2001 From: John Blum Date: Thu, 9 May 2019 22:53:29 -0700 Subject: [PATCH] DATAGEODE-184 - Apply RegionConfigurers to Caching-defined Regions. --- .../CachingDefinedRegionsConfiguration.java | 27 ++++ .../EntityDefinedRegionsConfiguration.java | 13 -- ...liesRegionConfigurersIntegrationTests.java | 119 ++++++++++++++++++ .../EnableCachingDefinedRegionsUnitTests.java | 16 +++ 4 files changed, 162 insertions(+), 13 deletions(-) create mode 100644 src/test/java/org/springframework/data/gemfire/config/annotation/CachingDefinedRegionsAppliesRegionConfigurersIntegrationTests.java diff --git a/src/main/java/org/springframework/data/gemfire/config/annotation/CachingDefinedRegionsConfiguration.java b/src/main/java/org/springframework/data/gemfire/config/annotation/CachingDefinedRegionsConfiguration.java index 181a5f09..b81767cf 100644 --- a/src/main/java/org/springframework/data/gemfire/config/annotation/CachingDefinedRegionsConfiguration.java +++ b/src/main/java/org/springframework/data/gemfire/config/annotation/CachingDefinedRegionsConfiguration.java @@ -20,6 +20,7 @@ import static java.util.Arrays.asList; import static java.util.Arrays.stream; import static org.springframework.data.gemfire.util.ArrayUtils.asArray; 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.StreamUtils.concat; import java.lang.annotation.Annotation; @@ -30,6 +31,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; @@ -47,6 +49,8 @@ import org.apache.geode.cache.client.ClientRegionShortcut; import org.apache.geode.cache.client.Pool; import org.springframework.beans.BeanInstantiationException; import org.springframework.beans.BeansException; +import org.springframework.beans.factory.ListableBeanFactory; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.config.BeanPostProcessor; import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.cache.annotation.CacheEvict; @@ -113,6 +117,9 @@ public class CachingDefinedRegionsConfiguration extends AbstractAnnotationConfig private ClientRegionShortcut clientRegionShortcut = ClientRegionShortcut.PROXY; + @Autowired(required = false) + private List regionConfigurers = Collections.emptyList(); + private RegionShortcut serverRegionShortcut = RegionShortcut.PARTITION; private String poolName = ClientRegionFactoryBean.DEFAULT_POOL_NAME; @@ -303,6 +310,7 @@ public class CachingDefinedRegionsConfiguration extends AbstractAnnotationConfig regionFactoryBean.setCache(gemfireCache); regionFactoryBean.setClientRegionShortcut(resolveClientRegionShortcut()); + regionFactoryBean.setRegionConfigurers(resolveRegionConfigurers()); regionFactoryBean.setRegionName(cacheName); regionFactoryBean.setServerRegionShortcut(resolveServerRegionShortcut()); @@ -327,6 +335,25 @@ public class CachingDefinedRegionsConfiguration extends AbstractAnnotationConfig return beanFactory; } + protected List resolveRegionConfigurers() { + + return Optional.ofNullable(this.regionConfigurers) + .filter(regionConfigurers -> !regionConfigurers.isEmpty()) + .orElseGet(() -> + Optional.of(getBeanFactory()) + .filter(beanFactory -> beanFactory instanceof ListableBeanFactory) + .map(beanFactory -> { + + Map beansOfType = ((ListableBeanFactory) beanFactory) + .getBeansOfType(RegionConfigurer.class, true, false); + + return nullSafeMap(beansOfType).values().stream().collect(Collectors.toList()); + + }) + .orElseGet(Collections::emptyList) + ); + } + /** * {@link CacheNameResolver} is a {@link FunctionalInterface} declaring a contract for all implementations * used to resolve all cache names declared and used by a Spring application. A resolver typically inspects 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 48a271da..351f38d2 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 @@ -169,7 +169,6 @@ public class EntityDefinedRegionsConfiguration extends AbstractAnnotationConfigS } } - /* (non-Javadoc) */ protected GemFireComponentClassTypeScanner newGemFireComponentClassTypeScanner( AnnotationMetadata importingClassMetadata, AnnotationAttributes enableEntityDefinedRegionsAttributes) { @@ -182,7 +181,6 @@ public class EntityDefinedRegionsConfiguration extends AbstractAnnotationConfigS .withIncludes(resolveRegionAnnotatedPersistentEntityTypeFilters()); } - /* (non-Javadoc) */ protected Set resolveBasePackages(AnnotationMetadata importingClassMetaData, AnnotationAttributes enableEntityDefinedRegionAttributes) { @@ -205,17 +203,14 @@ public class EntityDefinedRegionsConfiguration extends AbstractAnnotationConfigS return resolvedBasePackages; } - /* (non-Javadoc) */ protected Iterable resolveExcludes(AnnotationAttributes enableEntityDefinedRegionsAttributes) { return parseFilters(enableEntityDefinedRegionsAttributes.getAnnotationArray("excludeFilters")); } - /* (non-Javadoc) */ protected Iterable resolveIncludes(AnnotationAttributes enableEntityDefinedRegionsAttributes) { return parseFilters(enableEntityDefinedRegionsAttributes.getAnnotationArray("includeFilters")); } - /* (non-Javadoc) */ @SuppressWarnings("unchecked") protected Iterable resolveRegionAnnotatedPersistentEntityTypeFilters() { @@ -353,7 +348,6 @@ public class EntityDefinedRegionsConfiguration extends AbstractAnnotationConfigS registry.registerBeanDefinition(regionMetadata.getRegionName(), regionFactoryBeanBuilder.getBeanDefinition()); } - /* (non-Javadoc) */ protected List resolveRegionConfigurers() { return Optional.ofNullable(this.regionConfigurers) @@ -373,7 +367,6 @@ public class EntityDefinedRegionsConfiguration extends AbstractAnnotationConfigS ); } - /* (non-Javadoc) */ protected BeanDefinitionBuilder setRegionAttributes(BeanDefinitionBuilder regionFactoryBeanBuilder, RegionBeanDefinitionMetadata regionMetadata) { @@ -464,7 +457,6 @@ public class EntityDefinedRegionsConfiguration extends AbstractAnnotationConfigS : regionMetadata.resolveServerRegionShortcut(DEFAULT_SERVER_REGION_SHORTCUT); } - /* (non-Javadoc) */ protected BeanDefinitionBuilder setClientRegionAttributes(RegionBeanDefinitionMetadata regionMetadata, AnnotationAttributes regionAnnotationAttributes, BeanDefinitionBuilder regionFactoryBeanBuilder) { @@ -478,7 +470,6 @@ public class EntityDefinedRegionsConfiguration extends AbstractAnnotationConfigS return regionFactoryBeanBuilder; } - /* (non-Javadoc) */ protected BeanDefinitionBuilder setPartitionRegionAttributes(RegionBeanDefinitionMetadata regionMetadata, AnnotationAttributes regionAnnotationAttributes, BeanDefinitionBuilder regionFactoryBeanBuilder, BeanDefinitionBuilder regionAttributesFactoryBeanBuilder) { @@ -512,7 +503,6 @@ public class EntityDefinedRegionsConfiguration extends AbstractAnnotationConfigS return regionAttributesFactoryBeanBuilder; } - /* (non-Javadoc) */ protected BeanDefinitionBuilder setFixedPartitionRegionAttributes(AnnotationAttributes regionAnnotationAttributes, BeanDefinitionBuilder partitionAttributesFactoryBeanBuilder) { @@ -549,7 +539,6 @@ public class EntityDefinedRegionsConfiguration extends AbstractAnnotationConfigS return partitionAttributesFactoryBeanBuilder; } - /* (non-Javadoc) */ protected BeanDefinitionBuilder setReplicateRegionAttributes(RegionBeanDefinitionMetadata regionMetadata, AnnotationAttributes regionAnnotationAttributes, BeanDefinitionBuilder regionFactoryBeanBuilder) { @@ -562,7 +551,6 @@ public class EntityDefinedRegionsConfiguration extends AbstractAnnotationConfigS return regionFactoryBeanBuilder; } - /* (non-Javadoc) */ private BeanDefinitionBuilder setPropertyReferenceIfSet(BeanDefinitionBuilder beanDefinitionBuilder, String propertyName, String beanName) { @@ -571,7 +559,6 @@ public class EntityDefinedRegionsConfiguration extends AbstractAnnotationConfigS : beanDefinitionBuilder); } - /* (non-Javadoc) */ private BeanDefinitionBuilder setPropertyValueIfNotDefault(BeanDefinitionBuilder beanDefinitionBuilder, String propertyName, T value, T defaultValue) { diff --git a/src/test/java/org/springframework/data/gemfire/config/annotation/CachingDefinedRegionsAppliesRegionConfigurersIntegrationTests.java b/src/test/java/org/springframework/data/gemfire/config/annotation/CachingDefinedRegionsAppliesRegionConfigurersIntegrationTests.java new file mode 100644 index 00000000..f2d9cb13 --- /dev/null +++ b/src/test/java/org/springframework/data/gemfire/config/annotation/CachingDefinedRegionsAppliesRegionConfigurersIntegrationTests.java @@ -0,0 +1,119 @@ +/* + * Copyright 2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.data.gemfire.config.annotation; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +import org.apache.geode.cache.GemFireCache; +import org.apache.geode.cache.Region; +import org.apache.geode.cache.client.ClientRegionShortcut; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.context.annotation.Bean; +import org.springframework.data.gemfire.client.ClientRegionFactoryBean; +import org.springframework.data.gemfire.test.mock.annotation.EnableGemFireMockObjects; +import org.springframework.stereotype.Service; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringRunner; + +/** + * Integration Tests for {@link EnableCachingDefinedRegions} and {@link CachingDefinedRegionsConfiguration} to assert + * that {@link RegionConfigurer RegionConfigurers} beans are applied to the caching-defined {@link Region Regions}. + * + * @author John Blum + * @see org.junit.Test + * @see org.apache.geode.cache.GemFireCache + * @see org.apache.geode.cache.Region + * @see org.springframework.cache.annotation.Cacheable + * @see org.springframework.data.gemfire.config.annotation.CachingDefinedRegionsConfiguration + * @see org.springframework.data.gemfire.config.annotation.EnableCachingDefinedRegions + * @see org.springframework.data.gemfire.test.mock.annotation.EnableGemFireMockObjects + * @see org.springframework.test.context.ContextConfiguration + * @see org.springframework.test.context.junit4.SpringRunner + * @since 2.2.0 + */ +@RunWith(SpringRunner.class) +@ContextConfiguration +@SuppressWarnings("unused") +public class CachingDefinedRegionsAppliesRegionConfigurersIntegrationTests { + + private static final List configuredRegionNames = Collections.synchronizedList(new ArrayList<>()); + + @Autowired + private GemFireCache clientCache; + + @Test + public void clientCacheContainsCachingDefinedRegions() { + + assertThat(this.clientCache).isNotNull(); + + assertThat(this.clientCache.rootRegions().stream() + .filter(Objects::nonNull) + .map(region -> region.getName()) + .collect(Collectors.toList())).containsExactlyInAnyOrder("TestCacheOne", "TestCacheTwo"); + } + + @Test + public void regionConfigurerWasAppliedToCachingDefinedRegions() { + assertThat(configuredRegionNames).containsExactlyInAnyOrder("TestCacheOne", "TestCacheTwo"); + } + + @ClientCacheApplication + @EnableGemFireMockObjects + @EnableCachingDefinedRegions(clientRegionShortcut = ClientRegionShortcut.LOCAL) + static class TestConfiguration { + + @Bean + TestCacheableService testCacheableService() { + return new TestCacheableService(); + } + + @Bean + RegionConfigurer testRegionConfigurer() { + + return new RegionConfigurer() { + + @Override + public void configure(String beanName, ClientRegionFactoryBean bean) { + configuredRegionNames.add(beanName); + } + }; + } + } + + @Service + static class TestCacheableService { + + @Cacheable("TestCacheOne") + public Object testCacheableOperationOne(String key) { + return "TEST"; + } + + @Cacheable("TestCacheTwo") + public Object testCacheableOperationTwo(String key) { + return "MOCK"; + } + } +} diff --git a/src/test/java/org/springframework/data/gemfire/config/annotation/EnableCachingDefinedRegionsUnitTests.java b/src/test/java/org/springframework/data/gemfire/config/annotation/EnableCachingDefinedRegionsUnitTests.java index d182cf74..303878a2 100644 --- a/src/test/java/org/springframework/data/gemfire/config/annotation/EnableCachingDefinedRegionsUnitTests.java +++ b/src/test/java/org/springframework/data/gemfire/config/annotation/EnableCachingDefinedRegionsUnitTests.java @@ -194,6 +194,8 @@ public class EnableCachingDefinedRegionsUnitTests { when(mockBeanFactory.containsBean(anyString())).thenReturn(false); when(mockBeanFactory.getBean(eq(GemFireCache.class))).thenReturn(mockGemFireCache); + this.configuration.setBeanFactory(mockBeanFactory); + BeanPostProcessor cachingAnnotationsRegionBeanRegistrar = this.configuration.cachingAnnotationsRegionBeanRegistrar(mockBeanFactory); @@ -225,6 +227,8 @@ public class EnableCachingDefinedRegionsUnitTests { doAnswer(invocation -> registeredBeanNames.add(invocation.getArgument(0))).when(mockBeanFactory) .registerSingleton(anyString(), any()); + this.configuration.setBeanFactory(mockBeanFactory); + BeanPostProcessor cachingAnnotationsRegionBeanRegistrar = this.configuration.cachingAnnotationsRegionBeanRegistrar(mockBeanFactory); @@ -256,6 +260,8 @@ public class EnableCachingDefinedRegionsUnitTests { doAnswer(invocation -> registeredBeanNames.add(invocation.getArgument(0))).when(mockBeanFactory) .registerSingleton(anyString(), any()); + this.configuration.setBeanFactory(mockBeanFactory); + BeanPostProcessor cachingAnnotationsRegionBeanRegistrar = this.configuration.cachingAnnotationsRegionBeanRegistrar(mockBeanFactory); @@ -292,6 +298,8 @@ public class EnableCachingDefinedRegionsUnitTests { doAnswer(invocation -> registeredBeanNames.add(invocation.getArgument(0))).when(mockBeanFactory) .registerSingleton(anyString(), any()); + this.configuration.setBeanFactory(mockBeanFactory); + BeanPostProcessor cachingAnnotationsRegionBeanRegistrar = this.configuration.cachingAnnotationsRegionBeanRegistrar(mockBeanFactory); @@ -329,6 +337,8 @@ public class EnableCachingDefinedRegionsUnitTests { doAnswer(invocation -> registeredBeanNames.add(invocation.getArgument(0))).when(mockBeanFactory) .registerSingleton(anyString(), any()); + this.configuration.setBeanFactory(mockBeanFactory); + BeanPostProcessor cachingAnnotationsRegionBeanRegistrar = this.configuration.cachingAnnotationsRegionBeanRegistrar(mockBeanFactory); @@ -375,6 +385,8 @@ public class EnableCachingDefinedRegionsUnitTests { doAnswer(invocation -> registeredBeanNames.add(invocation.getArgument(0))).when(mockBeanFactory) .registerSingleton(anyString(), any()); + this.configuration.setBeanFactory(mockBeanFactory); + BeanPostProcessor cachingAnnotationsRegionBeanRegistrar = this.configuration.cachingAnnotationsRegionBeanRegistrar(mockBeanFactory); @@ -410,6 +422,8 @@ public class EnableCachingDefinedRegionsUnitTests { doAnswer(invocation -> registeredBeanNames.add(invocation.getArgument(0))).when(mockBeanFactory) .registerSingleton(anyString(), any()); + this.configuration.setBeanFactory(mockBeanFactory); + BeanPostProcessor cachingAnnotationsRegionBeanRegistrar = this.configuration.cachingAnnotationsRegionBeanRegistrar(mockBeanFactory); @@ -444,6 +458,8 @@ public class EnableCachingDefinedRegionsUnitTests { doAnswer(invocation -> registeredBeanNames.add(invocation.getArgument(0))).when(mockBeanFactory) .registerSingleton(anyString(), any()); + this.configuration.setBeanFactory(mockBeanFactory); + BeanPostProcessor cachingAnnotationsRegionBeanRegistrar = this.configuration.cachingAnnotationsRegionBeanRegistrar(mockBeanFactory);