Improves auto-confiuguration of GemfireTemplates for cache Regions to minimize issues when auto-wiring templates into application components.
Resolves gh-55.
This commit is contained in:
@@ -15,19 +15,30 @@
|
||||
*/
|
||||
package org.springframework.geode.boot.autoconfigure;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import org.apache.geode.cache.GemFireCache;
|
||||
import org.apache.geode.cache.Region;
|
||||
import org.apache.geode.internal.concurrent.ConcurrentHashSet;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.PropertyValue;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.beans.factory.config.SingletonBeanRegistry;
|
||||
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
||||
import org.springframework.beans.factory.config.ConstructorArgumentValues;
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
@@ -38,8 +49,18 @@ import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.event.ContextRefreshedEvent;
|
||||
import org.springframework.context.event.EventListener;
|
||||
import org.springframework.core.type.StandardMethodMetadata;
|
||||
import org.springframework.data.gemfire.GemfireOperations;
|
||||
import org.springframework.data.gemfire.GemfireTemplate;
|
||||
import org.springframework.data.gemfire.GemfireUtils;
|
||||
import org.springframework.data.gemfire.ResolvableRegionFactoryBean;
|
||||
import org.springframework.data.gemfire.config.xml.GemfireConstants;
|
||||
import org.springframework.data.gemfire.util.ArrayUtils;
|
||||
import org.springframework.data.gemfire.util.CollectionUtils;
|
||||
import org.springframework.data.gemfire.util.SpringUtils;
|
||||
import org.springframework.geode.config.annotation.support.TypelessAnnotationConfigSupport;
|
||||
import org.springframework.lang.NonNull;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
@@ -48,13 +69,26 @@ import org.springframework.util.StringUtils;
|
||||
* the Spring {@link ConfigurableApplicationContext} in order to perform {@link Region} data access operations.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.apache.geode.cache.GemFireCache
|
||||
* @see org.apache.geode.cache.Region
|
||||
* @see org.springframework.beans.factory.BeanFactory
|
||||
* @see org.springframework.beans.factory.config.BeanDefinition
|
||||
* @see org.springframework.beans.factory.config.BeanFactoryPostProcessor
|
||||
* @see org.springframework.beans.factory.config.BeanPostProcessor
|
||||
* @see org.springframework.beans.factory.config.SingletonBeanRegistry
|
||||
* @see org.springframework.beans.factory.config.ConfigurableBeanFactory
|
||||
* @see org.springframework.beans.factory.support.BeanDefinitionBuilder
|
||||
* @see org.springframework.beans.factory.support.BeanDefinitionRegistry
|
||||
* @see org.springframework.boot.autoconfigure.AutoConfigureAfter
|
||||
* @see org.springframework.boot.autoconfigure.condition.ConditionalOnBean
|
||||
* @see org.springframework.boot.autoconfigure.condition.ConditionalOnClass
|
||||
* @see org.springframework.context.ApplicationContext
|
||||
* @see org.springframework.context.ConfigurableApplicationContext
|
||||
* @see org.springframework.context.annotation.Bean
|
||||
* @see org.springframework.context.annotation.Configuration
|
||||
* @see org.springframework.context.event.EventListener
|
||||
* @see org.springframework.data.gemfire.GemfireTemplate
|
||||
* @see org.springframework.data.gemfire.ResolvableRegionFactoryBean
|
||||
* @see org.springframework.geode.config.annotation.support.TypelessAnnotationConfigSupport
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Configuration
|
||||
@@ -62,79 +96,237 @@ import org.springframework.util.StringUtils;
|
||||
@ConditionalOnBean(GemFireCache.class)
|
||||
@ConditionalOnClass(GemfireTemplate.class)
|
||||
@SuppressWarnings("unused")
|
||||
public class RegionTemplateAutoConfiguration {
|
||||
public class RegionTemplateAutoConfiguration extends TypelessAnnotationConfigSupport {
|
||||
|
||||
private static final Set<String> regionTemplateNames = new ConcurrentHashSet<>();
|
||||
private static final Object NON_BEAN = new Object();
|
||||
|
||||
private String toRegionTemplateName(String regionName) {
|
||||
return StringUtils.uncapitalize(regionName) + "Template";
|
||||
private static final String TEMPLATE = "Template";
|
||||
|
||||
private final Set<String> autoConfiguredRegionTemplateBeanNames = Collections.synchronizedSet(new HashSet<>());
|
||||
private final Set<String> regionNamesWithTemplates = Collections.synchronizedSet(new HashSet<>());
|
||||
|
||||
@Bean
|
||||
BeanFactoryPostProcessor regionTemplateBeanFactoryPostProcessor() {
|
||||
|
||||
return beanFactory -> {
|
||||
|
||||
if (beanFactory instanceof BeanDefinitionRegistry) {
|
||||
|
||||
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
|
||||
|
||||
List<String> beanDefinitionNames =
|
||||
Arrays.asList(ArrayUtils.nullSafeArray(registry.getBeanDefinitionNames(), String.class));
|
||||
|
||||
Set<String> userRegionTemplateNames = new HashSet<>();
|
||||
|
||||
for (String beanName : beanDefinitionNames) {
|
||||
|
||||
String regionTemplateBeanName = toRegionTemplateBeanName(beanName);
|
||||
|
||||
if (!beanDefinitionNames.contains(regionTemplateBeanName)) {
|
||||
|
||||
BeanDefinition beanDefinition = registry.getBeanDefinition(beanName);
|
||||
|
||||
Class<?> resolvedBeanType = resolveBeanClass(beanDefinition, registry).orElse(null);
|
||||
|
||||
if (isRegionBeanDefinition(resolvedBeanType)) {
|
||||
register(newGemfireTemplateBeanDefinition(beanName), regionTemplateBeanName, registry);
|
||||
}
|
||||
else if (isGemfireTemplateBeanDefinition(resolvedBeanType)) {
|
||||
userRegionTemplateNames.add(beanName);
|
||||
}
|
||||
else if (isBeanWithGemfireTemplateDependency(beanFactory, beanDefinition)) {
|
||||
SpringUtils.addDependsOn(beanDefinition, GemfireConstants.DEFAULT_GEMFIRE_CACHE_NAME);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setAutoConfiguredRegionTemplateDependencies(registry, userRegionTemplateNames);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private boolean isBeanWithGemfireTemplateDependency(@NonNull BeanFactory beanFactory,
|
||||
@NonNull BeanDefinition beanDefinition) {
|
||||
|
||||
Predicate<Object> isGemfireTemplate = value -> value instanceof RuntimeBeanReference
|
||||
? beanFactory.isTypeMatch(((RuntimeBeanReference) value).getBeanName(), GemfireOperations.class)
|
||||
: value instanceof GemfireOperations;
|
||||
|
||||
boolean match = beanDefinition.getConstructorArgumentValues().getGenericArgumentValues().stream()
|
||||
.map(ConstructorArgumentValues.ValueHolder::getValue)
|
||||
.anyMatch(isGemfireTemplate);
|
||||
|
||||
match |= match || beanDefinition.getPropertyValues().getPropertyValueList().stream()
|
||||
.map(PropertyValue::getValue)
|
||||
.anyMatch(isGemfireTemplate);
|
||||
|
||||
match |= match || Optional.of(beanDefinition)
|
||||
.filter(AnnotatedBeanDefinition.class::isInstance)
|
||||
.map(AnnotatedBeanDefinition.class::cast)
|
||||
.map(AnnotatedBeanDefinition::getFactoryMethodMetadata)
|
||||
.filter(StandardMethodMetadata.class::isInstance)
|
||||
.map(StandardMethodMetadata.class::cast)
|
||||
.map(StandardMethodMetadata::getIntrospectedMethod)
|
||||
.map(method -> Arrays.stream(ArrayUtils.nullSafeArray(method.getParameterTypes(), Class.class))
|
||||
.filter(Objects::nonNull)
|
||||
.anyMatch(GemfireOperations.class::isAssignableFrom)
|
||||
).orElse(false);
|
||||
|
||||
return match;
|
||||
}
|
||||
|
||||
private boolean isGemfireTemplateBeanDefinition(@Nullable Class<?> beanType) {
|
||||
return beanType != null && GemfireOperations.class.isAssignableFrom(beanType);
|
||||
}
|
||||
|
||||
private boolean isRegionBeanDefinition(@Nullable Class<?> beanType) {
|
||||
return beanType != null && ResolvableRegionFactoryBean.class.isAssignableFrom(beanType);
|
||||
}
|
||||
|
||||
private BeanDefinition newGemfireTemplateBeanDefinition(String regionBeanName) {
|
||||
|
||||
BeanDefinitionBuilder builder =
|
||||
BeanDefinitionBuilder.genericBeanDefinition(GemfireTemplate.class);
|
||||
|
||||
builder.addConstructorArgReference(regionBeanName);
|
||||
|
||||
return builder.getBeanDefinition();
|
||||
}
|
||||
|
||||
// Register BeanDefinition with bean name in BeanDefinitionRegistry
|
||||
private boolean register(BeanDefinition beanDefinition, String beanName, BeanDefinitionRegistry registry) {
|
||||
|
||||
if (this.autoConfiguredRegionTemplateBeanNames.add(beanName)) {
|
||||
registry.registerBeanDefinition(beanName, beanDefinition);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void setAutoConfiguredRegionTemplateDependencies(BeanDefinitionRegistry registry,
|
||||
Set<String> dependencyBeanNames) {
|
||||
|
||||
String[] dependencyBeanNamesArray = dependencyBeanNames.toArray(new String[0]);
|
||||
|
||||
this.autoConfiguredRegionTemplateBeanNames.stream()
|
||||
.map(registry::getBeanDefinition)
|
||||
.forEach(beanDefinition -> SpringUtils.addDependsOn(beanDefinition, dependencyBeanNamesArray));
|
||||
}
|
||||
|
||||
// Required by @EnableClusterDefinedRegions & Native-Defined Regions (e.g. Regions defined in "cache.xml").
|
||||
@Bean
|
||||
BeanPostProcessor regionTemplateBeanPostProcessor(ConfigurableApplicationContext applicationContext) {
|
||||
|
||||
handlePrematureCacheCreation(applicationContext);
|
||||
|
||||
return new BeanPostProcessor() {
|
||||
|
||||
@Override
|
||||
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
|
||||
/**
|
||||
* User-defined {@link GemfireTemplate} beans should be post processed before
|
||||
* auto-configured {@link GemfireTemplate} beans!
|
||||
*
|
||||
* @see RegionTemplateAutoConfiguration#setAutoConfiguredRegionTemplateDependencies(BeanDefinitionRegistry, Set)
|
||||
*/
|
||||
@Nullable @Override
|
||||
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
|
||||
|
||||
if (bean instanceof Region) {
|
||||
|
||||
String regionTemplateName = toRegionTemplateName(beanName);
|
||||
|
||||
registerRegionTemplateBean(regionTemplateName, bean);
|
||||
if (bean instanceof GemfireTemplate) {
|
||||
if (autoConfiguredRegionTemplateBeanNames.contains(beanName)) {
|
||||
if (regionNamesWithTemplates.contains(((GemfireTemplate) bean).getRegion().getName())) {
|
||||
// Returning NO_BEAN means an existing, user-defined GemfireTemplate bean already exists
|
||||
// for the target Region and the auto-configured GemfireTemplate bean is not required.
|
||||
bean = NON_BEAN;
|
||||
}
|
||||
}
|
||||
else {
|
||||
regionNamesWithTemplates.add(((GemfireTemplate) bean).getRegion().getName());
|
||||
}
|
||||
}
|
||||
|
||||
return bean;
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private void registerRegionTemplateBean(String regionTemplateName, Object bean) {
|
||||
@Override
|
||||
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
|
||||
|
||||
Optional.ofNullable(applicationContext)
|
||||
.filter(it -> bean instanceof Region)
|
||||
.filter(it -> !it.containsBean(regionTemplateName))
|
||||
.filter(it -> isGemfireTemplateWithRegionNotPresent(it, (Region) bean))
|
||||
.map(ConfigurableApplicationContext::getBeanFactory)
|
||||
.filter(SingletonBeanRegistry.class::isInstance)
|
||||
.map(SingletonBeanRegistry.class::cast)
|
||||
.ifPresent(beanFactory -> {
|
||||
beanFactory.registerSingleton(regionTemplateName, new GemfireTemplate((Region) bean));
|
||||
regionTemplateNames.add(regionTemplateName);
|
||||
});
|
||||
if (bean instanceof GemFireCache) {
|
||||
|
||||
GemFireCache cache = (GemFireCache) bean;
|
||||
|
||||
registerRegionTemplatesForCacheRegions(applicationContext, cache);
|
||||
}
|
||||
|
||||
return bean;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// TODO: Remove this logic when DATAGEODE-231 is resolved!
|
||||
private void handlePrematureCacheCreation(ConfigurableApplicationContext applicationContext) {
|
||||
|
||||
Optional.ofNullable(GemfireUtils.resolveGemFireCache())
|
||||
.ifPresent(cache -> registerRegionTemplatesForCacheRegions(applicationContext, cache));
|
||||
}
|
||||
|
||||
// Required by @EnableCachingDefinedRegions
|
||||
@EventListener({ ContextRefreshedEvent.class })
|
||||
public void registerRemainingRegionTemplatesOnContextRefresh(ContextRefreshedEvent event) {
|
||||
public void regionTemplateContextRefreshedEventListener(ContextRefreshedEvent event) {
|
||||
|
||||
this.regionNamesWithTemplates.clear();
|
||||
|
||||
ApplicationContext applicationContext = event.getApplicationContext();
|
||||
|
||||
if (applicationContext instanceof ConfigurableApplicationContext) {
|
||||
|
||||
ConfigurableListableBeanFactory beanFactory =
|
||||
((ConfigurableApplicationContext) applicationContext).getBeanFactory();
|
||||
ConfigurableApplicationContext configurableApplicationContext =
|
||||
(ConfigurableApplicationContext) applicationContext;
|
||||
|
||||
Optional.ofNullable(applicationContext.getBean(GemFireCache.class))
|
||||
.map(GemFireCache::rootRegions)
|
||||
.ifPresent(rootRegions -> rootRegions.stream()
|
||||
.filter(Objects::nonNull)
|
||||
.filter(region -> !regionTemplateNames.contains(toRegionTemplateName(region.getName())))
|
||||
.filter(region -> !applicationContext.containsBean(toRegionTemplateName(region.getName())))
|
||||
.filter(region -> isGemfireTemplateWithRegionNotPresent(applicationContext, region))
|
||||
.forEach(region -> beanFactory.registerSingleton(toRegionTemplateName(region.getName()),
|
||||
new GemfireTemplate(region))));
|
||||
GemFireCache cache = configurableApplicationContext.getBean(GemFireCache.class);
|
||||
|
||||
registerRegionTemplatesForCacheRegions(configurableApplicationContext, cache);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isGemfireTemplateWithRegionNotPresent(ApplicationContext applicationContext, Region region) {
|
||||
private void registerRegionTemplatesForCacheRegions(@NonNull ConfigurableApplicationContext applicationContext,
|
||||
@NonNull GemFireCache cache) {
|
||||
|
||||
Map<String, GemfireTemplate> gemfireTemplateBeans =
|
||||
applicationContext.getBeansOfType(GemfireTemplate.class, false, false);
|
||||
for (Region region : CollectionUtils.nullSafeSet(cache.rootRegions())) {
|
||||
|
||||
return CollectionUtils.nullSafeMap(gemfireTemplateBeans).values().stream()
|
||||
.map(GemfireTemplate::getRegion)
|
||||
.noneMatch(templateRegion -> templateRegion.equals(region));
|
||||
String regionTemplateBeanName = toRegionTemplateBeanName(region.getName());
|
||||
|
||||
registerRegionTemplateBean(applicationContext, region, regionTemplateBeanName);
|
||||
}
|
||||
}
|
||||
|
||||
private void registerRegionTemplateBean(@NonNull ConfigurableApplicationContext applicationContext,
|
||||
@NonNull Region region, String regionTemplateBeanName) {
|
||||
|
||||
Optional.of(applicationContext)
|
||||
.filter(it -> isNotBean(it, regionTemplateBeanName))
|
||||
.map(ConfigurableApplicationContext::getBeanFactory)
|
||||
.ifPresent(beanFactory -> register(newGemfireTemplate(region), regionTemplateBeanName, beanFactory));
|
||||
}
|
||||
|
||||
private boolean isNotBean(@NonNull ApplicationContext applicationContext, @Nullable String beanName) {
|
||||
return !(StringUtils.hasText(beanName) && applicationContext.containsBean(beanName));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private GemfireTemplate newGemfireTemplate(@NonNull Region region) {
|
||||
return new GemfireTemplate(region);
|
||||
}
|
||||
|
||||
// Register Singleton Object with bean name in BeanDefinitionRegistry
|
||||
private void register(Object singletonObject, String beanName, ConfigurableBeanFactory beanFactory) {
|
||||
|
||||
if (this.autoConfiguredRegionTemplateBeanNames.add(beanName)) {
|
||||
beanFactory.registerSingleton(beanName, singletonObject);
|
||||
}
|
||||
}
|
||||
|
||||
private String toRegionTemplateBeanName(@NonNull String regionName) {
|
||||
return StringUtils.uncapitalize(regionName) + TEMPLATE;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,6 +102,10 @@ public class CachingDefinedRegionTemplateAutoConfigurationIntegrationTests exten
|
||||
.map(Region::getName)
|
||||
.sorted()
|
||||
.collect(Collectors.toList())).containsExactly("BooksByAuthor", "BooksByYear", "CachedBooks");
|
||||
|
||||
assertThat(this.booksByAuthor).isNotNull();
|
||||
assertThat(this.booksByTitle).isNotNull();
|
||||
assertThat(this.booksByYear).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -134,5 +138,10 @@ public class CachingDefinedRegionTemplateAutoConfigurationIntegrationTests exten
|
||||
LibraryService libraryService() {
|
||||
return new LibraryService();
|
||||
}
|
||||
|
||||
//@Bean("TestBean")
|
||||
Object testBean(@Qualifier("booksByAuthor") GemfireTemplate booksByAuthorTemplate) {
|
||||
return "TEST";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* Copyright 2019 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
|
||||
*
|
||||
* https://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.geode.boot.autoconfigure.template;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import org.apache.geode.cache.GemFireCache;
|
||||
import org.apache.geode.cache.Region;
|
||||
import org.apache.geode.cache.client.ClientCache;
|
||||
import org.apache.geode.cache.client.ClientRegionShortcut;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.data.gemfire.GemfireTemplate;
|
||||
import org.springframework.data.gemfire.client.ClientRegionFactoryBean;
|
||||
import org.springframework.data.gemfire.tests.integration.IntegrationTestsSupport;
|
||||
import org.springframework.data.gemfire.tests.mock.annotation.EnableGemFireMockObjects;
|
||||
import org.springframework.data.gemfire.util.RegionUtils;
|
||||
import org.springframework.geode.boot.autoconfigure.RegionTemplateAutoConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
/**
|
||||
* Integration Tests for {@link RegionTemplateAutoConfiguration}.
|
||||
*
|
||||
* This Integration Test class tests that the {@link GemfireTemplate} is created regardless of whether
|
||||
* the {@literal Example} client {@link Region} bean is actually referenced (injected) into application code.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.junit.Test
|
||||
* @see org.apache.geode.cache.GemFireCache
|
||||
* @see org.apache.geode.cache.Region
|
||||
* @see org.apache.geode.cache.client.ClientCache
|
||||
* @see org.springframework.boot.autoconfigure.SpringBootApplication
|
||||
* @see org.springframework.boot.test.context.SpringBootTest
|
||||
* @see org.springframework.data.gemfire.GemfireTemplate
|
||||
* @see org.springframework.data.gemfire.client.ClientRegionFactoryBean
|
||||
* @see org.springframework.data.gemfire.tests.mock.annotation.EnableGemFireMockObjects
|
||||
* @see org.springframework.data.gemfire.tests.integration.IntegrationTestsSupport
|
||||
* @see org.springframework.geode.boot.autoconfigure.RegionTemplateAutoConfiguration
|
||||
* @see org.springframework.test.context.junit4.SpringRunner
|
||||
* @see <a href="https://github.com/spring-projects/spring-boot-data-geode/issues/55">Autowiring a GemfireTemplate into the application is not working in all cases</a>
|
||||
* @since 1.2.0
|
||||
*/
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE)
|
||||
@SuppressWarnings("unused")
|
||||
public class DeclaredNonInjectedRegionTemplateAutoConfigurationIntegrationTests extends IntegrationTestsSupport {
|
||||
|
||||
@Autowired
|
||||
private ClientCache clientCache;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("exampleTemplate")
|
||||
private GemfireTemplate exampleTemplate;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
|
||||
assertThat(this.clientCache).isNotNull();
|
||||
assertThat(this.exampleTemplate).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void clientCacheContainsExampleRegion() {
|
||||
|
||||
Region<?, ?> example = this.clientCache.getRegion(RegionUtils.toRegionPath("Example"));
|
||||
|
||||
assertThat(example).isNotNull();
|
||||
assertThat(example.getName()).isEqualTo("Example");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void exampleRegionTemplateExists() {
|
||||
assertThat(this.exampleTemplate.getRegion())
|
||||
.isEqualTo(this.clientCache.getRegion(RegionUtils.toRegionPath("Example")));
|
||||
}
|
||||
|
||||
@SpringBootApplication
|
||||
@EnableGemFireMockObjects
|
||||
static class TestConfiguration {
|
||||
|
||||
@Bean("Example")
|
||||
public ClientRegionFactoryBean<Object, Object> exampleRegion(GemFireCache gemfireCache) {
|
||||
|
||||
ClientRegionFactoryBean<Object, Object> exampleRegion = new ClientRegionFactoryBean<>();
|
||||
|
||||
exampleRegion.setCache(gemfireCache);
|
||||
exampleRegion.setShortcut(ClientRegionShortcut.LOCAL);
|
||||
|
||||
return exampleRegion;
|
||||
}
|
||||
|
||||
@Bean("TestBean")
|
||||
public Object testBean(@Qualifier("exampleTemplate") GemfireTemplate exampleTemplate) {
|
||||
return "TEST";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -45,10 +45,12 @@ import org.springframework.test.context.junit4.SpringRunner;
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.junit.Test
|
||||
* @see org.apache.geode.cache.GemFireCache
|
||||
* @see org.apache.geode.cache.Region
|
||||
* @see org.springframework.boot.autoconfigure.SpringBootApplication
|
||||
* @see org.springframework.boot.test.context.SpringBootTest
|
||||
* @see org.springframework.data.gemfire.GemfireTemplate
|
||||
* @see org.springframework.data.gemfire.client.ClientRegionFactoryBean
|
||||
* @see org.springframework.data.gemfire.tests.integration.IntegrationTestsSupport
|
||||
* @see org.springframework.data.gemfire.tests.mock.annotation.EnableGemFireMockObjects
|
||||
* @see org.springframework.geode.boot.autoconfigure.RegionTemplateAutoConfiguration
|
||||
@@ -67,6 +69,13 @@ public class DeclaredRegionTemplateAutoConfigurationIntegrationTests extends Int
|
||||
@Resource(name = "Example")
|
||||
private Region<Long, String> exampleRegion;
|
||||
|
||||
@Test
|
||||
public void exampleRegionIsPresent() {
|
||||
|
||||
assertThat(this.exampleRegion).isNotNull();
|
||||
assertThat(this.exampleRegion.getName()).isEqualTo("Example");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void exampleRegionTemplateIsPresent() {
|
||||
|
||||
|
||||
@@ -17,11 +17,15 @@ package org.springframework.geode.boot.autoconfigure.template;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
import org.apache.geode.cache.GemFireCache;
|
||||
import org.apache.geode.cache.Region;
|
||||
import org.apache.geode.cache.client.ClientRegionShortcut;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@@ -29,6 +33,7 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.data.gemfire.GemfireTemplate;
|
||||
import org.springframework.data.gemfire.config.annotation.EnableEntityDefinedRegions;
|
||||
import org.springframework.data.gemfire.tests.integration.IntegrationTestsSupport;
|
||||
@@ -62,6 +67,9 @@ import example.app.books.model.ISBN;
|
||||
@SuppressWarnings("unused")
|
||||
public class EntityDefinedRegionTemplateAutoConfigurationIntegrationTests extends IntegrationTestsSupport {
|
||||
|
||||
@Autowired
|
||||
public GemFireCache gemfireCache;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("authorsTemplate")
|
||||
private GemfireTemplate authorsTemplate;
|
||||
@@ -76,6 +84,20 @@ public class EntityDefinedRegionTemplateAutoConfigurationIntegrationTests extend
|
||||
@Resource(name = "Books")
|
||||
private Region<ISBN, Book> books;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
|
||||
assertThat(this.gemfireCache).isNotNull();
|
||||
|
||||
assertThat(this.gemfireCache.rootRegions().stream()
|
||||
.map(Region::getName)
|
||||
.sorted()
|
||||
.collect(Collectors.toList())).containsExactly("Authors", "Books");
|
||||
|
||||
assertThat(this.authors).isNotNull();
|
||||
assertThat(this.books).isNotNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authorsRegionTemplateIsPresent() {
|
||||
|
||||
@@ -93,6 +115,11 @@ public class EntityDefinedRegionTemplateAutoConfigurationIntegrationTests extend
|
||||
@SpringBootApplication
|
||||
@EnableGemFireMockObjects
|
||||
@EnableEntityDefinedRegions(basePackageClasses = Book.class, clientRegionShortcut = ClientRegionShortcut.LOCAL)
|
||||
static class TestApplicationConfiguration { }
|
||||
static class TestApplicationConfiguration {
|
||||
|
||||
@Bean("TestBean")
|
||||
Object testBean(@Qualifier("booksTemplate") GemfireTemplate booksTemplate) {
|
||||
return "TEST";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,13 +70,19 @@ public class ExistingRegionTemplateByRegionAutoConfigurationIntegrationTests ext
|
||||
private Region<Object, Object> example;
|
||||
|
||||
@Test
|
||||
public void exampleRegionTemplateIsNotPresent() {
|
||||
public void exampleTemplateIsPresentButIsNotGemfireTemplate() {
|
||||
|
||||
assertThat(this.applicationContext.containsBean("exampleTemplate")).isFalse();
|
||||
assertThat(this.applicationContext.containsBean("exampleTemplate")).isTrue();
|
||||
assertThat(this.applicationContext.getBean("exampleTemplate")).isNotInstanceOf(GemfireTemplate.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRegionTemplateIsPresent() {
|
||||
public void onlyOneBeanOfTypeGemfireTemplateExists() {
|
||||
assertThat(this.applicationContext.getBeanNamesForType(GemfireTemplate.class)).hasSize(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTemplateIsPresent() {
|
||||
|
||||
assertThat(this.testTemplate).isNotNull();
|
||||
assertThat(this.testTemplate.getRegion()).isEqualTo(this.example);
|
||||
|
||||
@@ -17,6 +17,9 @@ package org.springframework.geode.boot.autoconfigure.template;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.geode.cache.GemFireCache;
|
||||
import org.apache.geode.cache.Region;
|
||||
|
||||
import org.junit.Test;
|
||||
@@ -24,12 +27,16 @@ import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.DependsOn;
|
||||
import org.springframework.data.gemfire.GemfireTemplate;
|
||||
import org.springframework.data.gemfire.config.annotation.EnableGemFireProperties;
|
||||
import org.springframework.data.gemfire.tests.integration.IntegrationTestsSupport;
|
||||
import org.springframework.data.gemfire.util.CollectionUtils;
|
||||
import org.springframework.geode.boot.autoconfigure.RegionTemplateAutoConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
@@ -56,9 +63,22 @@ public class NativeDefinedRegionTemplateAutoConfigurationIntegrationTests extend
|
||||
@Autowired
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
@Autowired
|
||||
private GemFireCache cache;
|
||||
|
||||
@Autowired
|
||||
private GemfireTemplate exampleTemplate;
|
||||
|
||||
@Test
|
||||
public void cacheContainsExampleRegion() {
|
||||
|
||||
assertThat(this.cache).isNotNull();
|
||||
|
||||
assertThat(CollectionUtils.nullSafeSet(this.cache.rootRegions()).stream()
|
||||
.map(Region::getName)
|
||||
.collect(Collectors.toSet())).containsExactly("Example");
|
||||
}
|
||||
|
||||
@Test(expected = NoSuchBeanDefinitionException.class)
|
||||
public void exampleRegionBeanIsNotPresent() {
|
||||
this.applicationContext.getBean("Example", Region.class);
|
||||
@@ -74,6 +94,12 @@ public class NativeDefinedRegionTemplateAutoConfigurationIntegrationTests extend
|
||||
|
||||
@SpringBootApplication
|
||||
@EnableGemFireProperties(cacheXmlFile = "template-cache.xml")
|
||||
static class TestConfiguration { }
|
||||
static class TestConfiguration {
|
||||
|
||||
@Bean("TestBean")
|
||||
@DependsOn("gemfireCache")
|
||||
Object testBean(@Qualifier("exampleTemplate") GemfireTemplate exampleTemplate) {
|
||||
return "TEST";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,16 +18,19 @@ package org.springframework.geode.boot.autoconfigure.template;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.geode.cache.DataPolicy;
|
||||
import org.apache.geode.cache.GemFireCache;
|
||||
import org.apache.geode.cache.Region;
|
||||
import org.apache.geode.cache.client.ClientCache;
|
||||
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
@@ -39,11 +42,12 @@ import org.springframework.data.gemfire.config.annotation.CacheServerApplication
|
||||
import org.springframework.data.gemfire.config.annotation.EnableClusterDefinedRegions;
|
||||
import org.springframework.data.gemfire.config.annotation.EnableLogging;
|
||||
import org.springframework.data.gemfire.tests.integration.ForkingClientServerIntegrationTestsSupport;
|
||||
import org.springframework.data.gemfire.util.CollectionUtils;
|
||||
import org.springframework.geode.boot.autoconfigure.RegionTemplateAutoConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
/**
|
||||
* Integration tests for {@link RegionTemplateAutoConfiguration} using SDG's {@link EnableServerDefinedRegions}
|
||||
* Integration tests for {@link RegionTemplateAutoConfiguration} using SDG's {@link EnableClusterDefinedRegions}
|
||||
* annotation to define {@link Region Regions} and associated Templates.
|
||||
*
|
||||
* @author John Blum
|
||||
@@ -80,11 +84,24 @@ public class ServerDefinedRegionTemplateAutoConfigurationIntegrationTests
|
||||
@Autowired
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
@Autowired
|
||||
private ClientCache clientCache;
|
||||
|
||||
@Autowired
|
||||
private GemfireTemplate exampleServerRegionTemplate;
|
||||
|
||||
@Test
|
||||
public void exampleServerRegionExistsAsClientRegion() {
|
||||
public void clientCacheContainsExampleServerRegion() {
|
||||
|
||||
assertThat(this.clientCache).isNotNull();
|
||||
|
||||
assertThat(CollectionUtils.nullSafeSet(this.clientCache.rootRegions()).stream()
|
||||
.map(Region::getName)
|
||||
.collect(Collectors.toSet())).containsExactly("ExampleServerRegion");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void exampleServerRegionExistsAsClientRegionBean() {
|
||||
|
||||
Region<?, ?> exampleServerRegion = this.applicationContext.getBean("ExampleServerRegion", Region.class);
|
||||
|
||||
@@ -105,7 +122,13 @@ public class ServerDefinedRegionTemplateAutoConfigurationIntegrationTests
|
||||
@SpringBootApplication
|
||||
@EnableClusterDefinedRegions
|
||||
@EnableLogging(logLevel = GEMFIRE_LOG_LEVEL)
|
||||
static class GemFireClientConfiguration { }
|
||||
static class GemFireClientConfiguration {
|
||||
|
||||
@Bean("TestBean")
|
||||
Object testBean(@Qualifier("exampleServerRegionTemplate") GemfireTemplate exampleServerRegionTemplate) {
|
||||
return "TEST";
|
||||
}
|
||||
}
|
||||
|
||||
@CacheServerApplication(logLevel = GEMFIRE_LOG_LEVEL)
|
||||
static class GemFireServerConfiguration {
|
||||
|
||||
Reference in New Issue
Block a user