DATAGEODE-306 - Refactor logic in Repository classes.

This commit is contained in:
John Blum
2020-09-24 11:43:41 -07:00
parent b751f99524
commit 48735b2711
2 changed files with 111 additions and 62 deletions

View File

@@ -93,8 +93,8 @@ public class GemfireRepositoryConfigurationExtension extends RepositoryConfigura
}
/**
* Adds a property reference to the data store-specific {@link MappingContext} in
* the given {@link BeanDefinitionBuilder bean definition}.
* Adds a property reference to the data store-specific {@link MappingContext}
* in the given {@link BeanDefinitionBuilder bean definition}.
*
* @param builder {@link BeanDefinitionBuilder} used to build the target bean definition.
* @param configurationSource {@link RepositoryConfigurationSource} containing {@link Repository}
@@ -114,6 +114,22 @@ public class GemfireRepositoryConfigurationExtension extends RepositoryConfigura
public void registerBeansForRoot(BeanDefinitionRegistry registry, RepositoryConfigurationSource configurationSource) {
super.registerBeansForRoot(registry, configurationSource);
registerMappingContextForRoot(registry, configurationSource);
}
/**
* Registers a {@link GemfireMappingContext} if a {@link MappingContext} is not already registered in
* the {@link BeanDefinitionRegistry}.
*
* @param registry {@link BeanDefinitionRegistry} containing registered bean definitions.
* @param configurationSource {@link RepositoryConfigurationSource} containing the configuration metadata
* for Apache Geode {@link Repository Repositories}.
* @see org.springframework.data.repository.config.RepositoryConfigurationSource
* @see org.springframework.beans.factory.support.BeanDefinitionRegistry
* @see #noMappingContextIsConfigured(RepositoryConfigurationSource)
*/
private void registerMappingContextForRoot(@NonNull BeanDefinitionRegistry registry,
@NonNull RepositoryConfigurationSource configurationSource) {
if (noMappingContextIsConfigured(configurationSource)) {
registry.registerBeanDefinition(DEFAULT_MAPPING_CONTEXT_BEAN_NAME,
@@ -128,7 +144,7 @@ public class GemfireRepositoryConfigurationExtension extends RepositoryConfigura
* an existing {@link MappingContext} configuration.
* @return a boolean value indicating whether a {@link GemfireMappingContext} has already been configured.
*/
private boolean noMappingContextIsConfigured(RepositoryConfigurationSource configurationSource) {
private boolean noMappingContextIsConfigured(@NonNull RepositoryConfigurationSource configurationSource) {
return !configurationSource.getAttribute(MAPPING_CONTEXT_REF_ATTRIBUTE_NAME).isPresent();
}
}

View File

@@ -20,6 +20,7 @@ import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.WeakHashMap;
@@ -35,10 +36,12 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.OrderComparator;
import org.springframework.data.gemfire.mapping.GemfireMappingContext;
import org.springframework.data.gemfire.mapping.GemfirePersistentEntity;
import org.springframework.data.gemfire.mapping.GemfirePersistentProperty;
import org.springframework.data.gemfire.repository.query.GemfireRepositoryQuery;
import org.springframework.data.gemfire.repository.query.QueryPostProcessor;
import org.springframework.data.gemfire.util.CollectionUtils;
import org.springframework.data.mapping.context.MappingContext;
import org.springframework.data.repository.Repository;
import org.springframework.data.repository.RepositoryDefinition;
@@ -48,25 +51,31 @@ import org.springframework.data.repository.core.support.RepositoryFactorySupport
import org.springframework.data.util.ClassTypeInformation;
import org.springframework.data.util.TypeInformation;
import org.springframework.lang.NonNull;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
/**
* {@link FactoryBean} adapter for {@link GemfireRepositoryFactory}.
* Spring {@link FactoryBean} adapter for {@link GemfireRepositoryFactory}.
*
* @author Oliver Gierke
* @author John Blum
* @see org.apache.geode.cache.GemFireCache
* @see org.apache.geode.cache.Region
* @see org.springframework.beans.factory.FactoryBean
* @see org.springframework.context.ApplicationContext
* @see org.springframework.context.ApplicationContextAware
* @see org.springframework.data.gemfire.mapping.GemfireMappingContext
* @see org.springframework.data.gemfire.mapping.GemfirePersistentEntity
* @see org.springframework.data.gemfire.mapping.GemfirePersistentProperty
* @see org.springframework.data.gemfire.repository.query.GemfireRepositoryQuery
* @see org.springframework.data.gemfire.repository.query.QueryPostProcessor
* @see org.springframework.data.mapping.context.MappingContext
* @see org.springframework.data.repository.Repository
* @see org.springframework.data.repository.RepositoryDefinition
* @see org.springframework.data.repository.core.support.QueryCreationListener
* @see org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport
* @see org.springframework.data.repository.core.support.RepositoryFactorySupport
* @see org.apache.geode.cache.Region
*/
public class GemfireRepositoryFactoryBean<T extends Repository<S, ID>, S, ID>
extends RepositoryFactoryBeanSupport<T, S, ID> implements ApplicationContextAware {
@@ -80,10 +89,12 @@ public class GemfireRepositoryFactoryBean<T extends Repository<S, ID>, S, ID>
private MappingContext<? extends GemfirePersistentEntity<?>, GemfirePersistentProperty> mappingContext;
/**
* Creates a new {@link GemfireRepositoryFactoryBean} for the given {@link Repository} {@link Class interface}.
* Constructs a new instance of {@link GemfireRepositoryFactoryBean} initialized with the given {@link Repository}
* {@link Class interface}.
*
* @param repositoryInterface {@link Class interface type} specifying the application data access operations
* contract; must not be {@literal null}.
* @param repositoryInterface {@link Class interface} specifying the application data access operations contract;
* must not be {@literal null}.
* @throws IllegalArgumentException if the {@link Repository} {@link Class interface} is {@literal null}.
* @see java.lang.Class
*/
public GemfireRepositoryFactoryBean(Class<? extends T> repositoryInterface) {
@@ -98,20 +109,8 @@ public class GemfireRepositoryFactoryBean<T extends Repository<S, ID>, S, ID>
* @see org.springframework.context.ApplicationContext
*/
@Override
@SuppressWarnings("rawtypes")
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
public void setApplicationContext(@Nullable ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
Map<String, Region> regionBeans = applicationContext.getBeansOfType(Region.class);
Set<Region<?, ?>> regions = new HashSet<>(Collections.unmodifiableSet(regionBeans.entrySet().stream()
.<Region<?, ?>>map(Map.Entry::getValue)
.collect(Collectors.toSet())));
getCache().map(GemFireCache::rootRegions).ifPresent(regions::addAll);
this.regions = regions;
}
/**
@@ -126,19 +125,19 @@ public class GemfireRepositoryFactoryBean<T extends Repository<S, ID>, S, ID>
}
/**
* Set a reference to the {@link GemFireCache}.
* Set a reference to the Apache Geode {@link GemFireCache}.
*
* @param cache reference to the {@link GemFireCache}.
* @param cache reference to the Apache Geode {@link GemFireCache}.
* @see org.apache.geode.cache.GemFireCache
*/
public void setCache(GemFireCache cache) {
public void setCache(@Nullable GemFireCache cache) {
this.cache = cache;
}
/**
* Returns an {@link Optional} reference to the configured {@link GemFireCache}.
* Returns an {@link Optional} reference to the configured Apache Geode {@link GemFireCache}.
*
* @return an {@link Optional} reference to the configured {@link GemFireCache}.
* @return an {@link Optional} reference to the configured Apache Geode {@link GemFireCache}.
* @see org.apache.geode.cache.GemFireCache
*/
protected Optional<GemFireCache> getCache() {
@@ -153,7 +152,7 @@ public class GemfireRepositoryFactoryBean<T extends Repository<S, ID>, S, ID>
* @see org.springframework.data.mapping.context.MappingContext
*/
@Autowired(required = false)
public void setGemfireMappingContext(MappingContext<? extends GemfirePersistentEntity<?>, GemfirePersistentProperty> mappingContext) {
public void setGemfireMappingContext(@Nullable MappingContext<? extends GemfirePersistentEntity<?>, GemfirePersistentProperty> mappingContext) {
setMappingContext(mappingContext);
this.mappingContext = mappingContext;
}
@@ -167,43 +166,69 @@ public class GemfireRepositoryFactoryBean<T extends Repository<S, ID>, S, ID>
* @see org.springframework.data.mapping.context.MappingContext
* @see #setGemfireMappingContext(MappingContext)
*/
protected MappingContext<? extends GemfirePersistentEntity<?>, GemfirePersistentProperty> getGemfireMappingContext() {
protected @Nullable MappingContext<? extends GemfirePersistentEntity<?>, GemfirePersistentProperty> getGemfireMappingContext() {
return this.mappingContext;
}
/**
* Attempts to resolve the {@link MappingContext} used to map {@link GemfirePersistentEntity entities}
* to Pivotal GemFire.
*
* @return a reference to the resolved {@link MappingContext}.
* @throws IllegalStateException if the {@link MappingContext} cannot be resolved.
* @see org.springframework.data.gemfire.mapping.GemfireMappingContext
* @see org.springframework.data.mapping.context.MappingContext
*/
private MappingContext<? extends GemfirePersistentEntity<?>, GemfirePersistentProperty> resolveGemfireMappingContext() {
MappingContext<? extends GemfirePersistentEntity<?>, GemfirePersistentProperty> mappingContext =
getGemfireMappingContext();
Assert.state(mappingContext != null, "GemfireMappingContext must not be null");
return mappingContext;
}
/**
* Returns an {@link Iterable} reference to the {@link Region Regions}
* defined in the Spring {@link ApplicationContext}.
* Returns an {@link Iterable} of {@link Region Regions}defined in the Spring {@link ApplicationContext}.
*
* @return a reference to all {@link Region Regions} defined in the Spring {@link ApplicationContext}.
* @see org.apache.geode.cache.Region
* @see java.lang.Iterable
*/
protected Iterable<Region<?, ?>> getRegions() {
return this.regions;
Iterable<Region<?, ?>> regions = this.regions;
return regions != null ? regions : CollectionUtils.emptyIterable();
}
/**
* Creates an instance of {@link RepositoryFactorySupport} that interfaces with GemFire.
* Initializes the {@link GemfireRepositoryFactoryBean} by configuring {@link Region Regions} and resolving
* the {@link GemfireMappingContext}.
*
* @see #configureRegions()
* @see #resolveGemfireMappingContext()
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
*/
@Override
public void afterPropertiesSet() {
configureRegions();
resolveGemfireMappingContext();
super.afterPropertiesSet();
}
/**
* Configures a reference to a {@link Set} of all {@link Region Regions} defined, declared and registered in
* the Spring {@link ApplicationContext} as well as in the Apache Geode {@link GemFireCache}.
*/
protected void configureRegions() {
Set<Region<?, ?>> regions = new HashSet<>();
getApplicationContext()
.map(applicationContext -> applicationContext.getBeansOfType(Region.class))
.map(Map::values)
.orElseGet(Collections::emptySet)
.stream()
.filter(Objects::nonNull)
.forEach(regions::add);
getCache()
.map(GemFireCache::rootRegions)
.orElseGet(Collections::emptySet)
.stream()
.filter(Objects::nonNull)
.forEach(regions::add);
this.regions = Collections.unmodifiableSet(regions);
}
/**
* Creates a new instance of {@link GemfireRepositoryFactory} used to create an Apache Geode {@link Repository}.
*
* @see org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport#createRepositoryFactory()
* @see org.springframework.data.repository.core.support.RepositoryFactorySupport
@@ -221,14 +246,23 @@ public class GemfireRepositoryFactoryBean<T extends Repository<S, ID>, S, ID>
return repositoryFactory;
}
/*
* (non-Javadoc)
* @see org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport#afterPropertiesSet()
/**
* Attempts to resolve the {@link MappingContext} used to map {@link GemfirePersistentEntity entities}
* to Apache Geode.
*
* @return a reference to the resolved {@link MappingContext}.
* @throws IllegalStateException if the {@link MappingContext} cannot be resolved.
* @see org.springframework.data.gemfire.mapping.GemfireMappingContext
* @see org.springframework.data.mapping.context.MappingContext
*/
@Override
public void afterPropertiesSet() {
resolveGemfireMappingContext();
super.afterPropertiesSet();
protected MappingContext<? extends GemfirePersistentEntity<?>, GemfirePersistentProperty> resolveGemfireMappingContext() {
MappingContext<? extends GemfirePersistentEntity<?>, GemfirePersistentProperty> mappingContext =
getGemfireMappingContext();
Assert.state(mappingContext != null, "GemfireMappingContext must not be null");
return mappingContext;
}
protected class QueryPostProcessorRegistrationOnQueryCreationListener
@@ -298,14 +332,12 @@ public class GemfireRepositoryFactoryBean<T extends Repository<S, ID>, S, ID>
.orElse((Class) Repository.class);
}
@NonNull
Class<?> getDeclaredRepositoryType() {
@NonNull Class<?> getDeclaredRepositoryType() {
return this.declaredRepositoryType;
}
@NonNull
@SuppressWarnings("unchecked")
QueryPostProcessor<?, String> getQueryPostProcessor() {
@NonNull QueryPostProcessor<?, String> getQueryPostProcessor() {
return (QueryPostProcessor<?, String>) this.queryPostProcessor;
}
@@ -364,6 +396,7 @@ public class GemfireRepositoryFactoryBean<T extends Repository<S, ID>, S, ID>
int hashValue = 17;
hashValue = 37 * hashValue + ObjectUtils.nullSafeHashCode(this.getQueryPostProcessor());
return hashValue;
}