SGF-741 - Add support for enforcing Lucene Index creation before Region creation.
This commit is contained in:
@@ -102,9 +102,6 @@ public class IndexFactoryBean extends AbstractFactoryBeanSupport<Index> implemen
|
||||
private String indexName;
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
|
||||
|
||||
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* 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.support;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import org.apache.geode.cache.Region;
|
||||
import org.apache.geode.cache.lucene.LuceneIndex;
|
||||
import org.apache.geode.cache.query.Index;
|
||||
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.core.type.MethodMetadata;
|
||||
import org.springframework.data.gemfire.GenericRegionFactoryBean;
|
||||
import org.springframework.data.gemfire.LocalRegionFactoryBean;
|
||||
import org.springframework.data.gemfire.PartitionedRegionFactoryBean;
|
||||
import org.springframework.data.gemfire.ReplicatedRegionFactoryBean;
|
||||
import org.springframework.data.gemfire.client.ClientCacheFactoryBean;
|
||||
import org.springframework.data.gemfire.client.ClientRegionFactoryBean;
|
||||
import org.springframework.data.gemfire.client.PoolFactoryBean;
|
||||
import org.springframework.data.gemfire.util.SpringUtils;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* The {@link AbstractDependencyStructuringBeanFactoryPostProcessor} class is a Spring {@link BeanFactoryPostProcessor}
|
||||
* post processing the Spring {@link BeanFactory} to help ensure that the dependencies between different Apache Geode
|
||||
* or Pivotal GemFire objects (e.g. {@link Region} and a {@link LuceneIndex} or an OQL {@link Index}) have been
|
||||
* properly declared in order to the lifecycle of those components are upheld according to Apache Geode
|
||||
* or Pivotal GemFire requirements/rules.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.springframework.beans.factory.BeanFactory
|
||||
* @see org.springframework.beans.factory.config.BeanDefinition
|
||||
* @see org.springframework.beans.factory.config.BeanFactoryPostProcessor
|
||||
* @since 2.1.0
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public abstract class AbstractDependencyStructuringBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
|
||||
|
||||
protected BeanDefinition addDependsOn(BeanDefinition beanDefinition, String... beanNames) {
|
||||
return SpringUtils.addDependsOn(beanDefinition, beanNames);
|
||||
}
|
||||
|
||||
protected Optional<Object> getPropertyValue(BeanDefinition beanDefinition, String propertyName) {
|
||||
return SpringUtils.getPropertyValue(beanDefinition, propertyName);
|
||||
}
|
||||
|
||||
protected boolean isBeanDefinitionOfType(BeanDefinition beanDefinition, Class<?> type) {
|
||||
|
||||
Assert.notNull(type, "Class type must not be null");
|
||||
|
||||
return isBeanDefinitionOfType(beanDefinition, typeName -> type.getName().equals(typeName));
|
||||
}
|
||||
|
||||
protected boolean isBeanDefinitionOfType(BeanDefinition beanDefinition, String typeName) {
|
||||
|
||||
return isBeanDefinitionOfType(beanDefinition,
|
||||
typeNameArgument -> String.valueOf(typeName).equals(typeNameArgument));
|
||||
}
|
||||
|
||||
protected boolean isBeanDefinitionOfType(BeanDefinition beanDefinition, Predicate<String> typeFilter) {
|
||||
|
||||
return Optional.of(beanDefinition)
|
||||
.map(it -> beanDefinition.getBeanClassName())
|
||||
.filter(StringUtils::hasText)
|
||||
.map(typeFilter::test)
|
||||
.orElseGet(() ->
|
||||
Optional.ofNullable(beanDefinition.getFactoryMethodName())
|
||||
.filter(StringUtils::hasText)
|
||||
.filter(it -> beanDefinition instanceof AnnotatedBeanDefinition)
|
||||
.map(it -> ((AnnotatedBeanDefinition) beanDefinition).getFactoryMethodMetadata())
|
||||
.map(MethodMetadata::getReturnTypeName)
|
||||
.map(typeFilter::test)
|
||||
.orElse(false)
|
||||
);
|
||||
}
|
||||
|
||||
protected boolean isClientCacheBean(BeanDefinition beanDefinition) {
|
||||
return isBeanDefinitionOfType(beanDefinition, ClientCacheFactoryBean.class);
|
||||
}
|
||||
|
||||
protected boolean isClientRegionBean(BeanDefinition beanDefinition) {
|
||||
return isBeanDefinitionOfType(beanDefinition, ClientRegionFactoryBean.class);
|
||||
}
|
||||
|
||||
protected boolean isPoolBean(BeanDefinition beanDefinition) {
|
||||
return isBeanDefinitionOfType(beanDefinition, PoolFactoryBean.class);
|
||||
}
|
||||
|
||||
protected Predicate<String> isRegionBeanType() {
|
||||
|
||||
Predicate<String> genericRegionBeanType =
|
||||
typeName -> GenericRegionFactoryBean.class.getName().equals(typeName);
|
||||
|
||||
return genericRegionBeanType.or(typeName -> ClientRegionFactoryBean.class.getName().equals(typeName))
|
||||
.or(typeName -> LocalRegionFactoryBean.class.getName().equals(typeName))
|
||||
.or(typeName -> PartitionedRegionFactoryBean.class.getName().equals(typeName))
|
||||
.or(typeName -> ReplicatedRegionFactoryBean.class.getName().equals(typeName));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* 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.support;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.apache.geode.cache.Region;
|
||||
import org.apache.geode.cache.lucene.LuceneIndex;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.data.gemfire.search.lucene.LuceneIndexFactoryBean;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* The {@link LuceneIndexRegionBeanFactoryPostProcessor} class is a Spring {@link BeanFactoryPostProcessor} ensuring
|
||||
* that a {@link LuceneIndex} is created before the {@link Region} on which the {@link LuceneIndex} is defined.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.apache.geode.cache.Region
|
||||
* @see org.apache.geode.cache.lucene.LuceneIndex
|
||||
* @see org.springframework.beans.factory.config.BeanDefinition
|
||||
* @see org.springframework.beans.factory.config.BeanFactoryPostProcessor
|
||||
* @see org.springframework.beans.factory.config.ConfigurableListableBeanFactory
|
||||
* @see org.springframework.data.gemfire.search.lucene.LuceneIndexFactoryBean
|
||||
* @see org.springframework.data.gemfire.config.support.AbstractDependencyStructuringBeanFactoryPostProcessor
|
||||
* @since 2.1.0
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class LuceneIndexRegionBeanFactoryPostProcessor extends AbstractDependencyStructuringBeanFactoryPostProcessor {
|
||||
|
||||
@Override
|
||||
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
|
||||
|
||||
Map<String, String> regionNameToLuceneIndexBeanName = new HashMap<>();
|
||||
Map<String, String> regionNameToRegionBeanName = new HashMap<>();
|
||||
|
||||
Arrays.stream(beanFactory.getBeanDefinitionNames()).forEach(beanName -> {
|
||||
|
||||
BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);
|
||||
|
||||
if (isBeanDefinitionOfType(beanDefinition, LuceneIndexFactoryBean.class)) {
|
||||
resolveRegionNameFromLuceneIndex(beanDefinition)
|
||||
.ifPresent(regionName -> regionNameToLuceneIndexBeanName.put(regionName, beanName));
|
||||
}
|
||||
else if (isBeanDefinitionOfType(beanDefinition, isRegionBeanType())) {
|
||||
resolveRegionNameFromRegionBean(beanName, beanDefinition)
|
||||
.ifPresent(regionName -> regionNameToRegionBeanName.put(regionName, beanName));
|
||||
}
|
||||
});
|
||||
|
||||
regionNameToRegionBeanName.keySet().stream().forEach(regionName -> {
|
||||
|
||||
if (regionNameToLuceneIndexBeanName.containsKey(regionName)) {
|
||||
|
||||
String regionBeanName = regionNameToRegionBeanName.get(regionName);
|
||||
String luceneIndexBeanName = regionNameToLuceneIndexBeanName.get(regionName);
|
||||
|
||||
addDependsOn(beanFactory.getBeanDefinition(regionBeanName), luceneIndexBeanName);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private Optional<String> resolveRegionNameFromLuceneIndex(BeanDefinition beanDefinition) {
|
||||
|
||||
return getPropertyValue(beanDefinition, "regionPath")
|
||||
.map(this::asFullyQualifiedRegionName);
|
||||
}
|
||||
|
||||
private Optional<String> resolveRegionNameFromRegionBean(String beanName, BeanDefinition beanDefinition) {
|
||||
|
||||
String regionName = asString(getPropertyValue(beanDefinition, "regionName"));
|
||||
String name = asString(getPropertyValue(beanDefinition, "name"));
|
||||
|
||||
return Optional.ofNullable(StringUtils.hasText(regionName) ? regionName
|
||||
: (StringUtils.hasText(name) ? name : beanName)).filter(StringUtils::hasText);
|
||||
}
|
||||
|
||||
private String asFullyQualifiedRegionName(Object regionPath) {
|
||||
|
||||
return Optional.ofNullable(regionPath)
|
||||
.map(String::valueOf)
|
||||
.map(String::trim)
|
||||
.map(it -> {
|
||||
|
||||
int index = it.lastIndexOf(Region.SEPARATOR);
|
||||
|
||||
return index > 0 ? it : it.substring(1);
|
||||
})
|
||||
.filter(StringUtils::hasText)
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
@SuppressWarnings("all")
|
||||
private String asString(Optional<Object> value) {
|
||||
|
||||
return value.map(String::valueOf)
|
||||
.map(String::trim)
|
||||
.filter(StringUtils::hasText)
|
||||
.orElse(null);
|
||||
}
|
||||
}
|
||||
@@ -24,6 +24,7 @@ import org.apache.geode.cache.lucene.LuceneService;
|
||||
import org.apache.geode.cache.lucene.LuceneServiceProvider;
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.data.gemfire.support.AbstractFactoryBeanSupport;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -38,7 +39,7 @@ import org.springframework.util.Assert;
|
||||
* @since 1.1.0
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class LuceneServiceFactoryBean implements FactoryBean<LuceneService>, InitializingBean {
|
||||
public class LuceneServiceFactoryBean extends AbstractFactoryBeanSupport<LuceneService> implements InitializingBean {
|
||||
|
||||
private GemFireCache gemfireCache;
|
||||
|
||||
@@ -49,6 +50,7 @@ public class LuceneServiceFactoryBean implements FactoryBean<LuceneService>, Ini
|
||||
*/
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
|
||||
GemFireCache gemfireCache = getCache();
|
||||
|
||||
Assert.state(gemfireCache != null,
|
||||
@@ -83,15 +85,10 @@ public class LuceneServiceFactoryBean implements FactoryBean<LuceneService>, Ini
|
||||
*/
|
||||
@Override
|
||||
public Class<?> getObjectType() {
|
||||
return Optional.ofNullable(this.luceneService).<Class<?>>map(LuceneService::getClass).orElse(LuceneService.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
@Override
|
||||
public boolean isSingleton() {
|
||||
return true;
|
||||
return Optional.ofNullable(this.luceneService)
|
||||
.<Class<?>>map(LuceneService::getClass)
|
||||
.orElse(LuceneService.class);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -42,7 +42,6 @@ import org.springframework.util.StringUtils;
|
||||
// TODO rename this utility class using a more descriptive, intuitive and meaningful name
|
||||
public abstract class SpringUtils {
|
||||
|
||||
/* (non-Javadoc) */
|
||||
public static BeanDefinition addDependsOn(BeanDefinition bean, String... beanNames) {
|
||||
|
||||
List<String> dependsOnList = new ArrayList<>();
|
||||
@@ -54,7 +53,14 @@ public abstract class SpringUtils {
|
||||
return bean;
|
||||
}
|
||||
|
||||
/* (non-Javadoc) */
|
||||
public static Optional<Object> getPropertyValue(BeanDefinition beanDefinition, String propertyName) {
|
||||
|
||||
return Optional.ofNullable(beanDefinition)
|
||||
.map(it -> it.getPropertyValues())
|
||||
.map(propertyValues -> propertyValues.getPropertyValue(propertyName))
|
||||
.map(propertyValue -> propertyValue.getValue());
|
||||
}
|
||||
|
||||
public static BeanDefinition setPropertyReference(BeanDefinition beanDefinition,
|
||||
String propertyName, String beanName) {
|
||||
|
||||
@@ -63,7 +69,6 @@ public abstract class SpringUtils {
|
||||
return beanDefinition;
|
||||
}
|
||||
|
||||
/* (non-Javadoc) */
|
||||
public static BeanDefinition setPropertyValue(BeanDefinition beanDefinition,
|
||||
String propertyName, Object propertyValue) {
|
||||
|
||||
@@ -72,57 +77,46 @@ public abstract class SpringUtils {
|
||||
return beanDefinition;
|
||||
}
|
||||
|
||||
/* (non-Javadoc) */
|
||||
public static String defaultIfEmpty(String value, String defaultValue) {
|
||||
return (StringUtils.hasText(value) ? value : defaultValue);
|
||||
}
|
||||
|
||||
/* (non-Javadoc) */
|
||||
public static <T> T defaultIfNull(T value, T defaultValue) {
|
||||
return Optional.ofNullable(value).orElse(defaultValue);
|
||||
}
|
||||
|
||||
/* (non-Javadoc) */
|
||||
public static <T> T defaultIfNull(T value, Supplier<T> supplier) {
|
||||
return Optional.ofNullable(value).orElseGet(supplier);
|
||||
}
|
||||
|
||||
/* (non-Javadoc) */
|
||||
public static String dereferenceBean(String beanName) {
|
||||
return String.format("%1$s%2$s", BeanFactory.FACTORY_BEAN_PREFIX, beanName);
|
||||
}
|
||||
|
||||
/* (non-Javadoc) */
|
||||
public static boolean equalsIgnoreNull(Object obj1, Object obj2) {
|
||||
return (obj1 == null ? obj2 == null : obj1.equals(obj2));
|
||||
}
|
||||
|
||||
/* (non-Javadoc) */
|
||||
public static boolean nullOrEquals(Object obj1, Object obj2) {
|
||||
return (obj1 == null || obj1.equals(obj2));
|
||||
}
|
||||
|
||||
/* (non-Javadoc) */
|
||||
public static boolean nullSafeEquals(Object obj1, Object obj2) {
|
||||
return (obj1 != null && obj1.equals(obj2));
|
||||
}
|
||||
|
||||
/* (non-Javadoc) */
|
||||
public static <T> T safeGetValue(Supplier<T> valueSupplier) {
|
||||
return safeGetValue(valueSupplier, (T) null);
|
||||
}
|
||||
|
||||
/* (non-Javadoc) */
|
||||
public static <T> T safeGetValue(Supplier<T> valueSupplier, T defaultValue) {
|
||||
return safeGetValue(valueSupplier, (Supplier<T>) () -> defaultValue);
|
||||
}
|
||||
|
||||
/* (non-Javadoc) */
|
||||
public static <T> T safeGetValue(Supplier<T> valueSupplier, Supplier<T> defaultValueSupplier) {
|
||||
return safeGetValue(valueSupplier, (Function<Throwable, T>) exception -> defaultValueSupplier.get());
|
||||
}
|
||||
|
||||
/* (non-Javadoc) */
|
||||
public static <T> T safeGetValue(Supplier<T> valueSupplier, Function<Throwable, T> exceptionHandler) {
|
||||
try {
|
||||
return valueSupplier.get();
|
||||
|
||||
Reference in New Issue
Block a user