SGF-604 - Add Configurers to enable dynamic configuration in the new SDG Annotation configuration model.

Related JIRA: https://jira.spring.io/browse/SGF-586

Related JIRA: https://jira.spring.io/browse/DATAGEODE-12
This commit is contained in:
John Blum
2017-01-17 22:47:08 -08:00
parent 8af5ac3f8f
commit 80607deaec
82 changed files with 6024 additions and 2426 deletions

View File

@@ -16,30 +16,44 @@
package org.springframework.data.gemfire;
import static java.util.stream.StreamSupport.stream;
import static org.springframework.data.gemfire.util.ArrayUtils.nullSafeArray;
import static org.springframework.data.gemfire.util.CollectionUtils.nullSafeCollection;
import static org.springframework.data.gemfire.util.CollectionUtils.nullSafeIterable;
import static org.springframework.data.gemfire.util.RuntimeExceptionFactory.newIllegalStateException;
import java.io.File;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import org.apache.geode.cache.DiskStore;
import org.apache.geode.cache.DiskStoreFactory;
import org.apache.geode.cache.GemFireCache;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.data.gemfire.config.annotation.DiskStoreConfigurer;
import org.springframework.data.gemfire.support.AbstractFactoryBeanSupport;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
/**
* FactoryBean for creating a GemFire DiskStore.
* Spring {@link FactoryBean} used to create {@link DiskStore}.
*
* @author David Turanski
* @author John Blum
* @see org.springframework.beans.factory.BeanNameAware
* @see org.apache.geode.cache.DiskStore
* @see org.apache.geode.cache.DiskStoreFactory
* @see org.apache.geode.cache.GemFireCache
* @see org.springframework.beans.factory.FactoryBean
* @see org.springframework.beans.factory.InitializingBean
* @see org.springframework.data.gemfire.config.annotation.DiskStoreConfigurer
* @see org.springframework.data.gemfire.support.AbstractFactoryBeanSupport
*/
@SuppressWarnings("unused")
public class DiskStoreFactoryBean implements BeanNameAware , FactoryBean<DiskStore>, InitializingBean {
public class DiskStoreFactoryBean extends AbstractFactoryBeanSupport<DiskStore> implements InitializingBean {
private Boolean allowForceCompaction;
private Boolean autoCompact;
@@ -57,78 +71,184 @@ public class DiskStoreFactoryBean implements BeanNameAware , FactoryBean<DiskSto
private Float diskUsageCriticalPercentage;
private Float diskUsageWarningPercentage;
private List<DiskStoreConfigurer> diskStoreConfigurers = Collections.emptyList();
private DiskStoreConfigurer compositeDiskStoreConfigurer = (beanName, bean) ->
nullSafeCollection(diskStoreConfigurers).forEach(diskStoreConfigurer ->
diskStoreConfigurer.configure(beanName, bean));
private List<DiskDir> diskDirs;
private String name;
@Override
public DiskStore getObject() throws Exception {
return diskStore;
}
@Override
public Class<?> getObjectType() {
return (diskStore != null ? diskStore.getClass() : DiskStore.class);
}
@Override
public boolean isSingleton() {
return true;
}
@Override
public void afterPropertiesSet() throws Exception {
Assert.state(cache != null, String.format("A reference to the GemFire Cache must be set for Disk Store '%1$s'.",
getName()));
DiskStoreFactory diskStoreFactory = cache.createDiskStoreFactory();
String diskStoreName = resolveDiskStoreName();
if (allowForceCompaction != null) {
diskStoreFactory.setAllowForceCompaction(allowForceCompaction);
}
if (autoCompact != null) {
diskStoreFactory.setAutoCompact(autoCompact);
}
if (compactionThreshold != null) {
diskStoreFactory.setCompactionThreshold(compactionThreshold);
}
if (diskUsageCriticalPercentage != null) {
diskStoreFactory.setDiskUsageCriticalPercentage(diskUsageCriticalPercentage);
}
if (diskUsageWarningPercentage != null) {
diskStoreFactory.setDiskUsageWarningPercentage(diskUsageWarningPercentage);
}
if (maxOplogSize != null) {
diskStoreFactory.setMaxOplogSize(maxOplogSize);
}
if (queueSize != null) {
diskStoreFactory.setQueueSize(queueSize);
}
if (timeInterval != null) {
diskStoreFactory.setTimeInterval(timeInterval);
}
if (writeBufferSize != null) {
diskStoreFactory.setWriteBufferSize(writeBufferSize);
}
applyDiskStoreConfigurers(diskStoreName);
if (!CollectionUtils.isEmpty(diskDirs)) {
File[] diskDirFiles = new File[diskDirs.size()];
int[] diskDirSizes = new int[diskDirs.size()];
GemFireCache cache = resolveCache(diskStoreName);
for (int index = 0; index < diskDirs.size(); index++) {
DiskDir diskDir = diskDirs.get(index);
diskDirFiles[index] = new File(diskDir.location);
diskDirSizes[index] = (diskDir.maxSize != null ? diskDir.maxSize
: DiskStoreFactory.DEFAULT_DISK_DIR_SIZE);
}
DiskStoreFactory diskStoreFactory = postProcess(configure(createDiskStoreFactory(cache)));
diskStoreFactory.setDiskDirsAndSizes(diskDirFiles, diskDirSizes);
}
this.diskStore = postProcess(newDiskStore(diskStoreFactory, diskStoreName));
}
diskStore = diskStoreFactory.create(getName());
/* (non-Javadoc) */
private void applyDiskStoreConfigurers(String diskStoreName) {
applyDiskStoreConfigurers(diskStoreName, getCompositeDiskStoreConfigurer());
}
Assert.notNull(diskStore, String.format("DiskStore with name '%1$s' failed to be created successfully.",
diskStore.getName()));
/**
* Null-safe operation to apply the given array of {@link DiskStoreConfigurer DiskStoreConfigurers}
* to this {@link DiskStoreFactoryBean}.
*
* @param diskStoreName {@link String} containing the name of the {@link DiskStore}.
* @param diskStoreConfigurers array of {@link DiskStoreConfigurer DiskStoreConfigurers} applied
* to this {@link DiskStoreFactoryBean}.
* @see org.springframework.data.gemfire.config.annotation.DiskStoreConfigurer
* @see #applyDiskStoreConfigurers(String, Iterable)
*/
protected void applyDiskStoreConfigurers(String diskStoreName, DiskStoreConfigurer... diskStoreConfigurers) {
applyDiskStoreConfigurers(diskStoreName,
Arrays.asList(nullSafeArray(diskStoreConfigurers, DiskStoreConfigurer.class)));
}
/**
* Null-safe operation to apply the given {@link Iterable} of {@link DiskStoreConfigurer DiskStoreConfigurers}
* to this {@link DiskStoreFactoryBean}.
*
* @param diskStoreName {@link String} containing the name of the {@link DiskStore}.
* @param diskStoreConfigurers {@link Iterable} of {@link DiskStoreConfigurer DiskStoreConfigurers} applied
* to this {@link DiskStoreFactoryBean}.
* @see org.springframework.data.gemfire.config.annotation.DiskStoreConfigurer
*/
protected void applyDiskStoreConfigurers(String diskStoreName, Iterable<DiskStoreConfigurer> diskStoreConfigurers) {
stream(nullSafeIterable(diskStoreConfigurers).spliterator(), false)
.forEach(diskStoreConfigurer -> diskStoreConfigurer.configure(diskStoreName, this));
}
/* (non-Javadoc) */
private GemFireCache resolveCache(String diskStoreName) {
return Optional.ofNullable(this.cache)
.orElseThrow(() -> newIllegalStateException("Cache is required to create DiskStore [%s]", diskStoreName));
}
/* (non-Javadoc) */
final String resolveDiskStoreName() {
return Optional.ofNullable(getBeanName()).filter(StringUtils::hasText)
.orElse(DiskStoreFactory.DEFAULT_DISK_STORE_NAME);
}
/**
* Creates an instance of {@link DiskStoreFactory} using the given {@link GemFireCache} in order to
* construct, configure and initialize a new {@link DiskStore}.
*
* @param cache reference to the {@link GemFireCache} used to create the {@link DiskStoreFactory}.
* @return a new instance of {@link DiskStoreFactory}.
* @see org.apache.geode.cache.GemFireCache#createDiskStoreFactory()
* @see org.apache.geode.cache.DiskStoreFactory
*/
protected DiskStoreFactory createDiskStoreFactory(GemFireCache cache) {
return cache.createDiskStoreFactory();
}
/**
* Configures the given {@link DiskStoreFactory} with the configuration settings present
* on this {@link DiskStoreFactoryBean}
*
* @param diskStoreFactory {@link DiskStoreFactory} to configure.
* @return the given {@link DiskStoreFactory}
* @see org.apache.geode.cache.DiskStoreFactory
*/
protected DiskStoreFactory configure(DiskStoreFactory diskStoreFactory) {
Optional.ofNullable(this.allowForceCompaction).ifPresent(diskStoreFactory::setAllowForceCompaction);
Optional.ofNullable(this.autoCompact).ifPresent(diskStoreFactory::setAutoCompact);
Optional.ofNullable(this.compactionThreshold).ifPresent(diskStoreFactory::setCompactionThreshold);
Optional.ofNullable(this.diskUsageCriticalPercentage).ifPresent(diskStoreFactory::setDiskUsageCriticalPercentage);
Optional.ofNullable(this.diskUsageWarningPercentage).ifPresent(diskStoreFactory::setDiskUsageWarningPercentage);
Optional.ofNullable(this.maxOplogSize).ifPresent(diskStoreFactory::setMaxOplogSize);
Optional.ofNullable(this.queueSize).ifPresent(diskStoreFactory::setQueueSize);
Optional.ofNullable(this.timeInterval).ifPresent(diskStoreFactory::setTimeInterval);
Optional.ofNullable(this.writeBufferSize).ifPresent(diskStoreFactory::setWriteBufferSize);
Optional.ofNullable(this.diskDirs).filter(diskDirs -> !CollectionUtils.isEmpty(diskDirs))
.ifPresent(diskDirs -> {
File[] diskDirFiles = new File[diskDirs.size()];
int[] diskDirSizes = new int[diskDirs.size()];
for (int index = 0; index < diskDirs.size(); index++) {
DiskDir diskDir = diskDirs.get(index);
diskDirFiles[index] = new File(diskDir.location);
diskDirSizes[index] = Optional.ofNullable(diskDir.maxSize)
.orElse(DiskStoreFactory.DEFAULT_DISK_DIR_SIZE);
}
diskStoreFactory.setDiskDirsAndSizes(diskDirFiles, diskDirSizes);
});
return diskStoreFactory;
}
/**
* Constructs a new instance of {@link DiskStore} with the given {@link String name}
* using the provided {@link DiskStoreFactory}
*
* @param diskStoreFactory {@link DiskStoreFactory} used to create the {@link DiskStore}.
* @param diskStoreName {@link String} containing the name of the new {@link DiskStore}.
* @return a new instance of {@link DiskStore} with the given {@link String name}.
* @see org.apache.geode.cache.DiskStoreFactory
* @see org.apache.geode.cache.DiskStore
*/
protected DiskStore newDiskStore(DiskStoreFactory diskStoreFactory, String diskStoreName) {
return diskStoreFactory.create(diskStoreName);
}
/**
* Post-process the {@link DiskStoreFactory} with any custom {@link DiskStoreFactory} or {@link DiskStore}
* configuration settings as required by the application.
*
* @param diskStoreFactory {@link DiskStoreFactory} to process.
* @return the given {@link DiskStoreFactory}.
* @see org.apache.geode.cache.DiskStoreFactory
*/
protected DiskStoreFactory postProcess(DiskStoreFactory diskStoreFactory) {
return diskStoreFactory;
}
/**
* Post-process the provided {@link DiskStore} constructed, configured and initialized
* by this {@link DiskStoreFactoryBean}.
*
* @param diskStore {@link DiskStore} to process.
* @return the given {@link DiskStore}.
* @see org.apache.geode.cache.DiskStore
*/
protected DiskStore postProcess(DiskStore diskStore) {
return diskStore;
}
/**
* Returns a reference to the Composite {@link DiskStoreConfigurer} used to apply additional configuration
* to this {@link DiskStoreFactoryBean} on Spring container initialization.
*
* @return the Composite {@link DiskStoreConfigurer}.
* @see org.springframework.data.gemfire.config.annotation.DiskStoreConfigurer
*/
protected DiskStoreConfigurer getCompositeDiskStoreConfigurer() {
return this.compositeDiskStoreConfigurer;
}
@Override
public DiskStore getObject() throws Exception {
return this.diskStore;
}
@Override
@SuppressWarnings("unchecked")
public Class<?> getObjectType() {
return Optional.ofNullable(this.diskStore).map(DiskStore::getClass).orElse((Class) DiskStore.class);
}
public void setCache(GemFireCache cache) {
@@ -143,26 +263,47 @@ public class DiskStoreFactoryBean implements BeanNameAware , FactoryBean<DiskSto
this.autoCompact = autoCompact;
}
@Override
public void setBeanName(String name) {
this.name = name;
}
public void setCompactionThreshold(Integer compactionThreshold) {
validateCompactionThreshold(compactionThreshold);
this.compactionThreshold = compactionThreshold;
}
protected void validateCompactionThreshold(final Integer compactionThreshold) {
protected void validateCompactionThreshold(Integer compactionThreshold) {
Assert.isTrue(compactionThreshold == null || (compactionThreshold >= 0 && compactionThreshold <= 100),
String.format("The DiskStore's (%1$s) compaction threshold (%2$d) must be an integer value between 0 and 100 inclusive.",
this.name, compactionThreshold));
resolveDiskStoreName(), compactionThreshold));
}
public void setDiskDirs(List<DiskDir> diskDirs) {
this.diskDirs = diskDirs;
}
/**
* Null-safe operation to set an array of {@link DiskStoreConfigurer DiskStoreConfigurers} used to
* apply additional configuration to this {@link DiskStoreFactoryBean} when using Annotation-based configuration.
*
* @param diskStoreConfigurers array of {@link DiskStoreConfigurer DiskStoreConfigurers} used to apply
* additional configuration to this {@link DiskStoreFactoryBean}.
* @see org.springframework.data.gemfire.config.annotation.DiskStoreConfigurer
* @see #setDiskStoreConfigurers(List)
*/
public void setDiskStoreConfigurers(DiskStoreConfigurer... diskStoreConfigurers) {
setDiskStoreConfigurers(Arrays.asList(nullSafeArray(diskStoreConfigurers, DiskStoreConfigurer.class)));
}
/**
* Null-safe operation to set an {@link Iterable} of {@link DiskStoreConfigurer DiskStoreConfigurers}
* used to apply additional configuration to this {@link DiskStoreFactoryBean}
* when using Annotation-based configuration.
*
* @param diskStoreConfigurers {@link Iterable } of {@link DiskStoreConfigurer DiskStoreConfigurers} used to
* apply additional configuration to this {@link DiskStoreFactoryBean}.
* @see org.springframework.data.gemfire.config.annotation.DiskStoreConfigurer
*/
public void setDiskStoreConfigurers(List<DiskStoreConfigurer> diskStoreConfigurers) {
this.diskStoreConfigurers = Optional.ofNullable(diskStoreConfigurers).orElseGet(Collections::emptyList);
}
public void setDiskUsageCriticalPercentage(Float diskUsageCriticalPercentage) {
this.diskUsageCriticalPercentage = diskUsageCriticalPercentage;
}
@@ -187,11 +328,8 @@ public class DiskStoreFactoryBean implements BeanNameAware , FactoryBean<DiskSto
this.writeBufferSize = writeBufferSize;
}
/* package-private */ final String getName() {
return (StringUtils.hasText(name) ? name : DiskStoreFactory.DEFAULT_DISK_STORE_NAME);
}
public static class DiskDir {
final Integer maxSize;
final String location;
@@ -199,10 +337,10 @@ public class DiskStoreFactoryBean implements BeanNameAware , FactoryBean<DiskSto
this.location = location;
this.maxSize = null;
}
public DiskDir(String location, int maxSize) {
this.location = location;
this.maxSize = maxSize;
}
}
}

View File

@@ -20,6 +20,7 @@ import java.util.concurrent.ConcurrentMap;
import org.apache.geode.cache.CacheFactory;
import org.apache.geode.cache.Region;
import org.apache.geode.internal.GemFireVersion;
import org.springframework.data.gemfire.util.CacheUtils;
import org.springframework.util.ClassUtils;
@@ -36,7 +37,30 @@ import org.springframework.util.ClassUtils;
@SuppressWarnings("unused")
public abstract class GemfireUtils extends CacheUtils {
public final static String GEMFIRE_VERSION = CacheFactory.getVersion();
public final static String APACHE_GEODE_NAME = "Aache Geode";
public final static String GEMFIRE_NAME = apacheGeodeProductName();
public final static String GEMFIRE_VERSION = apacheGeodeVersion();
public final static String UNKNOWN = "unknown";
/* (non-Javadoc) */
public static String apacheGeodeProductName() {
try {
return GemFireVersion.getProductName();
}
catch (Throwable ignore) {
return APACHE_GEODE_NAME;
}
}
/* (non-Javadoc) */
public static String apacheGeodeVersion() {
try {
return CacheFactory.getVersion();
}
catch (Throwable ignore) {
return UNKNOWN;
}
}
/* (non-Javadoc) */
public static boolean isGemfireVersionGreaterThanEqualTo(double expectedVersion) {
@@ -87,5 +111,4 @@ public abstract class GemfireUtils extends CacheUtils {
//System.out.printf("Is GemFire Version 6.5 of Above? %1$s%n", isGemfireVersion65OrAbove());
//System.out.printf("Is GemFire Version 7.0 of Above? %1$s%n", isGemfireVersion7OrAbove());
}
}

View File

@@ -16,7 +16,16 @@
package org.springframework.data.gemfire;
import static java.util.stream.StreamSupport.stream;
import static org.springframework.data.gemfire.util.ArrayUtils.nullSafeArray;
import static org.springframework.data.gemfire.util.CollectionUtils.nullSafeCollection;
import static org.springframework.data.gemfire.util.CollectionUtils.nullSafeIterable;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import org.apache.geode.cache.Region;
import org.apache.geode.cache.RegionService;
@@ -27,51 +36,59 @@ import org.apache.geode.cache.query.IndexInvalidException;
import org.apache.geode.cache.query.IndexNameConflictException;
import org.apache.geode.cache.query.IndexStatistics;
import org.apache.geode.cache.query.QueryService;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.data.gemfire.config.annotation.IndexConfigurer;
import org.springframework.data.gemfire.config.xml.GemfireConstants;
import org.springframework.data.gemfire.support.AbstractFactoryBeanSupport;
import org.springframework.data.gemfire.util.CollectionUtils;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
/**
* Spring FactoryBean for easy declarative creation of GemFire Indexes.
* Spring {@link FactoryBean} used to construct, configure and initialize {@link Index Indexes}
* using a declarative approach.
*
* @author Costin Leau
* @author David Turanski
* @author John Blum
* @see org.springframework.beans.factory.BeanFactoryAware
* @see org.springframework.beans.factory.BeanNameAware
* @see org.springframework.beans.factory.FactoryBean
* @see org.springframework.beans.factory.InitializingBean
* @see org.springframework.data.gemfire.IndexFactoryBean.IndexWrapper
* @see org.apache.geode.cache.Region
* @see org.apache.geode.cache.RegionService
* @see org.apache.geode.cache.query.Index
* @see org.apache.geode.cache.query.QueryService
* @see org.springframework.beans.factory.FactoryBean
* @see org.springframework.beans.factory.InitializingBean
* @see org.springframework.data.gemfire.IndexFactoryBean.IndexWrapper
* @see org.springframework.data.gemfire.config.annotation.IndexConfigurer
* @see org.springframework.data.gemfire.support.AbstractFactoryBeanSupport
* @since 1.0.0
*/
public class IndexFactoryBean implements InitializingBean, FactoryBean<Index>, BeanNameAware, BeanFactoryAware {
public class IndexFactoryBean extends AbstractFactoryBeanSupport<Index> implements InitializingBean {
private boolean define = false;
private boolean override = true;
private BeanFactory beanFactory;
private Index index;
private IndexType indexType;
//@Autowired(required = false)
private List<IndexConfigurer> indexConfigurers = Collections.emptyList();
private IndexConfigurer compositeIndexConfigurer = new IndexConfigurer() {
@Override
public void configure(String beanName, IndexFactoryBean bean) {
nullSafeCollection(indexConfigurers).forEach(indexConfigurer -> indexConfigurer.configure(beanName, bean));
}
};
private QueryService queryService;
private RegionService cache;
private String beanName;
private String expression;
private String from;
private String imports;
@@ -83,29 +100,66 @@ public class IndexFactoryBean implements InitializingBean, FactoryBean<Index>, B
*/
@Override
public void afterPropertiesSet() throws Exception {
Assert.notNull(cache, "The GemFire Cache reference must not be null!");
queryService = lookupQueryService();
this.indexName = Optional.ofNullable(this.name).filter(StringUtils::hasText).orElse(getBeanName());
Assert.hasText(this.indexName, "Index name is required");
applyIndexConfigurers(this.indexName);
Assert.notNull(cache, "Cache is required");
this.queryService = lookupQueryService();
Assert.notNull(queryService, "QueryService is required to create an Index");
Assert.hasText(expression, "Index 'expression' is required");
Assert.hasText(from, "Index 'from clause' is required");
Assert.hasText(expression, "Index expression is required");
Assert.hasText(from, "Index from clause is required");
if (IndexType.isKey(indexType)) {
Assert.isNull(imports, "'imports' are not supported with a KEY Index");
Assert.isNull(imports, "imports are not supported with a KEY Index");
}
indexName = (StringUtils.hasText(name) ? name : beanName);
this.index = createIndex(queryService, indexName);
}
Assert.hasText(indexName, "Index 'name' is required");
/* (non-Javadoc) */
private void applyIndexConfigurers(String indexName) {
applyIndexConfigurers(indexName, getCompositeRegionConfigurer());
}
index = createIndex(queryService, indexName);
/**
* Null-safe operation to apply the given array of {@link IndexConfigurer IndexConfigurers}
* to this {@link IndexFactoryBean}.
*
* @param indexName {@link String} containing the name of the {@link Index}.
* @param indexConfigurers array of {@link IndexConfigurer IndexConfigurers} applied
* to this {@link IndexFactoryBean}.
* @see org.springframework.data.gemfire.config.annotation.RegionConfigurer
* @see #applyIndexConfigurers(String, Iterable)
*/
protected void applyIndexConfigurers(String indexName, IndexConfigurer... indexConfigurers) {
applyIndexConfigurers(indexName, Arrays.asList(nullSafeArray(indexConfigurers, IndexConfigurer.class)));
}
/**
* Null-safe operation to apply the given {@link Iterable} of {@link IndexConfigurer IndexConfigurers}
* to this {@link IndexFactoryBean}.
*
* @param indexName {@link String} containing the name of the {@link Index}.
* @param indexConfigurers {@link Iterable} of {@link IndexConfigurer IndexConfigurers} applied
* to this {@link IndexFactoryBean}.
* @see org.springframework.data.gemfire.config.annotation.RegionConfigurer
*/
protected void applyIndexConfigurers(String indexName, Iterable<IndexConfigurer> indexConfigurers) {
stream(nullSafeIterable(indexConfigurers).spliterator(), false)
.forEach(indexConfigurer -> indexConfigurer.configure(indexName, this));
}
/* (non-Javadoc) */
QueryService doLookupQueryService() {
return (queryService != null ? queryService
: (cache instanceof ClientCache ? ((ClientCache) cache).getLocalQueryService() : cache.getQueryService()));
return Optional.ofNullable(this.queryService).orElseGet(() ->
(this.cache instanceof ClientCache ? ((ClientCache) this.cache).getLocalQueryService()
: this.cache.getQueryService()));
}
/* (non-Javadoc) */
@@ -131,6 +185,7 @@ public class IndexFactoryBean implements InitializingBean, FactoryBean<Index>, B
/* (non-Javadoc) */
Index createIndex(QueryService queryService, String indexName) throws Exception {
Index existingIndex = getExistingIndex(queryService, indexName);
if (existingIndex != null) {
@@ -183,6 +238,7 @@ public class IndexFactoryBean implements InitializingBean, FactoryBean<Index>, B
/* (non-Javadoc) */
Index createKeyIndex(QueryService queryService, String indexName, String expression, String from) throws Exception {
if (isDefine()) {
queryService.defineKeyIndex(indexName, expression, from);
return new IndexWrapper(queryService, indexName);
@@ -194,7 +250,7 @@ public class IndexFactoryBean implements InitializingBean, FactoryBean<Index>, B
/* (non-Javadoc) */
Index createHashIndex(QueryService queryService, String indexName, String expression, String from,
String imports) throws Exception {
String imports) throws Exception {
boolean hasImports = StringUtils.hasText(imports);
@@ -246,7 +302,8 @@ public class IndexFactoryBean implements InitializingBean, FactoryBean<Index>, B
/* (non-Javadoc) */
Index getExistingIndex(QueryService queryService, String indexName) {
for (Index index : CollectionUtils.nullSafeCollection(queryService.getIndexes())) {
for (Index index : nullSafeCollection(queryService.getIndexes())) {
if (index.getName().equalsIgnoreCase(indexName)) {
return index;
}
@@ -255,29 +312,33 @@ public class IndexFactoryBean implements InitializingBean, FactoryBean<Index>, B
return null;
}
/**
* Returns a reference to the Composite {@link IndexConfigurer} used to apply additional configuration
* to this {@link IndexFactoryBean} on Spring container initialization.
*
* @return the Composite {@link IndexConfigurer}.
* @see org.springframework.data.gemfire.config.annotation.IndexConfigurer
*/
protected IndexConfigurer getCompositeRegionConfigurer() {
return this.compositeIndexConfigurer;
}
/**
* @inheritDoc
*/
@Override
public Index getObject() {
index = (index != null ? index : getExistingIndex(queryService, indexName));
return index;
return Optional.ofNullable(this.index)
.orElseGet(() -> this.index = getExistingIndex(queryService, indexName));
}
/**
* @inheritDoc
*/
@Override
@SuppressWarnings("unchecked")
public Class<?> getObjectType() {
return (index != null ? index.getClass() : Index.class);
}
/**
* @inheritDoc
*/
@Override
public boolean isSingleton() {
return true;
return Optional.ofNullable(this.index).map(Index::getClass).orElse((Class) Index.class);
}
/**
@@ -298,24 +359,6 @@ public class IndexFactoryBean implements InitializingBean, FactoryBean<Index>, B
this.queryService = service;
}
/* (non-Javadoc) */
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
}
/* (non-Javadoc) */
protected BeanFactory getBeanFactory() {
Assert.state(beanFactory != null, "'beanFactory' was not properly initialized");
return beanFactory;
}
/* (non-Javadoc) */
@Override
public void setBeanName(String name) {
this.beanName = name;
}
/**
* @param name the name to set
*/
@@ -363,6 +406,31 @@ public class IndexFactoryBean implements InitializingBean, FactoryBean<Index>, B
this.imports = imports;
}
/**
* Null-safe operation to set an array of {@link IndexConfigurer IndexConfigurers} used to apply
* additional configuration to this {@link IndexFactoryBean} when using Annotation-based configuration.
*
* @param indexConfigurers array of {@link IndexConfigurer IndexConfigurers} used to apply
* additional configuration to this {@link IndexFactoryBean}.
* @see org.springframework.data.gemfire.config.annotation.IndexConfigurer
* @see #setIndexConfigurers(List)
*/
public void setIndexConfigurers(IndexConfigurer... indexConfigurers) {
setIndexConfigurers(Arrays.asList(nullSafeArray(indexConfigurers, IndexConfigurer.class)));
}
/**
* Null-safe operation to set an {@link Iterable} of {@link IndexConfigurer IndexConfigurers} used to apply
* additional configuration to this {@link IndexFactoryBean} when using Annotation-based configuration.
*
* @param indexConfigurers {@link Iterable } of {@link IndexConfigurer IndexConfigurers} used to apply
* additional configuration to this {@link IndexFactoryBean}.
* @see org.springframework.data.gemfire.config.annotation.IndexConfigurer
*/
public void setIndexConfigurers(List<IndexConfigurer> indexConfigurers) {
this.indexConfigurers = Optional.ofNullable(indexConfigurers).orElseGet(Collections::emptyList);
}
/**
* @param override the override to set
*/

View File

@@ -16,7 +16,19 @@
package org.springframework.data.gemfire;
import static java.util.Arrays.stream;
import static org.springframework.data.gemfire.util.ArrayUtils.nullSafeArray;
import static org.springframework.data.gemfire.util.CollectionUtils.nullSafeCollection;
import static org.springframework.data.gemfire.util.CollectionUtils.nullSafeIterable;
import static org.springframework.data.gemfire.util.RuntimeExceptionFactory.newIllegalArgumentException;
import static org.springframework.data.gemfire.util.RuntimeExceptionFactory.newIllegalStateException;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.stream.StreamSupport;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -43,20 +55,52 @@ import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.context.SmartLifecycle;
import org.springframework.core.io.Resource;
import org.springframework.data.gemfire.util.ArrayUtils;
import org.springframework.data.gemfire.client.ClientRegionFactoryBean;
import org.springframework.data.gemfire.config.annotation.RegionConfigurer;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;
/**
<<<<<<< HEAD
* Abstract base class and Spring {@link FactoryBean} for constructing and initializing a GemFire {@link Region}.
=======
* Abstract Spring {@link FactoryBean} base class extended by other SDG {@link FactoryBean FactoryBeans} used to
* construct, configure and initialize peer {@link Region Regions}.
*
* This {@link FactoryBean} allows for very easy and flexible creation of peer {@link Region}.
* For client {@link Region Regions}, however, see the {@link ClientRegionFactoryBean}.
>>>>>>> c22ebe6... DATAGEODE-12 - Introduce Spring Configurers to flexibly alter Spring Data GemFire configuration when using Annotation config.
*
* @author Costin Leau
* @author David Turanski
* @author John Blum
<<<<<<< HEAD
* @see org.springframework.beans.factory.DisposableBean
* @see org.springframework.context.SmartLifecycle
* @see org.springframework.data.gemfire.RegionLookupFactoryBean
=======
* @see org.apache.geode.cache.Cache
* @see org.apache.geode.cache.CacheListener
* @see org.apache.geode.cache.CacheLoader
* @see org.apache.geode.cache.CacheWriter
* @see org.apache.geode.cache.DataPolicy
* @see org.apache.geode.cache.EvictionAttributes
* @see org.apache.geode.cache.GemFireCache
* @see org.apache.geode.cache.PartitionAttributes
* @see org.apache.geode.cache.Region
* @see org.apache.geode.cache.RegionAttributes
* @see org.apache.geode.cache.RegionFactory
* @see org.apache.geode.cache.RegionShortcut
* @see org.apache.geode.cache.Scope
* @see org.apache.geode.cache.asyncqueue.AsyncEventQueue
* @see org.springframework.beans.factory.DisposableBean
* @see org.springframework.context.SmartLifecycle
* @see org.springframework.data.gemfire.RegionLookupFactoryBean
* @see org.springframework.data.gemfire.client.ClientRegionFactoryBean
* @see org.springframework.data.gemfire.config.annotation.RegionConfigurer
>>>>>>> c22ebe6... DATAGEODE-12 - Introduce Spring Configurers to flexibly alter Spring Data GemFire configuration when using Annotation config.
*/
@SuppressWarnings("unused")
public abstract class RegionFactoryBean<K, V> extends RegionLookupFactoryBean<K, V>
@@ -68,6 +112,7 @@ public abstract class RegionFactoryBean<K, V> extends RegionLookupFactoryBean<K,
private boolean destroy = false;
private boolean running;
private Boolean offHeap;
private Boolean persistent;
private AsyncEventQueue[] asyncEventQueues;
@@ -87,8 +132,19 @@ public abstract class RegionFactoryBean<K, V> extends RegionLookupFactoryBean<K,
private GatewaySender[] gatewaySenders;
private List<RegionConfigurer> regionConfigurers = Collections.emptyList();
private RegionAttributes<K, V> attributes;
private RegionConfigurer compositeRegionConfigurer = new RegionConfigurer() {
@Override
public void configure(String beanName, RegionFactoryBean<?, ?> bean) {
nullSafeCollection(regionConfigurers)
.forEach(regionConfigurer -> regionConfigurer.configure(beanName, bean));
}
};
private RegionShortcut shortcut;
private Resource snapshot;
@@ -98,128 +154,215 @@ public abstract class RegionFactoryBean<K, V> extends RegionLookupFactoryBean<K,
private String diskStoreName;
/**
* @inheritDoc
* Creates a new {@link Region} with the given {@link String name}.
*
* @param gemfireCache reference to the {@link GemFireCache}.
* @param regionName {@link String name} of the new {@link Region}.
* @return a new {@link Region} with the given {@link String name}.
* @see org.apache.geode.cache.GemFireCache
* @see org.apache.geode.cache.Region
*/
@Override
public void afterPropertiesSet() throws Exception {
super.afterPropertiesSet();
postProcess(getRegion());
protected Region<K, V> createRegion(GemFireCache gemfireCache, String regionName) throws Exception {
applyRegionConfigurers(regionName);
verifyLockGrantorEligibility(getAttributes(), getScope());
Cache cache = resolveCache(gemfireCache);
RegionFactory<K, V> regionFactory = postProcess(configure(createRegionFactory(cache)));
Region<K, V> region = newRegion(regionFactory, getParent(), regionName);
return enableAsLockGrantor(region);
}
/* (non-Javadoc) */
private void applyRegionConfigurers(String regionName) {
applyRegionConfigurers(regionName, getCompositeRegionConfigurer());
}
/**
* @inheritDoc
* Null-safe operation to apply the given array of {@link RegionConfigurer RegionConfigurers}
* to this {@link RegionFactoryBean}.
*
* @param regionName {@link String} containing the name of the {@link Region}.
* @param regionConfigurers array of {@link RegionConfigurer RegionConfigurers} applied
* to this {@link RegionFactoryBean}.
* @see org.springframework.data.gemfire.config.annotation.RegionConfigurer
* @see #applyRegionConfigurers(String, Iterable)
*/
@Override
@SuppressWarnings({ "unchecked" })
protected Region<K, V> lookupRegion(GemFireCache gemfireCache, String regionName) throws Exception {
Assert.isTrue(gemfireCache instanceof Cache, String.format("Unable to create Regions from '%1$s'.",
gemfireCache));
protected void applyRegionConfigurers(String regionName, RegionConfigurer... regionConfigurers) {
applyRegionConfigurers(regionName, Arrays.asList(nullSafeArray(regionConfigurers, RegionConfigurer.class)));
}
Cache cache = (Cache) gemfireCache;
/**
* Null-safe operation to apply the given {@link Iterable} of {@link RegionConfigurer RegionConfigurers}
* to this {@link RegionFactoryBean}.
*
* @param regionName {@link String} containing the name of the {@link Region}.
* @param regionConfigurers {@link Iterable} of {@link RegionConfigurer RegionConfigurers} applied
* to this {@link RegionFactoryBean}.
* @see org.springframework.data.gemfire.config.annotation.RegionConfigurer
*/
protected void applyRegionConfigurers(String regionName, Iterable<RegionConfigurer> regionConfigurers) {
StreamSupport.stream(nullSafeIterable(regionConfigurers).spliterator(), false)
.forEach(regionConfigurer -> regionConfigurer.configure(regionName, this));
}
RegionFactory<K, V> regionFactory = createRegionFactory(cache);
/* (non-Javadoc) */
private Region<K, V> enableAsLockGrantor(Region<K, V> region) {
for (AsyncEventQueue asyncEventQueue : ArrayUtils.nullSafeArray(asyncEventQueues, AsyncEventQueue.class)) {
regionFactory.addAsyncEventQueueId(asyncEventQueue.getId());
}
for (CacheListener<K, V> listener : ArrayUtils.nullSafeArray(cacheListeners, CacheListener.class)) {
regionFactory.addCacheListener(listener);
}
if (cacheLoader != null) {
regionFactory.setCacheLoader(cacheLoader);
}
if (cacheWriter != null) {
regionFactory.setCacheWriter(cacheWriter);
}
for (GatewaySender gatewaySender : ArrayUtils.nullSafeArray(gatewaySenders, GatewaySender.class)) {
regionFactory.addGatewaySenderId(gatewaySender.getId());
}
resolveDataPolicy(regionFactory, persistent, dataPolicy);
if (isDiskStoreConfigurationAllowed()) {
regionFactory.setDiskStoreName(diskStoreName);
}
if (evictionAttributes != null) {
regionFactory.setEvictionAttributes(evictionAttributes);
}
if (keyConstraint != null) {
regionFactory.setKeyConstraint(keyConstraint);
}
if (scope != null) {
regionFactory.setScope(scope);
}
if (valueConstraint != null) {
regionFactory.setValueConstraint(valueConstraint);
}
if (attributes != null) {
Assert.state(!attributes.isLockGrantor() || (scope == null) || scope.isGlobal(),
"Lock Grantor only applies to a 'GLOBAL' scoped Region.");
}
postProcess(regionFactory);
Region<K, V> region = (getParent() != null ? regionFactory.createSubregion(getParent(), regionName)
: regionFactory.create(regionName));
if (log.isInfoEnabled()) {
if (getParent() != null) {
log.info(String.format("Created new Cache sub-Region [%1$s] under parent Region [%2$s].",
regionName, getParent().getName()));
}
else {
log.info(String.format("Created new Cache Region [%1$s].", regionName));
}
}
if (snapshot != null) {
region.loadSnapshot(snapshot.getInputStream());
}
if (attributes != null && attributes.isLockGrantor()) {
region.becomeLockGrantor();
}
Optional.ofNullable(region)
.filter(it -> it.getAttributes().isLockGrantor())
.ifPresent(Region::becomeLockGrantor);
return region;
}
/* (non-Javadoc) */
private Region<K, V> newRegion(RegionFactory<K, V> regionFactory, Region<?, ?> parentRegion, String regionName) {
return Optional.ofNullable(parentRegion)
.map(parent -> {
logInfo("Creating Subregion [%1$s] with parent Region [%2$s]",
regionName, parent.getName());
return regionFactory.<K, V>createSubregion(parent, regionName);
})
.orElseGet(() -> {
logInfo("Created Region [%1$s]", regionName);
return regionFactory.create(regionName);
});
}
/* (non-Javadoc) */
private Cache resolveCache(GemFireCache gemfireCache) {
return Optional.ofNullable(gemfireCache)
.filter(cache -> cache instanceof Cache)
.map(cache -> (Cache) cache)
.orElseThrow(() -> newIllegalArgumentException("Peer Cache is required"));
}
/* (non-Javadoc) */
private RegionAttributes<K, V> verifyLockGrantorEligibility(RegionAttributes<K, V> regionAttributes, Scope scope) {
Optional.ofNullable(regionAttributes).ifPresent(attributes ->
Assert.state(!attributes.isLockGrantor() || verifyScope(scope),
"Lock Grantor only applies to GLOBAL Scoped Regions"));
return regionAttributes;
}
/* (non-Javadoc) */
private boolean verifyScope(Scope scope) {
return (scope == null || Scope.GLOBAL.equals(scope));
}
/**
* Creates an instance of RegionFactory using the given Cache instance used to configure and construct the Region
* created by this FactoryBean.
* Creates an instance of {@link RegionFactory} with the given {@link Cache} which is then used to construct,
* configure and initialize the {@link Region} specified by this {@link RegionFactoryBean}.
*
* @param cache the GemFire Cache instance.
* @return a RegionFactory used to configure and construct the Region created by this FactoryBean.
* @see org.apache.geode.cache.Cache#createRegionFactory()
* @see org.apache.geode.cache.Cache#createRegionFactory(org.apache.geode.cache.RegionAttributes)
* @param cache reference to the {@link Cache}.
* @return a {@link RegionFactory} used to construct, configure and initialized the {@link Region} specified by
* this {@link RegionFactoryBean}.
* @see org.apache.geode.cache.Cache#createRegionFactory(org.apache.geode.cache.RegionShortcut)
* @see org.apache.geode.cache.Cache#createRegionFactory(org.apache.geode.cache.RegionAttributes)
* @see org.apache.geode.cache.Cache#createRegionFactory()
* @see org.apache.geode.cache.RegionFactory
*/
protected RegionFactory<K, V> createRegionFactory(Cache cache) {
if (shortcut != null) {
RegionFactory<K, V> regionFactory = mergeRegionAttributes(cache.createRegionFactory(shortcut), attributes);
if (this.shortcut != null) {
RegionFactory<K, V> regionFactory =
mergeRegionAttributes(cache.createRegionFactory(this.shortcut), this.attributes);
setDataPolicy(getDataPolicy(regionFactory));
return regionFactory;
}
else if (attributes != null) {
return cache.createRegionFactory(attributes);
else if (this.attributes != null) {
return cache.createRegionFactory(this.attributes);
}
else {
return cache.createRegionFactory();
}
}
/**
* Configures the {@link RegionFactory} based on the configuration settings of this {@link RegionFactoryBean}.
*
* @param regionFactory {@link RegionFactory} to configure
* @return the given {@link RegionFactory}.
* @see org.apache.geode.cache.RegionFactory
*/
protected RegionFactory<K, V> configure(RegionFactory<K, V> regionFactory) {
stream(nullSafeArray(this.asyncEventQueues, AsyncEventQueue.class))
.forEach(asyncEventQueue -> regionFactory.addAsyncEventQueueId(asyncEventQueue.getId()));
stream(nullSafeArray(this.cacheListeners, CacheListener.class)).forEach(regionFactory::addCacheListener);
Optional.ofNullable(this.cacheLoader).ifPresent(regionFactory::setCacheLoader);
Optional.ofNullable(this.cacheWriter).ifPresent(regionFactory::setCacheWriter);
resolveDataPolicy(regionFactory, persistent, dataPolicy);
Optional.ofNullable(this.diskStoreName)
.filter(name -> isDiskStoreConfigurationAllowed())
.ifPresent(regionFactory::setDiskStoreName);
Optional.ofNullable(this.evictionAttributes).ifPresent(regionFactory::setEvictionAttributes);
stream(nullSafeArray(this.gatewaySenders, GatewaySender.class))
.forEach(gatewaySender -> regionFactory.addGatewaySenderId(((GatewaySender) gatewaySender).getId()));
Optional.ofNullable(this.keyConstraint).ifPresent(regionFactory::setKeyConstraint);
Optional.ofNullable(this.scope).ifPresent(regionFactory::setScope);
Optional.ofNullable(this.valueConstraint).ifPresent(regionFactory::setValueConstraint);
return regionFactory;
}
/**
* Post-process the {@link RegionFactory} used to create the {@link Region} specified by
* this {@link RegionFactoryBean} during initialization.
*
* The {@link RegionFactory} has been already constructed, configured and initialized by
* this {@link RegionFactoryBean} before this method gets invoked.
*
* @param regionFactory {@link RegionFactory} used to create the {@link Region}.
* @return the given {@link RegionFactory}.
* @see org.apache.geode.cache.RegionFactory
*/
protected RegionFactory<K, V> postProcess(RegionFactory<K, V> regionFactory) {
regionFactory.setOffHeap(Boolean.TRUE.equals(this.offHeap));
return regionFactory;
}
/**
* Returns a reference to the Composite {@link RegionConfigurer} used to apply additional configuration
* to this {@link RegionFactoryBean} on Spring container initialization.
*
* @return the Composite {@link RegionConfigurer}.
* @see org.springframework.data.gemfire.config.annotation.RegionConfigurer
*/
protected RegionConfigurer getCompositeRegionConfigurer() {
return this.compositeRegionConfigurer;
}
/*
* (non-Javadoc) - This method should not be considered part of the RegionFactoryBean API
* and is strictly for testing purposes!
* (non-Javadoc)
*
* This method is not considered part of the RegionFactoryBean API and is strictly used for testing purposes!
*
* NOTE cannot pass RegionAttributes.class as the "targetType" in the second invocation of getFieldValue(..)
* since the "regionAttributes" field is naively declared as a instance of the implementation class type
@@ -233,8 +376,8 @@ public abstract class RegionFactoryBean<K, V> extends RegionLookupFactoryBean<K,
*/
@SuppressWarnings({ "deprecation", "unchecked" })
DataPolicy getDataPolicy(RegionFactory regionFactory) {
return ((RegionAttributes) getFieldValue(getFieldValue(regionFactory, "attrsFactory", AttributesFactory.class),
"regionAttributes", null)).getDataPolicy();
return ((RegionAttributes) getFieldValue(getFieldValue(regionFactory, "attrsFactory",
AttributesFactory.class), "regionAttributes", null)).getDataPolicy();
}
/* (non-Javadoc) */
@@ -298,7 +441,10 @@ public abstract class RegionFactoryBean<K, V> extends RegionLookupFactoryBean<K,
regionFactory.setLockGrantor(regionAttributes.isLockGrantor());
regionFactory.setMembershipAttributes(regionAttributes.getMembershipAttributes());
regionFactory.setMulticastEnabled(regionAttributes.getMulticastEnabled());
regionFactory.setOffHeap(regionAttributes.getOffHeap());
mergePartitionAttributes(regionFactory, regionAttributes);
regionFactory.setPoolName(regionAttributes.getPoolName());
regionFactory.setRegionIdleTimeout(regionAttributes.getRegionIdleTimeout());
regionFactory.setRegionTimeToLive(regionAttributes.getRegionTimeToLive());
@@ -310,8 +456,12 @@ public abstract class RegionFactoryBean<K, V> extends RegionLookupFactoryBean<K,
return regionFactory;
}
/* (non-Javadoc) */
protected <K, V> void mergePartitionAttributes(final RegionFactory<K, V> regionFactory,
/**
*
* @param regionFactory
* @param regionAttributes
*/
protected <K, V> void mergePartitionAttributes(RegionFactory<K, V> regionFactory,
RegionAttributes<K, V> regionAttributes) {
// NOTE PartitionAttributes are created by certain RegionShortcuts; need the null check since RegionAttributes
@@ -342,8 +492,9 @@ public abstract class RegionFactoryBean<K, V> extends RegionLookupFactoryBean<K,
}
/*
* (non-Javadoc) - This method should not be considered part of the RegionFactoryBean API
* and is strictly for testing purposes!
* (non-Javadoc)
*
* This method is not part of the RegionFactoryBean API and is strictly used for testing purposes!
*
* @see org.apache.geode.cache.AttributesFactory#validateAttributes(:RegionAttributes)
*/
@@ -353,10 +504,12 @@ public abstract class RegionFactoryBean<K, V> extends RegionLookupFactoryBean<K,
}
/*
* (non-Javadoc) - This method should not be considered part of the RegionFactoryBean API
* and is strictly for testing purposes!
* (non-Javadoc)
*
* This method is not part of the RegionFactoryBean API and is strictly used for testing purposes!
*
* NOTE unfortunately, must resort to using a GemFire internal class, ugh!
*
* @see org.apache.geode.internal.cache.UserSpecifiedRegionAttributes#hasEvictionAttributes
*/
boolean isUserSpecifiedEvictionAttributes(final RegionAttributes regionAttributes) {
@@ -366,7 +519,8 @@ public abstract class RegionFactoryBean<K, V> extends RegionLookupFactoryBean<K,
/* (non-Javadoc) */
private boolean isDiskStoreConfigurationAllowed() {
boolean allow = (diskStoreName != null);
boolean allow = StringUtils.hasText(this.diskStoreName);
allow &= (getDataPolicy().withPersistence() || (getAttributes() != null
&& getAttributes().getEvictionAttributes() != null
@@ -425,41 +579,21 @@ public abstract class RegionFactoryBean<K, V> extends RegionLookupFactoryBean<K,
* @see org.apache.geode.cache.DataPolicy
*/
protected void assertDataPolicyAndPersistentAttributesAreCompatible(DataPolicy resolvedDataPolicy) {
if (resolvedDataPolicy.withPersistence()) {
Assert.isTrue(isPersistentUnspecified() || isPersistent(), String.format(
"Data Policy '%1$s' is invalid when persistent is false.", resolvedDataPolicy));
"Data Policy [%1$s] is invalid when persistent is false.", resolvedDataPolicy));
}
else {
// NOTE otherwise, the Data Policy is not persistent, so...
Assert.isTrue(isPersistentUnspecified() || isNotPersistent(), String.format(
"Data Policy '%1$s' is invalid when persistent is true.", resolvedDataPolicy));
"Data Policy [%1$s] is invalid when persistent is true.", resolvedDataPolicy));
}
}
/**
* Post-process the RegionFactory used to create the GemFire Region for this factory bean during the initialization
* process. The RegionFactory is already configured and initialized by the factory bean before this method
* is invoked.
*
* @param regionFactory the GemFire RegionFactory used to create the Region for post-processing.
* @see org.apache.geode.cache.RegionFactory
*/
protected RegionFactory<K, V> postProcess(RegionFactory<K, V> regionFactory) {
return regionFactory;
}
/**
* Post-process the Region for this factory bean during the initialization process. The Region is
* already configured and initialized by the factory bean before this method is invoked.
*
* @param region the GemFire Region to post-process.
* @see org.apache.geode.cache.Region
*/
protected Region<K, V> postProcess(Region<K, V> region) {
return region;
}
/**
=======
>>>>>>> c22ebe6... DATAGEODE-12 - Introduce Spring Configurers to flexibly alter Spring Data GemFire configuration when using Annotation config.
* Validates and sets the Data Policy on the RegionFactory used to create and configure the Region from this
* FactoryBean.
*
@@ -472,6 +606,7 @@ public abstract class RegionFactoryBean<K, V> extends RegionLookupFactoryBean<K,
* @see org.apache.geode.cache.RegionFactory
*/
protected void resolveDataPolicy(RegionFactory<K, V> regionFactory, Boolean persistent, DataPolicy dataPolicy) {
if (dataPolicy != null) {
assertDataPolicyAndPersistentAttributesAreCompatible(dataPolicy);
regionFactory.setDataPolicy(dataPolicy);
@@ -493,10 +628,11 @@ public abstract class RegionFactoryBean<K, V> extends RegionLookupFactoryBean<K,
* @see org.apache.geode.cache.RegionFactory
*/
protected void resolveDataPolicy(RegionFactory<K, V> regionFactory, Boolean persistent, String dataPolicy) {
if (dataPolicy != null) {
DataPolicy resolvedDataPolicy = new DataPolicyConverter().convert(dataPolicy);
Assert.notNull(resolvedDataPolicy, String.format("Data Policy '%1$s' is invalid.", dataPolicy));
Assert.notNull(resolvedDataPolicy, String.format("Data Policy [%1$s] is invalid.", dataPolicy));
assertDataPolicyAndPersistentAttributesAreCompatible(resolvedDataPolicy);
regionFactory.setDataPolicy(resolvedDataPolicy);
@@ -515,16 +651,21 @@ public abstract class RegionFactoryBean<K, V> extends RegionLookupFactoryBean<K,
}
/* (non-Javadoc) */
private DataPolicy getDataPolicy(final RegionAttributes regionAttributes, final DataPolicy defaultDataPolicy) {
return (regionAttributes != null ? regionAttributes.getDataPolicy() : defaultDataPolicy);
private DataPolicy getDataPolicy(RegionAttributes regionAttributes, DataPolicy defaultDataPolicy) {
return Optional.ofNullable(regionAttributes).map(RegionAttributes::getDataPolicy).orElse(defaultDataPolicy);
}
/**
* Closes and destroys the {@link Region}.
*
* @throws Exception if destroy fails.
* @see org.springframework.beans.factory.DisposableBean
*/
@Override
public void destroy() throws Exception {
Region<K, V> region = getObject();
if (region != null) {
if (close) {
Optional.ofNullable(getObject()).ifPresent(region -> {
if (this.close) {
if (!region.getRegionService().isClosed()) {
try {
region.close();
@@ -535,10 +676,10 @@ public abstract class RegionFactoryBean<K, V> extends RegionLookupFactoryBean<K,
}
if (destroy) {
if (this.destroy) {
region.destroyRegion();
}
}
});
}
/**
@@ -568,9 +709,8 @@ public abstract class RegionFactoryBean<K, V> extends RegionLookupFactoryBean<K,
* @return the RegionAttributes used to configure the Region created by this factory.
* @see org.apache.geode.cache.RegionAttributes
*/
public RegionAttributes getAttributes() {
Region<K, V> region = getRegion();
return (region != null ? region.getAttributes() : attributes);
public RegionAttributes<K, V> getAttributes() {
return Optional.ofNullable(getRegion()).map(Region::getAttributes).orElse(this.attributes);
}
/**
@@ -656,8 +796,8 @@ public abstract class RegionFactoryBean<K, V> extends RegionLookupFactoryBean<K,
* @see org.apache.geode.cache.DataPolicy
*/
public DataPolicy getDataPolicy() {
Assert.state(dataPolicy != null, "The Data Policy has not been properly resolved yet!");
return dataPolicy;
return Optional.ofNullable(this.dataPolicy)
.orElseThrow(() -> newIllegalStateException("Data Policy has not been properly resolved yet"));
}
/**
@@ -682,6 +822,37 @@ public abstract class RegionFactoryBean<K, V> extends RegionLookupFactoryBean<K,
this.gatewaySenders = gatewaySenders;
}
/**
* Sets whether to enable this {@link Region} to store it's data in off-heap memory.
*
* @param offHeap Boolean value indicating whether to enable off-heap memory for this Region.
* @see org.apache.geode.cache.RegionFactory#setOffHeap(boolean)
*/
public void setOffHeap(Boolean offHeap) {
this.offHeap = offHeap;
}
/**
* Returns a {@link Boolean} value indicating whether off-heap memory was enabled for this {@link Region}.
* Off-heap will be enabled if this method returns a non-{@literal null} {@link Boolean} value that evaluates
* to {@literal true}.
*
* @return a {@link Boolean} value indicating whether off-heap is enabled for this {@link Region}.
*/
public Boolean getOffHeap() {
return this.offHeap;
}
/**
* Returns a boolean value indicating whether off-heap has been enabled for this {@link Region}.
*
* @return a {@literal boolean} value indicating whether off-heap has been enabled for this {@link Region}.
* @see #getOffHeap()
*/
public boolean isOffHeap() {
return Boolean.TRUE.equals(getOffHeap());
}
public void setKeyConstraint(Class<K> keyConstraint) {
this.keyConstraint = keyConstraint;
}
@@ -690,6 +861,35 @@ public abstract class RegionFactoryBean<K, V> extends RegionLookupFactoryBean<K,
this.persistent = persistent;
}
/**
* Null-safe operation to set an array of {@link RegionConfigurer RegionConfigurers} used to apply
* additional configuration to this {@link RegionFactoryBean} when using Annotation-based configuration.
*
* @param regionConfigurers array of {@link RegionConfigurer RegionConfigurers} used to apply
* additional configuration to this {@link RegionFactoryBean}.
* @see org.springframework.data.gemfire.config.annotation.RegionConfigurer
* @see #setRegionConfigurers(List)
*/
public void setRegionConfigurers(RegionConfigurer... regionConfigurers) {
setRegionConfigurers(Arrays.asList(nullSafeArray(regionConfigurers, RegionConfigurer.class)));
}
/**
* Null-safe operation to set an {@link Iterable} of {@link RegionConfigurer RegionConfigurers} used to apply
* additional configuration to this {@link RegionFactoryBean} when using Annotation-based configuration.
*
* @param regionConfigurers {@link Iterable} of {@link RegionConfigurer RegionConfigurers} used to apply
* additional configuration to this {@link RegionFactoryBean}.
* @see org.springframework.data.gemfire.config.annotation.RegionConfigurer
*/
public void setRegionConfigurers(List<RegionConfigurer> regionConfigurers) {
this.regionConfigurers = Optional.ofNullable(regionConfigurers).orElseGet(Collections::emptyList);
}
public Scope getScope() {
return this.scope;
}
/**
* Sets the region scope. Used only when a new region is created. Overrides
* the settings specified through {@link #setAttributes(RegionAttributes)}.
@@ -712,23 +912,10 @@ public abstract class RegionFactoryBean<K, V> extends RegionLookupFactoryBean<K,
this.shortcut = shortcut;
}
/* (non-Javadoc) */
protected final RegionShortcut getShortcut() {
return shortcut;
}
/**
* Sets the snapshots used for loading a newly <i>created</i> region. That
* is, the snapshot will be used <i>only</i> when a new region is created -
* if the region already exists, no loading will be performed.
*
* @see #setName(String)
* @param snapshot the snapshot to set
*/
public void setSnapshot(Resource snapshot) {
this.snapshot = snapshot;
}
public void setValueConstraint(Class<V> valueConstraint) {
this.valueConstraint = valueConstraint;
}
@@ -739,6 +926,7 @@ public abstract class RegionFactoryBean<K, V> extends RegionLookupFactoryBean<K,
@Override
@SuppressWarnings("all")
public void start() {
if (!ObjectUtils.isEmpty(gatewaySenders)) {
synchronized (gatewaySenders) {
for (GatewaySender gatewaySender: gatewaySenders) {
@@ -769,6 +957,7 @@ public abstract class RegionFactoryBean<K, V> extends RegionLookupFactoryBean<K,
*/
@Override
public void stop() {
if (!ObjectUtils.isEmpty(gatewaySenders)) {
synchronized (gatewaySenders) {
for (GatewaySender gatewaySender : gatewaySenders) {

View File

@@ -16,35 +16,39 @@
package org.springframework.data.gemfire;
import static org.springframework.data.gemfire.util.RuntimeExceptionFactory.newRuntimeException;
import java.io.InputStream;
import java.util.Optional;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.geode.cache.GemFireCache;
import org.apache.geode.cache.Region;
import org.springframework.beans.factory.BeanInitializationException;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.io.Resource;
import org.springframework.data.gemfire.support.AbstractFactoryBeanSupport;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
* Spring {@link FactoryBean} for looking up generic GemFire {@link Region Regions}. If lookups are not enabled
* or the {@link Region} does not exist, an Exception is thrown.
* Spring {@link FactoryBean} for looking up {@link Region Regions}.
*
* If lookups are disabled or the {@link Region} does not exist, an exception is thrown.
*
* For declaring and configuring new Regions, see {@link RegionFactoryBean}.
*
* @author Costin Leau
* @author John Blum
* @see org.springframework.beans.factory.BeanNameAware
* @see org.apache.geode.cache.GemFireCache
* @see org.apache.geode.cache.Region
* @see org.springframework.beans.factory.FactoryBean
* @see org.springframework.beans.factory.InitializingBean
* @see org.apache.geode.cache.Region
* @see org.springframework.data.gemfire.support.AbstractFactoryBeanSupport
*/
@SuppressWarnings("unused")
public abstract class RegionLookupFactoryBean<K, V>
implements FactoryBean<Region<K, V>>, InitializingBean, BeanNameAware {
protected final Log log = LogFactory.getLog(getClass());
public abstract class RegionLookupFactoryBean<K, V> extends AbstractFactoryBeanSupport<Region<K, V>>
implements InitializingBean {
private Boolean lookupEnabled = false;
@@ -52,60 +56,109 @@ public abstract class RegionLookupFactoryBean<K, V>
private Region<?, ?> parent;
private Resource snapshot;
private volatile Region<K, V> region;
private String beanName;
private String name;
private String regionName;
/**
* @inheritDoc
* Initializes this {@link RegionLookupFactoryBean} after properties have been set by the Spring container.
*
* @throws Exception if initialization fails.
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
* @see #createRegion(GemFireCache, String)
*/
@Override
@SuppressWarnings("all")
public void afterPropertiesSet() throws Exception {
Assert.notNull(this.cache, "A 'Cache' reference must be set");
GemFireCache cache = getCache();
Assert.notNull(cache, "Cache is required");
String regionName = resolveRegionName();
Assert.hasText(regionName, "'regionName', 'name' or 'beanName' property must be set");
Assert.hasText(regionName, "regionName, name or beanName property must be set");
synchronized (this.cache) {
if (isLookupEnabled()) {
this.region = Optional.ofNullable(getParent())
synchronized (cache) {
setRegion(isLookupEnabled()
? Optional.ofNullable(getParent())
.map(parentRegion -> parentRegion.<K, V>getSubregion(regionName))
.orElseGet(() -> this.cache.<K, V>getRegion(regionName));
}
.orElseGet(() -> cache.<K, V>getRegion(regionName))
: null);
if (region != null) {
log.info(String.format("Found Region [%1$s] in Cache [%2$s]", regionName, cache.getName()));
if (getRegion() != null) {
logInfo("Found Region [%1$s] in Cache [%2$s]", regionName, cache.getName());
}
else {
log.info(String.format("Falling back to creating Region [%1$s] in Cache [%2$s]",
regionName, cache.getName()));
logInfo("Falling back to creating Region [%1$s] in Cache [%2$s]",
regionName, cache.getName());
region = lookupRegion(cache, regionName);
setRegion(postProcess(loadSnapshot(createRegion(cache, regionName))));
}
}
}
/**
* Method to perform a lookup when the named {@link Region} does not exist. By default, this implementation
* throws an exception.
* Creates a new {@link Region} with the given {@link String name}.
*
* @param cache reference to the GemFire cache.
* @param regionName name of the GemFire {@link Region}.
* @return the {@link Region} in the GemFire cache with the given name.
* @throws BeanInitializationException if the lookup operation fails.
* This method gets called when a {@link Region} with the specified {@link String name} does not already exist.
* By default, this method implementation throws a {@link BeanInitializationException} and it is expected
* that {@link Class subclasses} will override this method.
*
* @param cache reference to the {@link GemFireCache}.
* @param regionName {@link String name} of the new {@link Region}.
* @return a new {@link Region} with the given {@link String name}.
* @throws BeanInitializationException by default unless a {@link Class subclass} overrides this method.
* @see org.apache.geode.cache.GemFireCache
* @see org.apache.geode.cache.Region
*/
protected Region<K, V> lookupRegion(GemFireCache cache, String regionName) throws Exception {
throw new BeanInitializationException(String.format(
"Region [%1$s] in Cache [%2$s] not found", regionName, cache));
protected Region<K, V> createRegion(GemFireCache cache, String regionName) throws Exception {
throw new BeanInitializationException(
String.format("Region [%1$s] in Cache [%2$s] not found", regionName, cache));
}
/**
* @inheritDoc
* Loads the configured data {@link Resource snapshot} into the given {@link Region}.
*
* @param region {@link Region} to load.
* @return the given {@link Region}.
* @throws RuntimeException if the snapshot load fails.
* @see org.apache.geode.cache.Region#loadSnapshot(InputStream)
*/
protected Region<K, V> loadSnapshot(Region<K, V> region) {
Optional.ofNullable(this.snapshot).ifPresent(snapshot -> {
try {
region.loadSnapshot(snapshot.getInputStream());
}
catch (Exception e) {
throw newRuntimeException(e, "Failed to load snapshot [%s]", snapshot);
}
});
return region;
}
/**
* Post-process the {@link Region} created by this {@link RegionFactoryBean}.
*
* @param region {@link Region} to process.
* @see org.apache.geode.cache.Region
*/
protected Region<K, V> postProcess(Region<K, V> region) {
return region;
}
/**
* Returns an object reference to the {@link Region} created by this {@link RegionLookupFactoryBean}.
*
* @return an object reference to the {@link Region} created by this {@link RegionLookupFactoryBean}.
* @see org.springframework.beans.factory.FactoryBean#getObject()
* @see org.apache.geode.cache.Region
* @see #getRegion()
*/
@Override
public Region<K, V> getObject() throws Exception {
@@ -113,49 +166,42 @@ public abstract class RegionLookupFactoryBean<K, V>
}
/**
* @inheritDoc
*/
@Override
public Class<?> getObjectType() {
Region region = getRegion();
return (region != null ? region.getClass() : Region.class);
}
/**
* @inheritDoc
*/
@Override
public boolean isSingleton() {
return true;
}
/**
* Resolves the name of the GemFire {@link Region}.
* Returns the {@link Class} type of the {@link Region} produced by this {@link RegionLookupFactoryBean}.
*
* @return a {@link String} indicating the name of the GemFire {@link Region}.
* @return the {@link Class} type of the {@link Region} produced by this {@link RegionLookupFactoryBean}.
* @see org.springframework.beans.factory.FactoryBean#getObjectType()
*/
@Override
@SuppressWarnings("unchecked")
public Class<?> getObjectType() {
return Optional.ofNullable(getRegion()).map(Region::getClass).orElse((Class) Region.class);
}
/**
* Resolves the {@link String name} of the {@link Region}.
*
* @return a {@link String} containing the name of the {@link Region}.
* @see org.apache.geode.cache.Region#getName()
*/
public String resolveRegionName() {
return (StringUtils.hasText(this.regionName) ? this.regionName
: (StringUtils.hasText(this.name) ? this.name : this.beanName));
: (StringUtils.hasText(this.name) ? this.name : getBeanName()));
}
/**
* Sets the name of the {@link Region} based on the bean 'id' attribute. If no {@link Region} is found
* with the given name, a new one will be created.
* Returns a reference to the {@link GemFireCache} used to create the {@link Region}.
*
* @param name name of this {@link Region} bean in the Spring {@link org.springframework.context.ApplicationContext}.
* @see org.springframework.beans.factory.BeanNameAware#setBeanName(String)
* @return a reference to the {@link GemFireCache} used to create the {@link Region}..
* @see org.apache.geode.cache.GemFireCache
*/
public void setBeanName(String name) {
this.beanName = name;
public GemFireCache getCache() {
return this.cache;
}
/**
* Sets a reference to the {@link GemFireCache} used to create the {@link Region}.
*
* @param cache reference to the {@link GemFireCache}.
* @see org.springframework.data.gemfire.CacheFactoryBean
* @see org.apache.geode.cache.GemFireCache
*/
public void setCache(GemFireCache cache) {
@@ -174,7 +220,7 @@ public abstract class RegionLookupFactoryBean<K, V>
/* (non-Javadoc) */
public Boolean getLookupEnabled() {
return lookupEnabled;
return this.lookupEnabled;
}
/**
@@ -213,13 +259,23 @@ public abstract class RegionLookupFactoryBean<K, V>
}
/**
* Returns a reference to the GemFire {@link Region} resolved by this Spring {@link FactoryBean}
* during the lookup operation; maybe a new {@link Region}.
* Sets a reference to the {@link Region} to be resolved by this Spring {@link FactoryBean}.
*
* @return a reference to the GemFire {@link Region} resolved during lookup.
* @param region reference to the resolvable {@link Region}.
* @see org.apache.geode.cache.Region
*/
protected Region<K, V> getRegion() {
protected void setRegion(Region<K, V> region) {
this.region = region;
}
/**
* Returns a reference to the {@link Region} resolved by this Spring {@link FactoryBean}
* during the lookup operation; maybe a new {@link Region}.
*
* @return a reference to the {@link Region} resolved during lookup.
* @see org.apache.geode.cache.Region
*/
public Region<K, V> getRegion() {
return this.region;
}
@@ -233,4 +289,16 @@ public abstract class RegionLookupFactoryBean<K, V>
public void setRegionName(String regionName) {
this.regionName = regionName;
}
/**
* Sets the snapshots used for loading a newly <i>created</i> region. That
* is, the snapshot will be used <i>only</i> when a new region is created -
* if the region already exists, no loading will be performed.
*
* @see #setName(String)
* @param snapshot the snapshot to set
*/
public void setSnapshot(Resource snapshot) {
this.snapshot = snapshot;
}
}

View File

@@ -16,9 +16,19 @@
package org.springframework.data.gemfire.client;
import static java.util.stream.StreamSupport.stream;
import static org.springframework.data.gemfire.util.ArrayUtils.nullSafeArray;
import static org.springframework.data.gemfire.util.CollectionUtils.nullSafeCollection;
import static org.springframework.data.gemfire.util.CollectionUtils.nullSafeIterable;
import java.net.InetSocketAddress;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Properties;
import java.util.concurrent.atomic.AtomicBoolean;
import org.apache.geode.cache.CacheClosedException;
import org.apache.geode.cache.GemFireCache;
@@ -27,34 +37,32 @@ import org.apache.geode.cache.client.ClientCacheFactory;
import org.apache.geode.cache.client.Pool;
import org.apache.geode.cache.client.PoolManager;
import org.apache.geode.distributed.DistributedSystem;
import org.apache.geode.pdx.PdxSerializer;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ApplicationContextEvent;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.data.gemfire.CacheFactoryBean;
import org.springframework.data.gemfire.GemfireUtils;
import org.springframework.data.gemfire.client.support.DefaultableDelegatingPoolAdapter;
import org.springframework.data.gemfire.client.support.DelegatingPoolAdapter;
import org.springframework.data.gemfire.config.annotation.ClientCacheConfigurer;
import org.springframework.data.gemfire.config.xml.GemfireConstants;
import org.springframework.data.gemfire.support.ConnectionEndpoint;
import org.springframework.data.gemfire.support.ConnectionEndpointList;
import org.springframework.data.gemfire.util.SpringUtils;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
/**
* FactoryBean dedicated to creating GemFire client caches.
* Spring {@link org.springframework.beans.factory.FactoryBean} used to create a Pivotal GemFire/Apache Geode
* {@link ClientCache}.
*
* @author Costin Leau
* @author Lyndon Adams
* @author John Blum
* @see org.springframework.context.ApplicationListener
* @see org.springframework.context.event.ContextRefreshedEvent
* @see org.springframework.data.gemfire.CacheFactoryBean
* @see org.springframework.data.gemfire.support.ConnectionEndpoint
* @see org.springframework.data.gemfire.support.ConnectionEndpointList
* @see java.net.InetSocketAddress
* @see org.apache.geode.cache.GemFireCache
* @see org.apache.geode.cache.client.ClientCache
* @see org.apache.geode.cache.client.ClientCacheFactory
@@ -62,6 +70,14 @@ import org.springframework.util.ObjectUtils;
* @see org.apache.geode.cache.client.PoolManager
* @see org.apache.geode.distributed.DistributedSystem
* @see org.apache.geode.pdx.PdxSerializer
* @see org.springframework.beans.factory.BeanFactory
* @see org.springframework.context.ApplicationContext
* @see org.springframework.context.ApplicationListener
* @see org.springframework.context.event.ContextRefreshedEvent
* @see org.springframework.data.gemfire.CacheFactoryBean
* @see org.springframework.data.gemfire.config.annotation.ClientCacheConfigurer
* @see org.springframework.data.gemfire.support.ConnectionEndpoint
* @see org.springframework.data.gemfire.support.ConnectionEndpointList
*/
@SuppressWarnings("unused")
public class ClientCacheFactoryBean extends CacheFactoryBean implements ApplicationListener<ContextRefreshedEvent> {
@@ -89,6 +105,8 @@ public class ClientCacheFactoryBean extends CacheFactoryBean implements Applicat
private Integer subscriptionMessageTrackingTimeout;
private Integer subscriptionRedundancy;
private List<ClientCacheConfigurer> clientCacheConfigurers = Collections.emptyList();
private Long idleTimeout;
private Long pingInterval;
@@ -98,37 +116,83 @@ public class ClientCacheFactoryBean extends CacheFactoryBean implements Applicat
private String poolName;
private String serverGroup;
private final ClientCacheConfigurer compositeClientCacheConfigurer = (beanName, bean) ->
nullSafeCollection(clientCacheConfigurers).forEach(clientCacheConfigurer ->
clientCacheConfigurer.configure(beanName, bean));
/**
* Post processes this {@link ClientCacheFactoryBean} before cache initialization.
*
* This is also the point at which any configured {@link ClientCacheConfigurer} beans are called.
*
* @param gemfireProperties {@link Properties} used to configure Pivotal GemFire/Apache Geode.
* @see org.springframework.data.gemfire.config.annotation.ClientCacheConfigurer
* @see java.util.Properties
*/
@Override
protected void postProcessBeforeCacheInitialization(Properties gemfireProperties) {
applyClientCacheConfigurers();
}
/* (non-Javadoc) */
private void applyClientCacheConfigurers() {
applyClientCacheConfigurers(this.compositeClientCacheConfigurer);
}
/**
* Fetches an existing GemFire ClientCache instance from the ClientCacheFactory.
* Null-safe operation to apply the given array of {@link ClientCacheConfigurer ClientCacheConfigurers}
* to this {@link ClientCacheFactoryBean}.
*
* @param <T> is Class type extension of GemFireCache.
* @return the existing GemFire ClientCache instance if available.
* @throws org.apache.geode.cache.CacheClosedException if an existing GemFire Cache instance does not exist.
* @throws java.lang.IllegalStateException if the GemFire cache instance is not a ClientCache.
* @see org.apache.geode.cache.GemFireCache
* @param clientCacheConfigurers array of {@link ClientCacheConfigurer ClientCacheConfigurers} applied to
* this {@link ClientCacheFactoryBean}.
* @see org.springframework.data.gemfire.config.annotation.ClientCacheConfigurer
* @see #applyClientCacheConfigurers(Iterable)
*/
protected void applyClientCacheConfigurers(ClientCacheConfigurer... clientCacheConfigurers) {
applyClientCacheConfigurers(Arrays.asList(nullSafeArray(clientCacheConfigurers, ClientCacheConfigurer.class)));
}
/**
* Null-safe operation to apply the given {@link Iterable} of {@link ClientCacheConfigurer ClientCacheConfigurers}
* to this {@link ClientCacheFactoryBean}.
*
* @param clientCacheConfigurers {@link Iterable} of {@link ClientCacheConfigurer ClientCacheConfigurers}
* applied to this {@link ClientCacheFactoryBean}.
* @see org.springframework.data.gemfire.config.annotation.ClientCacheConfigurer
* @see java.lang.Iterable
*/
protected void applyClientCacheConfigurers(Iterable<ClientCacheConfigurer> clientCacheConfigurers) {
stream(nullSafeIterable(clientCacheConfigurers).spliterator(), false)
.forEach(clientCacheConfigurer -> clientCacheConfigurer.configure(getBeanName(), this));
}
/**
* Fetches an existing {@link ClientCache} instance from the {@link ClientCacheFactory}.
*
* @param <T> parameterized {@link Class} type extension of {@link GemFireCache}.
* @return an existing {@link ClientCache} instance if available.
* @throws org.apache.geode.cache.CacheClosedException if an existing {@link ClientCache} instance does not exist.
* @see org.apache.geode.cache.client.ClientCacheFactory#getAnyInstance()
* @see org.apache.geode.cache.GemFireCache
* @see #getCache()
*/
@Override
@SuppressWarnings("unchecked")
protected <T extends GemFireCache> T fetchCache() {
ClientCache cache = getCache();
return (T) (cache != null ? cache : ClientCacheFactory.getAnyInstance());
return (T) Optional.ofNullable(getCache()).orElseGet(ClientCacheFactory::getAnyInstance);
}
/**
* Resolves the GemFire System properties used to configure the GemFire ClientCache instance.
* Resolves the Pivotal GemFire/Apache Geode {@link Properties} used to configure the {@link ClientCache}.
*
* @return a Properties object containing GemFire System properties used to configure
* the GemFire ClientCache instance.
* @return the resolved Pivotal GemFire/Apache Geode {@link Properties} used to configure the {@link ClientCache}.
* @see org.apache.geode.distributed.DistributedSystem#getProperties()
* @see #getDistributedSystem()
*/
@Override
protected Properties resolveProperties() {
Properties gemfireProperties = super.resolveProperties();
Properties gemfireProperties = super.resolveProperties();
DistributedSystem distributedSystem = getDistributedSystem();
if (GemfireUtils.isConnected(distributedSystem)) {
@@ -137,24 +201,32 @@ public class ClientCacheFactoryBean extends CacheFactoryBean implements Applicat
gemfireProperties = distributedSystemProperties;
}
GemfireUtils.configureDurableClient(gemfireProperties, durableClientId, durableClientTimeout);
GemfireUtils.configureDurableClient(gemfireProperties, getDurableClientId(), getDurableClientTimeout());
return gemfireProperties;
}
/* (non-Javadoc) */
/**
* Returns the {@link DistributedSystem} formed from cache initialization.
*
* @param <T> {@link Class} type of the {@link DistributedSystem}.
* @return an instance of the {@link DistributedSystem}.
* @see org.apache.geode.distributed.DistributedSystem
*/
<T extends DistributedSystem> T getDistributedSystem() {
return GemfireUtils.getDistributedSystem();
}
/**
* Creates an instance of GemFire factory initialized with the given GemFire System Properties
* to create an instance of a GemFire cache.
* Constructs a new instance of {@link ClientCacheFactory} initialized with the given Pivotal GemFire/Apache Geode
* {@link Properties} used to create an instance of a {@link ClientCache}.
*
* @param gemfireProperties a Properties object containing GemFire System properties.
* @return an instance of a GemFire factory used to create a GemFire cache instance.
* @see java.util.Properties
* @param gemfireProperties {@link Properties} used by the {@link ClientCacheFactory}
* to configure the {@link ClientCache}.
* @return a new instance of {@link ClientCacheFactory} initialized with the given Pivotal GemFire/Apache Geode
* {@link Properties}.
* @see org.apache.geode.cache.client.ClientCacheFactory
* @see java.util.Properties
*/
@Override
protected Object createFactory(Properties gemfireProperties) {
@@ -162,61 +234,52 @@ public class ClientCacheFactoryBean extends CacheFactoryBean implements Applicat
}
/**
* Initializes the GemFire factory used to create the GemFire client cache instance. Sets PDX options
* specified by the user.
* Prepares and initializes the {@link ClientCacheFactory} used to create the {@link ClientCache}.
*
* @param factory the GemFire factory used to create an instance of the GemFire client cache.
* @return the initialized GemFire client cache factory.
* @see #isPdxOptionsSpecified()
* Sets PDX options specified by the user.
*
* @param factory {@link ClientCacheFactory} used to create the {@link ClientCache}.
* @return the prepared and initialized {@link ClientCacheFactory}.
* @see #initializePdx(ClientCacheFactory)
*/
@Override
protected Object prepareFactory(final Object factory) {
protected Object prepareFactory(Object factory) {
return initializePool(initializePdx((ClientCacheFactory) factory));
}
/**
* Initialize the PDX settings on the {@link ClientCacheFactory}.
* Configure PDX for the {@link ClientCacheFactory}.
*
* @param clientCacheFactory the GemFire {@link ClientCacheFactory} used to configure and create
* a GemFire {@link ClientCache}.
* @param clientCacheFactory {@link ClientCacheFactory} used to configure PDX.
* @return the given {@link ClientCacheFactory}
* @see org.apache.geode.cache.client.ClientCacheFactory
*/
ClientCacheFactory initializePdx(ClientCacheFactory clientCacheFactory) {
if (isPdxOptionsSpecified()) {
if (getPdxSerializer() != null) {
Assert.isInstanceOf(PdxSerializer.class, getPdxSerializer(),
String.format("[%1$s] of type [%2$s] is not a PdxSerializer;", getPdxSerializer(),
ObjectUtils.nullSafeClassName(getPdxSerializer())));
clientCacheFactory.setPdxSerializer((PdxSerializer) getPdxSerializer());
}
if (getPdxDiskStoreName() != null) {
clientCacheFactory.setPdxDiskStore(getPdxDiskStoreName());
}
if (getPdxIgnoreUnreadFields() != null) {
clientCacheFactory.setPdxIgnoreUnreadFields(getPdxIgnoreUnreadFields());
}
if (getPdxPersistent() != null) {
clientCacheFactory.setPdxPersistent(getPdxPersistent());
}
if (getPdxReadSerialized() != null) {
clientCacheFactory.setPdxReadSerialized(getPdxReadSerialized());
}
}
Optional.ofNullable(getPdxSerializer()).ifPresent(clientCacheFactory::setPdxSerializer);
Optional.ofNullable(getPdxDiskStoreName()).filter(StringUtils::hasText)
.ifPresent(clientCacheFactory::setPdxDiskStore);
Optional.ofNullable(getPdxIgnoreUnreadFields()).ifPresent(clientCacheFactory::setPdxIgnoreUnreadFields);
Optional.ofNullable(getPdxPersistent()).ifPresent(clientCacheFactory::setPdxPersistent);
Optional.ofNullable(getPdxReadSerialized()).ifPresent(clientCacheFactory::setPdxReadSerialized);
return clientCacheFactory;
}
/**
* Initialize the {@link Pool} settings on the {@link ClientCacheFactory} with a given {@link Pool} instance
* or named {@link Pool}.
* Configure the {@literal DEFAULT} {@link Pool} configuration settings with the {@link ClientCacheFactory}
* using a given {@link Pool} instance or a named {@link Pool}.
*
* @param clientCacheFactory the GemFire {@link ClientCacheFactory} used to configure and create
* a GemFire {@link ClientCache}.
* @param clientCacheFactory {@link ClientCacheFactory} use to configure the {@literal DEFAULT} {@link Pool}.
* @see org.apache.geode.cache.client.ClientCacheFactory
* @see org.apache.geode.cache.client.Pool
*/
ClientCacheFactory initializePool(ClientCacheFactory clientCacheFactory) {
DefaultableDelegatingPoolAdapter pool = DefaultableDelegatingPoolAdapter.from(
DelegatingPoolAdapter.from(resolvePool())).preferDefault();
@@ -239,48 +302,51 @@ public class ClientCacheFactoryBean extends CacheFactoryBean implements Applicat
clientCacheFactory.setPoolSubscriptionRedundancy(pool.getSubscriptionRedundancy(getSubscriptionRedundancy()));
clientCacheFactory.setPoolThreadLocalConnections(pool.getThreadLocalConnections(getThreadLocalConnections()));
boolean noServers = getServers().isEmpty();
boolean hasServers = !noServers;
final AtomicBoolean noServers = new AtomicBoolean(getServers().isEmpty());
boolean hasServers = !noServers.get();
boolean noLocators = getLocators().isEmpty();
boolean hasLocators = !noLocators;
if (hasServers || noLocators) {
Iterable<InetSocketAddress> servers = pool.getServers(getServers().toInetSocketAddresses());
for (InetSocketAddress server : servers) {
stream(servers.spliterator(), false).forEach(server -> {
clientCacheFactory.addPoolServer(server.getHostName(), server.getPort());
noServers = false;
}
noServers.set(false);
});
}
if (hasLocators || noServers) {
if (hasLocators || noServers.get()) {
Iterable<InetSocketAddress> locators = pool.getLocators(getLocators().toInetSocketAddresses());
for (InetSocketAddress locator : locators) {
clientCacheFactory.addPoolLocator(locator.getHostName(), locator.getPort());
}
stream(locators.spliterator(), false).forEach(locator ->
clientCacheFactory.addPoolLocator(locator.getHostName(), locator.getPort()));
}
return clientCacheFactory;
}
/**
* Resolves the appropriate GemFire {@link Pool} from Spring configuration that will be used to configure
* the GemFire {@link ClientCache}.
* Resolves an appropriate {@link Pool} from the Spring container that will be used to configure
* the {@link ClientCache}.
*
* @return the resolved GemFire {@link Pool}.
* @see org.apache.geode.cache.client.PoolManager#find(String)
* @return the resolved {@link Pool}.
* @see org.apache.geode.cache.client.Pool
* @see #findPool(String)
*/
Pool resolvePool() {
Pool localPool = getPool();
if (localPool == null) {
String poolName = SpringUtils.defaultIfNull(getPoolName(), GemfireConstants.DEFAULT_GEMFIRE_POOL_NAME);
String poolName = Optional.ofNullable(getPoolName()).filter(StringUtils::hasText)
.orElse(GemfireConstants.DEFAULT_GEMFIRE_POOL_NAME);
localPool = findPool(poolName);
if (localPool == null) {
BeanFactory beanFactory = getBeanFactory();
if (beanFactory instanceof ListableBeanFactory) {
@@ -295,8 +361,8 @@ public class ClientCacheFactoryBean extends CacheFactoryBean implements Applicat
}
}
catch (BeansException e) {
log.info(String.format("unable to resolve bean of type [%1$s] with name [%2$s]",
PoolFactoryBean.class.getName(), poolName));
logInfo("Unable to resolve bean of type [%1$s] with name [%2$s]",
PoolFactoryBean.class.getName(), poolName);
}
}
}
@@ -306,11 +372,11 @@ public class ClientCacheFactoryBean extends CacheFactoryBean implements Applicat
}
/**
* Attempts to find a GemFire {@link Pool} with the given name.
* Attempts to find a {@link Pool} with the given {@link String name}.
*
* @param name a String indicating the name of the GemFire {@link Pool} to find.
* @return a {@link Pool} instance with the given name registered in GemFire or <code>null</code> if no {@link Pool}
* with name exists.
* @param name {@link String} containing the name of the {@link Pool} to find.
* @return a {@link Pool} instance with the given {@link String name} registered in GemFire/Geode
* or {@literal null} if no {@link Pool} with the given {@link String name} exists.
* @see org.apache.geode.cache.client.PoolManager#find(String)
* @see org.apache.geode.cache.client.Pool
*/
@@ -319,11 +385,11 @@ public class ClientCacheFactoryBean extends CacheFactoryBean implements Applicat
}
/**
* Creates a new GemFire cache instance using the provided factory.
* Creates a new {@link ClientCache} instance using the provided factory.
*
* @param <T> parameterized Class type extension of {@link GemFireCache}.
* @param factory the appropriate GemFire factory used to create a cache instance.
* @return an instance of the GemFire cache.
* @param <T> parameterized {@link Class} type extension of {@link GemFireCache}.
* @param factory instance of {@link ClientCacheFactory}.
* @return a new instance of {@link ClientCache} created by the provided factory.
* @see org.apache.geode.cache.client.ClientCacheFactory#create()
* @see org.apache.geode.cache.GemFireCache
*/
@@ -334,28 +400,36 @@ public class ClientCacheFactoryBean extends CacheFactoryBean implements Applicat
}
/**
* Inform the GemFire cluster that this client cache is ready to receive events iff the client is non-durable.
* Inform the Pivotal GemFire/Apache Geode cluster that this cache client is ready to receive events
* iff the client is non-durable.
*
* @param event the ApplicationContextEvent fired when the ApplicationContext is refreshed.
* @param event {@link ApplicationContextEvent} fired when the {@link ApplicationContext} is refreshed.
* @see org.apache.geode.cache.client.ClientCache#readyForEvents()
* @see #getReadyForEvents()
* @see #getObject()
* @see #isReadyForEvents()
* @see #fetchCache()
*/
@Override
public void onApplicationEvent(final ContextRefreshedEvent event) {
public void onApplicationEvent(ContextRefreshedEvent event) {
if (isReadyForEvents()) {
try {
((ClientCache) fetchCache()).readyForEvents();
this.<ClientCache>fetchCache().readyForEvents();
}
catch (IllegalStateException | CacheClosedException ignore) {
// IllegalStateException thrown if clientCache.readyForEvents() is called on a non-durable client
// CacheClosedException is throw when cache is closed or was shutdown so ready-for-events is moot
// thrown if clientCache.readyForEvents() is called on a non-durable client
}
}
}
/**
<<<<<<< HEAD
* @inheritDoc
=======
* Null-safe internal method used to close the {@link ClientCache} and preserve durability.
*
* @param cache {@link GemFireCache} to close.
* @see org.apache.geode.cache.client.ClientCache#close(boolean)
* @see #isKeepAlive()
>>>>>>> c22ebe6... DATAGEODE-12 - Introduce Spring Configurers to flexibly alter Spring Data GemFire configuration when using Annotation config.
*/
@Override
protected void close(GemFireCache cache) {
@@ -363,12 +437,19 @@ public class ClientCacheFactoryBean extends CacheFactoryBean implements Applicat
}
/**
<<<<<<< HEAD
* @inheritDoc
=======
* Returns the {@link Class} type of the {@link GemFireCache} produced by this {@link ClientCacheFactoryBean}.
*
* @return the {@link Class} type of the {@link GemFireCache} produced by this {@link ClientCacheFactoryBean}.
* @see org.springframework.beans.factory.FactoryBean#getObjectType()
>>>>>>> c22ebe6... DATAGEODE-12 - Introduce Spring Configurers to flexibly alter Spring Data GemFire configuration when using Annotation config.
*/
@Override
@SuppressWarnings("unchecked")
public Class<? extends GemFireCache> getObjectType() {
ClientCache cache = getCache();
return (cache != null ? cache.getClass() : ClientCache.class);
return Optional.ofNullable(getCache()).map(Object::getClass).orElse((Class) ClientCache.class);
}
/* (non-Javadoc) */
@@ -391,6 +472,42 @@ public class ClientCacheFactoryBean extends CacheFactoryBean implements Applicat
this.servers.add(servers);
}
/**
* Null-safe operation to set an array of {@link ClientCacheConfigurer ClientCacheConfigurers} used to apply
* additional configuration to this {@link ClientCacheFactoryBean} when using Annotation-based configuration.
*
* @param clientCacheConfigurers array of {@link ClientCacheConfigurer ClientCacheConfigurers} used to apply
* additional configuration to this {@link ClientCacheFactoryBean}.
* @see org.springframework.data.gemfire.config.annotation.ClientCacheConfigurer
* @see #setClientCacheConfigurers(List)
*/
public void setClientCacheConfigurers(ClientCacheConfigurer... clientCacheConfigurers) {
setClientCacheConfigurers(Arrays.asList(nullSafeArray(clientCacheConfigurers, ClientCacheConfigurer.class)));
}
/**
* Null-safe operation to set an {@link Iterable} of {@link ClientCacheConfigurer ClientCacheConfigurers} to apply
* additional configuration to this {@link ClientCacheFactoryBean} when using Annotation-based configuration.
*
* @param peerCacheConfigurers {@link Iterable} of {@link ClientCacheConfigurer ClientCacheConfigurers} used to apply
* additional configuration to this {@link ClientCacheFactoryBean}.
* @see org.springframework.data.gemfire.config.annotation.ClientCacheConfigurer
*/
public void setClientCacheConfigurers(List<ClientCacheConfigurer> peerCacheConfigurers) {
this.clientCacheConfigurers = Optional.ofNullable(peerCacheConfigurers).orElseGet(Collections::emptyList);
}
/**
* Returns a reference to the Composite {@link ClientCacheConfigurer} used to apply additional configuration
* to this {@link ClientCacheFactoryBean} on Spring container initialization.
*
* @return the Composite {@link ClientCacheConfigurer}.
* @see org.springframework.data.gemfire.config.annotation.ClientCacheConfigurer
*/
public ClientCacheConfigurer getCompositeClientCacheConfigurer() {
return this.compositeClientCacheConfigurer;
}
/**
* Set the GemFire System property 'durable-client-id' to indicate to the server that this client is durable.
*
@@ -407,7 +524,7 @@ public class ClientCacheFactoryBean extends CacheFactoryBean implements Applicat
* @return a String value indicating the durable client id.
*/
public String getDurableClientId() {
return durableClientId;
return this.durableClientId;
}
/**
@@ -429,15 +546,15 @@ public class ClientCacheFactoryBean extends CacheFactoryBean implements Applicat
* the durable client's queue around.
*/
public Integer getDurableClientTimeout() {
return durableClientTimeout;
return this.durableClientTimeout;
}
/**
* @inheritDoc
*/
@Override
public final void setEnableAutoReconnect(final Boolean enableAutoReconnect) {
throw new UnsupportedOperationException("Auto-reconnect does not apply to clients.");
public final void setEnableAutoReconnect(Boolean enableAutoReconnect) {
throw new UnsupportedOperationException("Auto-reconnect does not apply to clients");
}
/**
@@ -572,7 +689,7 @@ public class ClientCacheFactoryBean extends CacheFactoryBean implements Applicat
* to the GemFire cluster.
*/
public Pool getPool() {
return pool;
return this.pool;
}
/**
@@ -780,7 +897,7 @@ public class ClientCacheFactoryBean extends CacheFactoryBean implements Applicat
*/
@Override
public final void setUseClusterConfiguration(Boolean useClusterConfiguration) {
throw new UnsupportedOperationException("Shared, cluster-based configuration is not applicable for clients.");
throw new UnsupportedOperationException("Cluster-based Configuration is not applicable for clients");
}
/**

View File

@@ -16,10 +16,18 @@
package org.springframework.data.gemfire.client;
import static java.util.Arrays.stream;
import static org.springframework.data.gemfire.util.ArrayUtils.nullSafeArray;
import static org.springframework.data.gemfire.util.CollectionUtils.nullSafeCollection;
import static org.springframework.data.gemfire.util.CollectionUtils.nullSafeIterable;
import static org.springframework.data.gemfire.util.RuntimeExceptionFactory.newIllegalArgumentException;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.stream.StreamSupport;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.geode.cache.CacheListener;
import org.apache.geode.cache.CacheLoader;
import org.apache.geode.cache.CacheWriter;
@@ -33,28 +41,22 @@ import org.apache.geode.cache.client.ClientRegionFactory;
import org.apache.geode.cache.client.ClientRegionShortcut;
import org.apache.geode.cache.client.Pool;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.core.io.Resource;
import org.springframework.data.gemfire.DataPolicyConverter;
import org.springframework.data.gemfire.GemfireUtils;
import org.springframework.data.gemfire.RegionLookupFactoryBean;
import org.springframework.data.gemfire.config.annotation.RegionConfigurer;
import org.springframework.data.gemfire.config.xml.GemfireConstants;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
* Spring {@link FactoryBean} used to create a GemFire client cache {@link Region}.
* Spring {@link FactoryBean} used to construct, configure and initialize a client {@link Region}.
*
* @author Costin Leau
* @author David Turanski
* @author John Blum
* @see org.springframework.beans.factory.BeanFactory
* @see org.springframework.beans.factory.BeanFactoryAware
* @see org.springframework.beans.factory.DisposableBean
* @see org.springframework.data.gemfire.RegionLookupFactoryBean
* @see org.apache.geode.cache.DataPolicy
* @see org.apache.geode.cache.EvictionAttributes
* @see org.apache.geode.cache.GemFireCache
@@ -64,18 +66,18 @@ import org.springframework.util.StringUtils;
* @see org.apache.geode.cache.client.ClientRegionFactory
* @see org.apache.geode.cache.client.ClientRegionShortcut
* @see org.apache.geode.cache.client.Pool
* @see org.springframework.beans.factory.DisposableBean
* @see org.springframework.beans.factory.FactoryBean
* @see org.springframework.data.gemfire.DataPolicyConverter
* @see org.springframework.data.gemfire.RegionLookupFactoryBean
* @see org.springframework.data.gemfire.config.annotation.RegionConfigurer
*/
@SuppressWarnings("unused")
public class ClientRegionFactoryBean<K, V> extends RegionLookupFactoryBean<K, V>
implements BeanFactoryAware, DisposableBean {
private static final Log log = LogFactory.getLog(ClientRegionFactoryBean.class);
public class ClientRegionFactoryBean<K, V> extends RegionLookupFactoryBean<K, V> implements DisposableBean {
private boolean close = false;
private boolean destroy = false;
private BeanFactory beanFactory;
private Boolean persistent;
private CacheListener<K, V>[] cacheListeners;
@@ -87,7 +89,7 @@ public class ClientRegionFactoryBean<K, V> extends RegionLookupFactoryBean<K, V>
private Class<K> keyConstraint;
private Class<V> valueConstraint;
private ClientRegionShortcut shortcut = null;
private ClientRegionShortcut shortcut;
private DataPolicy dataPolicy;
@@ -95,97 +97,183 @@ public class ClientRegionFactoryBean<K, V> extends RegionLookupFactoryBean<K, V>
private Interest<K>[] interests;
private List<RegionConfigurer> regionConfigurers = Collections.emptyList();
private RegionAttributes<K, V> attributes;
private Resource snapshot;
private RegionConfigurer compositeRegionConfigurer = new RegionConfigurer() {
@Override
public void configure(String beanName, ClientRegionFactoryBean<?, ?> bean) {
nullSafeCollection(regionConfigurers)
.forEach(regionConfigurer -> regionConfigurer.configure(beanName, bean));
}
};
private String diskStoreName;
private String poolName;
/**
* @inheritDoc
* Creates a new {@link Region} with the given {@link String name}.
*
* @param gemfireCache reference to the {@link GemFireCache}.
* @param regionName {@link String name} of the new {@link Region}.
* @return a new {@link Region} with the given {@link String name}.
* @see org.apache.geode.cache.GemFireCache
* @see org.apache.geode.cache.Region
*/
@Override
public void afterPropertiesSet() throws Exception {
super.afterPropertiesSet();
postProcess(getRegion());
}
protected Region<K, V> createRegion(GemFireCache gemfireCache, String regionName) throws Exception {
/**
* @inheritDoc
*/
@Override
protected Region<K, V> lookupRegion(GemFireCache cache, String regionName) throws Exception {
Assert.isTrue(GemfireUtils.isClient(cache), "A ClientCache is required to create a client Region");
applyRegionConfigurers(regionName);
ClientCache cache = resolveCache(gemfireCache);
ClientRegionFactory<K, V> clientRegionFactory =
((ClientCache) cache).createClientRegionFactory(resolveClientRegionShortcut());
configure(createClientRegionFactory(cache, resolveClientRegionShortcut()));
setAttributes(clientRegionFactory);
addCacheListeners(clientRegionFactory);
setDiskStoreName(clientRegionFactory);
setEvictionAttributes(clientRegionFactory);
setPoolName(clientRegionFactory);
if (keyConstraint != null) {
clientRegionFactory.setKeyConstraint(keyConstraint);
}
if (valueConstraint != null) {
clientRegionFactory.setValueConstraint(valueConstraint);
}
return logCreateRegionEvent(create(clientRegionFactory, regionName));
}
/* (non-Javadoc) */
private Region<K, V> create(ClientRegionFactory<K, V> clientRegionFactory, String regionName) {
return (getParent() != null ? clientRegionFactory.createSubregion(getParent(), regionName)
: clientRegionFactory.create(regionName));
}
/* (non-Javadoc) */
private Region<K, V> logCreateRegionEvent(Region<K, V> region) {
if (log.isInfoEnabled()) {
if (getParent() != null) {
log.info(String.format("Created new client cache Sub-Region [%1$s] under parent Region [%2$s].",
region.getName(), getParent().getName()));
}
else {
log.info(String.format("Created new client cache Region [%s].", region.getName()));
}
}
@SuppressWarnings("all")
Region<K, V> region = newRegion(clientRegionFactory, getParent(), regionName);
return region;
}
/* (non-Javadoc) */
private void applyRegionConfigurers(String regionName) {
applyRegionConfigurers(regionName, getCompositeRegionConfigurer());
}
/**
* Resolves the {@link ClientRegionShortcut} used to configure the data policy of the client {@link Region}.
* Null-safe operation to apply the given array of {@link RegionConfigurer RegionConfigurers}
* to this {@link ClientRegionFactoryBean}.
*
* @return a {@link ClientRegionShortcut} used to configure the data policy of the client {@link Region}.
* @param regionName {@link String} containing the name of the {@link Region}.
* @param regionConfigurers array of {@link RegionConfigurer RegionConfigurers} applied
* to this {@link ClientRegionFactoryBean}.
* @see org.springframework.data.gemfire.config.annotation.RegionConfigurer
* @see #applyRegionConfigurers(String, Iterable)
*/
protected void applyRegionConfigurers(String regionName, RegionConfigurer... regionConfigurers) {
applyRegionConfigurers(regionName, Arrays.asList(nullSafeArray(regionConfigurers, RegionConfigurer.class)));
}
/**
* Null-safe operation to apply the given {@link Iterable} of {@link RegionConfigurer RegionConfigurers}
* to this {@link ClientRegionFactoryBean}.
*
* @param regionName {@link String} containing the name of the {@link Region}.
* @param regionConfigurers {@link Iterable} of {@link RegionConfigurer RegionConfigurers} applied
* to this {@link ClientRegionFactoryBean}.
* @see org.springframework.data.gemfire.config.annotation.RegionConfigurer
*/
protected void applyRegionConfigurers(String regionName, Iterable<RegionConfigurer> regionConfigurers) {
StreamSupport.stream(nullSafeIterable(regionConfigurers).spliterator(), false)
.forEach(regionConfigurer -> regionConfigurer.configure(regionName, this));
}
/**
* Assert the settings for {@link ClientRegionShortcut} and the {@literal persistent} attribute
* in &lt;gfe:*-region&gt; elements are compatible.
*
* @param resolvedShortcut {@link ClientRegionShortcut} resolved from the SDG XML namespace.
* @see org.springframework.data.gemfire.client.ClientRegionShortcutWrapper
* @see org.apache.geode.cache.client.ClientRegionShortcut
* @see #isNotPersistent()
* @see #isPersistent()
*/
private void assertClientRegionShortcutAndPersistentAttributeAreCompatible(ClientRegionShortcut resolvedShortcut) {
final boolean persistentNotSpecified = (this.persistent == null);
if (ClientRegionShortcutWrapper.valueOf(resolvedShortcut).isPersistent()) {
Assert.isTrue(persistentNotSpecified || isPersistent(),
String.format("Client Region Shortcut [%s] is not valid when persistent is false", resolvedShortcut));
}
else {
Assert.isTrue(persistentNotSpecified || isNotPersistent(),
String.format("Client Region Shortcut [%s] is not valid when persistent is true", resolvedShortcut));
}
}
/**
* Assert the settings for {@link DataPolicy} and the persistent attribute
* in &lt;gfe:*-region&gt; elements are compatible.
*
* @param resolvedDataPolicy {@link DataPolicy} resolved from the SDG XML namespace.
* @see org.apache.geode.cache.DataPolicy
* @see #isNotPersistent()
* @see #isPersistent()
*/
private void assertDataPolicyAndPersistentAttributeAreCompatible(DataPolicy resolvedDataPolicy) {
if (resolvedDataPolicy.withPersistence()) {
Assert.isTrue(isPersistentUnspecified() || isPersistent(),
String.format("Data Policy [%s] is not valid when persistent is false", resolvedDataPolicy));
}
else {
Assert.isTrue(isPersistentUnspecified() || isNotPersistent(),
String.format("Data Policy [%s] is not valid when persistent is true", resolvedDataPolicy));
}
}
/* (non-Javadoc) */
private Region<K, V> newRegion(ClientRegionFactory<K, V> clientRegionFactory,
Region<?, ?> parentRegion, String regionName) {
return Optional.ofNullable(parentRegion)
.map(parent -> {
logInfo("Creating client Subregion [%1$s] with parent Region [%2$s]",
regionName, parent.getName());
return clientRegionFactory.<K, V>createSubregion(parent, regionName);
})
.orElseGet(() -> {
logInfo("Created client Region [%s]", regionName);
return clientRegionFactory.create(regionName);
});
}
/* (non-Javadoc) */
private ClientCache resolveCache(GemFireCache gemfireCache) {
return Optional.ofNullable(gemfireCache)
.filter(GemfireUtils::isClient)
.map(cache -> (ClientCache) cache)
.orElseThrow(() -> newIllegalArgumentException("ClientCache is required"));
}
/**
* Resolves the {@link ClientRegionShortcut} used to configure the {@link DataPolicy} of the client {@link Region}.
*
* @return a {@link ClientRegionShortcut} used to configure the {@link DataPolicy} of the client {@link Region}.
* @see org.apache.geode.cache.client.ClientRegionShortcut
* @see org.apache.geode.cache.DataPolicy
*/
ClientRegionShortcut resolveClientRegionShortcut() {
ClientRegionShortcut resolvedShortcut = this.shortcut;
if (resolvedShortcut == null) {
if (this.dataPolicy != null) {
assertDataPolicyAndPersistentAttributeAreCompatible(this.dataPolicy);
if (DataPolicy.EMPTY.equals(this.dataPolicy)) {
DataPolicy dataPolicy = this.dataPolicy;
if (dataPolicy != null) {
assertDataPolicyAndPersistentAttributeAreCompatible(dataPolicy);
if (DataPolicy.EMPTY.equals(dataPolicy)) {
resolvedShortcut = ClientRegionShortcut.PROXY;
}
else if (DataPolicy.NORMAL.equals(this.dataPolicy)) {
else if (DataPolicy.NORMAL.equals(dataPolicy)) {
resolvedShortcut = ClientRegionShortcut.CACHING_PROXY;
}
else if (DataPolicy.PERSISTENT_REPLICATE.equals(this.dataPolicy)) {
else if (DataPolicy.PERSISTENT_REPLICATE.equals(dataPolicy)) {
resolvedShortcut = ClientRegionShortcut.LOCAL_PERSISTENT;
}
else {
// NOTE the DataPolicy validation is based on the ClientRegionShortcut initialization logic
// in org.apache.geode.internal.cache.GemFireCacheImpl.initializeClientRegionShortcuts
throw new IllegalArgumentException(String.format("Data Policy '%s' is invalid for Client Regions",
this.dataPolicy));
throw newIllegalArgumentException("Data Policy [%s] is not valid for the client Region", dataPolicy);
}
}
else {
@@ -194,145 +282,20 @@ public class ClientRegionFactoryBean<K, V> extends RegionLookupFactoryBean<K, V>
}
}
// NOTE the ClientRegionShortcut and Persistent attribute will be compatible if the shortcut
// was derived from the Data Policy.
// NOTE the ClientRegionShortcut and Persistent attribute will be compatible
// if the shortcut was derived from the Data Policy.
assertClientRegionShortcutAndPersistentAttributeAreCompatible(resolvedShortcut);
return resolvedShortcut;
}
/**
* Validates that the settings for ClientRegionShortcut and the 'persistent' attribute in &lt;gfe:*-region&gt; elements
* are compatible.
*
* @param resolvedShortcut the GemFire ClientRegionShortcut resolved form the Spring GemFire XML namespace
* configuration meta-data.
* @see #isPersistent()
* @see #isNotPersistent()
* @see org.apache.geode.cache.client.ClientRegionShortcut
*/
private void assertClientRegionShortcutAndPersistentAttributeAreCompatible(ClientRegionShortcut resolvedShortcut) {
final boolean persistentNotSpecified = (this.persistent == null);
if (ClientRegionShortcut.LOCAL_PERSISTENT.equals(resolvedShortcut)
|| ClientRegionShortcut.LOCAL_PERSISTENT_OVERFLOW.equals(resolvedShortcut)) {
Assert.isTrue(persistentNotSpecified || isPersistent(), String.format(
"Client Region Shortcut '%s' is invalid when persistent is false", resolvedShortcut));
}
else {
Assert.isTrue(persistentNotSpecified || isNotPersistent(), String.format(
"Client Region Shortcut '%s' is invalid when persistent is true", resolvedShortcut));
}
}
/**
* Validates that the settings for Data Policy and the 'persistent' attribute in &lt;gfe:*-region&gt; elements
* are compatible.
*
* @param resolvedDataPolicy the GemFire Data Policy resolved form the Spring GemFire XML namespace configuration
* meta-data.
* @see #isPersistent()
* @see #isNotPersistent()
* @see org.apache.geode.cache.DataPolicy
*/
private void assertDataPolicyAndPersistentAttributeAreCompatible(DataPolicy resolvedDataPolicy) {
if (resolvedDataPolicy.withPersistence()) {
Assert.isTrue(isPersistentUnspecified() || isPersistent(), String.format(
"Data Policy '%s' is invalid when persistent is false", resolvedDataPolicy));
}
else {
// NOTE otherwise, the Data Policy is without persistence, so...
Assert.isTrue(isPersistentUnspecified() || isNotPersistent(), String.format(
"Data Policy '%s' is invalid when persistent is true", resolvedDataPolicy));
}
}
/* (non-Javadoc) */
private ClientRegionFactory<K, V> setAttributes(ClientRegionFactory<K, V> clientRegionFactory) {
RegionAttributes<K, V> localAttributes = this.attributes;
if (localAttributes != null) {
clientRegionFactory.setCloningEnabled(localAttributes.getCloningEnabled());
clientRegionFactory.setCompressor(localAttributes.getCompressor());
clientRegionFactory.setConcurrencyChecksEnabled(localAttributes.getConcurrencyChecksEnabled());
clientRegionFactory.setConcurrencyLevel(localAttributes.getConcurrencyLevel());
clientRegionFactory.setCustomEntryIdleTimeout(localAttributes.getCustomEntryIdleTimeout());
clientRegionFactory.setCustomEntryTimeToLive(localAttributes.getCustomEntryTimeToLive());
clientRegionFactory.setDiskStoreName(localAttributes.getDiskStoreName());
clientRegionFactory.setDiskSynchronous(localAttributes.isDiskSynchronous());
clientRegionFactory.setEntryIdleTimeout(localAttributes.getEntryIdleTimeout());
clientRegionFactory.setEntryTimeToLive(localAttributes.getEntryTimeToLive());
clientRegionFactory.setEvictionAttributes(localAttributes.getEvictionAttributes());
clientRegionFactory.setInitialCapacity(localAttributes.getInitialCapacity());
clientRegionFactory.setKeyConstraint(localAttributes.getKeyConstraint());
clientRegionFactory.setLoadFactor(localAttributes.getLoadFactor());
clientRegionFactory.setPoolName(localAttributes.getPoolName());
clientRegionFactory.setRegionIdleTimeout(localAttributes.getRegionIdleTimeout());
clientRegionFactory.setRegionTimeToLive(localAttributes.getRegionTimeToLive());
clientRegionFactory.setStatisticsEnabled(localAttributes.getStatisticsEnabled());
clientRegionFactory.setValueConstraint(localAttributes.getValueConstraint());
}
return clientRegionFactory;
}
/* (non-Javadoc) */
@SuppressWarnings("unchecked")
private ClientRegionFactory<K, V> addCacheListeners(ClientRegionFactory<K, V> clientRegionFactory) {
for (CacheListener<K, V> cacheListener : this.<K, V>attributesCacheListeners()) {
clientRegionFactory.addCacheListener(cacheListener);
}
for (CacheListener<K, V> cacheListener : nullSafeArray(this.cacheListeners, CacheListener.class)) {
clientRegionFactory.addCacheListener(cacheListener);
}
return clientRegionFactory;
}
/* (non-Javadoc) */
@SuppressWarnings("unchecked")
private <K, V> CacheListener<K, V>[] attributesCacheListeners() {
CacheListener[] cacheListeners = (this.attributes != null ? this.attributes.getCacheListeners() : null);
return nullSafeArray(cacheListeners, CacheListener.class);
}
/* (non-Javadoc) */
private ClientRegionFactory<K, V> setDiskStoreName(ClientRegionFactory<K, V> clientRegionFactory) {
if (StringUtils.hasText(this.diskStoreName)) {
clientRegionFactory.setDiskStoreName(this.diskStoreName);
}
return clientRegionFactory;
}
/* (non-Javadoc) */
private ClientRegionFactory<K, V> setEvictionAttributes(ClientRegionFactory<K, V> clientRegionFactory) {
if (this.evictionAttributes != null) {
clientRegionFactory.setEvictionAttributes(this.evictionAttributes);
}
return clientRegionFactory;
}
/* (non-Javadoc) */
private ClientRegionFactory<K, V> setPoolName(ClientRegionFactory<K, V> clientRegionFactory) {
String poolName = resolvePoolName();
if (StringUtils.hasText(poolName)) {
clientRegionFactory.setPoolName(eagerlyInitializePool(poolName));
}
return clientRegionFactory;
}
/* (non-Javadoc) */
private String resolvePoolName() {
String poolName = this.poolName;
if (!StringUtils.hasText(poolName)) {
String defaultPoolName = GemfireConstants.DEFAULT_GEMFIRE_POOL_NAME;
poolName = (this.beanFactory.containsBean(defaultPoolName) ? defaultPoolName : poolName);
poolName = (getBeanFactory().containsBean(defaultPoolName) ? defaultPoolName : poolName);
}
return poolName;
@@ -340,35 +303,117 @@ public class ClientRegionFactoryBean<K, V> extends RegionLookupFactoryBean<K, V>
/* (non-Javadoc) */
private String eagerlyInitializePool(String poolName) {
try {
if (this.beanFactory.isTypeMatch(poolName, Pool.class)) {
if (log.isDebugEnabled()) {
log.debug(String.format("Found bean definition for Pool [%1$s]; Eagerly initializing...", poolName));
}
this.beanFactory.getBean(poolName, Pool.class);
try {
if (getBeanFactory().isTypeMatch(poolName, Pool.class)) {
logDebug("Found bean definition for Pool [%s]; Eagerly initializing...", poolName);
getBeanFactory().getBean(poolName, Pool.class);
}
}
catch (BeansException ignore) {
log.warn(ignore.getMessage());
getLog().warn(ignore.getMessage(), ignore.getCause());
}
return poolName;
}
/* (non-Javadoc) */
protected void postProcess(Region<K, V> region) throws Exception {
loadSnapshot(region);
registerInterests(region);
setCacheLoader(region);
setCacheWriter(region);
/**
* Constructs a new instance of {@link ClientRegionFactory} using the given {@link ClientCache}
* and {@link ClientRegionShortcut}.
*
* @param cache reference to the {@link ClientCache}.
* @param shortcut {@link ClientRegionShortcut} used to specify the client {@link Region} {@link DataPolicy}.
* @return a new instance of {@link ClientRegionFactory}.
* @see org.apache.geode.cache.client.ClientCache#createClientRegionFactory(ClientRegionShortcut)
* @see org.apache.geode.cache.client.ClientRegionShortcut
* @see org.apache.geode.cache.client.ClientRegionFactory
*/
protected ClientRegionFactory<K, V> createClientRegionFactory(ClientCache cache, ClientRegionShortcut shortcut) {
return cache.createClientRegionFactory(shortcut);
}
/* (non-Javadoc) */
private Region<K, V> loadSnapshot(Region<K, V> region) throws Exception {
if (snapshot != null) {
region.loadSnapshot(snapshot.getInputStream());
}
/**
* Configures the given {@link ClientRegionFactoryBean} from the configuration settings
* of this {@link ClientRegionFactoryBean}.
*
* @param clientRegionFactory {@link ClientRegionFactory} to configure.
* @return the given {@link ClientRegionFactory}.
* @see org.apache.geode.cache.client.ClientRegionFactory
*/
protected ClientRegionFactory<K, V> configure(ClientRegionFactory<K, V> clientRegionFactory) {
Optional.ofNullable(this.attributes).ifPresent(attributes -> {
stream(nullSafeArray(attributes.getCacheListeners(), CacheListener.class))
.forEach(clientRegionFactory::addCacheListener);
clientRegionFactory.setCloningEnabled(attributes.getCloningEnabled());
clientRegionFactory.setCompressor(attributes.getCompressor());
clientRegionFactory.setConcurrencyChecksEnabled(attributes.getConcurrencyChecksEnabled());
clientRegionFactory.setConcurrencyLevel(attributes.getConcurrencyLevel());
clientRegionFactory.setCustomEntryIdleTimeout(attributes.getCustomEntryIdleTimeout());
clientRegionFactory.setCustomEntryTimeToLive(attributes.getCustomEntryTimeToLive());
clientRegionFactory.setDiskStoreName(attributes.getDiskStoreName());
clientRegionFactory.setDiskSynchronous(attributes.isDiskSynchronous());
clientRegionFactory.setEntryIdleTimeout(attributes.getEntryIdleTimeout());
clientRegionFactory.setEntryTimeToLive(attributes.getEntryTimeToLive());
clientRegionFactory.setEvictionAttributes(attributes.getEvictionAttributes());
clientRegionFactory.setInitialCapacity(attributes.getInitialCapacity());
clientRegionFactory.setKeyConstraint(attributes.getKeyConstraint());
clientRegionFactory.setLoadFactor(attributes.getLoadFactor());
clientRegionFactory.setPoolName(attributes.getPoolName());
clientRegionFactory.setRegionIdleTimeout(attributes.getRegionIdleTimeout());
clientRegionFactory.setRegionTimeToLive(attributes.getRegionTimeToLive());
clientRegionFactory.setStatisticsEnabled(attributes.getStatisticsEnabled());
clientRegionFactory.setValueConstraint(attributes.getValueConstraint());
});
stream(nullSafeArray(this.cacheListeners, CacheListener.class)).forEach(clientRegionFactory::addCacheListener);
Optional.ofNullable(this.diskStoreName).filter(StringUtils::hasText)
.ifPresent(clientRegionFactory::setDiskStoreName);
Optional.ofNullable(this.evictionAttributes).ifPresent(clientRegionFactory::setEvictionAttributes);
Optional.ofNullable(this.keyConstraint).ifPresent(clientRegionFactory::setKeyConstraint);
Optional.ofNullable(resolvePoolName()).filter(StringUtils::hasText)
.ifPresent(poolName -> clientRegionFactory.setPoolName(eagerlyInitializePool(poolName)));
Optional.ofNullable(this.valueConstraint).ifPresent(clientRegionFactory::setValueConstraint);
return clientRegionFactory;
}
/**
* Post-process the given {@link ClientRegionFactory} setup by this {@link ClientRegionFactoryBean}.
*
* @param clientRegionFactory {@link ClientRegionFactory} to process.
* @return the given {@link ClientRegionFactory}.
* @see org.apache.geode.cache.client.ClientRegionFactory
*/
protected ClientRegionFactory<K, V> postProcess(ClientRegionFactory<K, V> clientRegionFactory) {
return clientRegionFactory;
}
/**
* Post-process the {@link Region} created by this {@link ClientRegionFactoryBean}.
*
* @param region {@link Region} to process.
* @see org.apache.geode.cache.Region
*/
@Override
protected Region<K, V> postProcess(Region<K, V> region) {
super.postProcess(region);
registerInterests(region);
Optional.ofNullable(this.cacheLoader)
.ifPresent(cacheLoader -> region.getAttributesMutator().setCacheLoader(cacheLoader));
Optional.ofNullable(this.cacheWriter)
.ifPresent(cacheWriter -> region.getAttributesMutator().setCacheWriter(cacheWriter));
return region;
}
@@ -376,47 +421,32 @@ public class ClientRegionFactoryBean<K, V> extends RegionLookupFactoryBean<K, V>
/* (non-Javadoc) */
@SuppressWarnings("unchecked")
private Region<K, V> registerInterests(Region<K, V> region) {
for (Interest<K> interest : nullSafeArray(interests, Interest.class)) {
stream(nullSafeArray(this.interests, Interest.class)).forEach(interest -> {
if (interest.isRegexType()) {
region.registerInterestRegex((String) interest.getKey(), interest.getPolicy(),
interest.isDurable(), interest.isReceiveValues());
}
else {
region.registerInterest(interest.getKey(), interest.getPolicy(), interest.isDurable(),
interest.isReceiveValues());
region.registerInterest(((Interest<K>) interest).getKey(), interest.getPolicy(),
interest.isDurable(), interest.isReceiveValues());
}
}
return region;
}
/* (non-Javadoc) */
private Region<K, V> setCacheLoader(Region<K, V> region) {
if (cacheLoader != null) {
region.getAttributesMutator().setCacheLoader(this.cacheLoader);
}
return region;
}
/* (non-Javadoc) */
private Region<K, V> setCacheWriter(Region<K, V> region) {
if (cacheWriter != null) {
region.getAttributesMutator().setCacheWriter(this.cacheWriter);
}
});
return region;
}
/**
* @inheritDoc
* Closes and destroys the {@link Region}.
*
* @throws Exception if destroy fails.
* @see org.springframework.beans.factory.DisposableBean
*/
@Override
public void destroy() throws Exception {
Region<K, V> region = getObject();
if (region != null) {
if (close) {
Optional.ofNullable(getObject()).ifPresent(region -> {
if (isClose()) {
if (!region.getRegionService().isClosed()) {
try {
region.close();
@@ -426,10 +456,21 @@ public class ClientRegionFactoryBean<K, V> extends RegionLookupFactoryBean<K, V>
}
}
if (destroy) {
if (isDestroy()) {
region.destroyRegion();
}
}
});
}
/**
* Returns a reference to the Composite {@link RegionConfigurer} used to apply additional configuration
* to this {@link ClientRegionFactoryBean} on Spring container initialization.
*
* @return the Composite {@link RegionConfigurer}.
* @see org.springframework.data.gemfire.config.annotation.RegionConfigurer
*/
protected RegionConfigurer getCompositeRegionConfigurer() {
return this.compositeRegionConfigurer;
}
/**
@@ -446,29 +487,6 @@ public class ClientRegionFactoryBean<K, V> extends RegionLookupFactoryBean<K, V>
this.attributes = attributes;
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
}
/* (non-Javadoc) */
final boolean isClose() {
return close;
}
/**
* Indicates whether the region referred by this factory bean, will be
* closed on shutdown (default true). Note: destroy and close are mutually
* exclusive. Enabling one will automatically disable the other.
*
* @param close whether to close or not the region
* @see #setDestroy(boolean)
*/
public void setClose(boolean close) {
this.close = close;
this.destroy = (this.destroy && !close); // retain previous value iff close is false.
}
/**
* Sets the cache listeners used for the region used by this factory. Used
* only when a new region is created.Overrides the settings specified
@@ -500,6 +518,24 @@ public class ClientRegionFactoryBean<K, V> extends RegionLookupFactoryBean<K, V>
this.cacheWriter = cacheWriter;
}
/* (non-Javadoc) */
final boolean isClose() {
return this.close;
}
/**
* Indicates whether the region referred by this factory bean will be closed on shutdown (default true).
*
* Note: destroy and close are mutually exclusive. Enabling one will automatically disable the other.
*
* @param close whether to close or not the region
* @see #setDestroy(boolean)
*/
public void setClose(boolean close) {
this.close = close;
this.destroy = (this.destroy && !close); // retain previous value iff close is false.
}
/**
* Sets the Data Policy. Used only when a new Region is created.
*
@@ -521,13 +557,13 @@ public class ClientRegionFactoryBean<K, V> extends RegionLookupFactoryBean<K, V>
@Deprecated
public void setDataPolicyName(String dataPolicyName) {
DataPolicy resolvedDataPolicy = new DataPolicyConverter().convert(dataPolicyName);
Assert.notNull(resolvedDataPolicy, String.format("Data Policy '%1$s' is invalid.", dataPolicyName));
Assert.notNull(resolvedDataPolicy, String.format("Data Policy [%1$s] is not valid", dataPolicyName));
setDataPolicy(resolvedDataPolicy);
}
/* (non-Javadoc) */
final boolean isDestroy() {
return destroy;
return this.destroy;
}
/**
@@ -598,8 +634,8 @@ public class ClientRegionFactoryBean<K, V> extends RegionLookupFactoryBean<K, V>
* @see org.apache.geode.cache.client.Pool
*/
public void setPool(Pool pool) {
Assert.notNull(pool, "Pool cannot be null");
setPoolName(pool.getName());
setPoolName(Optional.ofNullable(pool).map(Pool::getName)
.orElseThrow(() -> newIllegalArgumentException("Pool cannot be null")));
}
/**
@@ -608,8 +644,33 @@ public class ClientRegionFactoryBean<K, V> extends RegionLookupFactoryBean<K, V>
* @param poolName String specifying the name of the GemFire client {@link Pool}.
*/
public void setPoolName(String poolName) {
Assert.hasText(poolName, "Pool name is required");
this.poolName = poolName;
this.poolName = Optional.ofNullable(poolName).filter(StringUtils::hasText)
.orElseThrow(() -> newIllegalArgumentException("Pool name is required"));
}
/**
* Null-safe operation to set an array of {@link RegionConfigurer RegionConfigurers} used to apply
* additional configuration to this {@link ClientRegionFactoryBean} when using Annotation-based configuration.
*
* @param regionConfigurers array of {@link RegionConfigurer RegionConfigurers} used to apply
* additional configuration to this {@link ClientRegionFactoryBean}.
* @see org.springframework.data.gemfire.config.annotation.RegionConfigurer
* @see #setRegionConfigurers(List)
*/
public void setRegionConfigurers(RegionConfigurer... regionConfigurers) {
setRegionConfigurers(Arrays.asList(nullSafeArray(regionConfigurers, RegionConfigurer.class)));
}
/**
* Null-safe operation to set an {@link Iterable} of {@link RegionConfigurer RegionConfigurers} used to apply
* additional configuration to this {@link ClientRegionFactoryBean} when using Annotation-based configuration.
*
* @param regionConfigurers {@link Iterable} of {@link RegionConfigurer RegionConfigurers} used to apply
* additional configuration to this {@link ClientRegionFactoryBean}.
* @see org.springframework.data.gemfire.config.annotation.RegionConfigurer
*/
public void setRegionConfigurers(List<RegionConfigurer> regionConfigurers) {
this.regionConfigurers = Optional.ofNullable(regionConfigurers).orElseGet(Collections::emptyList);
}
/**
@@ -621,18 +682,6 @@ public class ClientRegionFactoryBean<K, V> extends RegionLookupFactoryBean<K, V>
this.shortcut = shortcut;
}
/**
* Specifies the data snapshots used for loading a newly <i>created</i> {@link Region}.
* The snapshot will be used <i>only</i> when a new {@link Region} is created.
* If the {@link Region} already exists, no loading will be performed.
*
* @param snapshot {@link Resource} referencing the snapshot used to load the {@link Region} with data.
* @see org.springframework.core.io.Resource
*/
public void setSnapshot(Resource snapshot) {
this.snapshot = snapshot;
}
public void setValueConstraint(Class<V> valueConstraint) {
this.valueConstraint = valueConstraint;
}

View File

@@ -30,6 +30,7 @@ import org.springframework.util.ObjectUtils;
*/
@SuppressWarnings("unused")
public enum ClientRegionShortcutWrapper {
CACHING_PROXY(ClientRegionShortcut.CACHING_PROXY, DataPolicy.NORMAL),
CACHING_PROXY_HEAP_LRU(ClientRegionShortcut.CACHING_PROXY_HEAP_LRU, DataPolicy.NORMAL),
CACHING_PROXY_OVERFLOW(ClientRegionShortcut.CACHING_PROXY_OVERFLOW, DataPolicy.NORMAL),
@@ -45,11 +46,6 @@ public enum ClientRegionShortcutWrapper {
private final DataPolicy dataPolicy;
ClientRegionShortcutWrapper(ClientRegionShortcut clientRegionShortcut, DataPolicy dataPolicy) {
this.clientRegionShortcut = clientRegionShortcut;
this.dataPolicy = dataPolicy;
}
public static ClientRegionShortcutWrapper valueOf(ClientRegionShortcut clientRegionShortcut) {
for (ClientRegionShortcutWrapper wrapper : values()) {
if (ObjectUtils.nullSafeEquals(wrapper.getClientRegionShortcut(), clientRegionShortcut)) {
@@ -60,6 +56,11 @@ public enum ClientRegionShortcutWrapper {
return ClientRegionShortcutWrapper.UNSPECIFIED;
}
ClientRegionShortcutWrapper(ClientRegionShortcut clientRegionShortcut, DataPolicy dataPolicy) {
this.clientRegionShortcut = clientRegionShortcut;
this.dataPolicy = dataPolicy;
}
public ClientRegionShortcut getClientRegionShortcut() {
return this.clientRegionShortcut;
}

View File

@@ -16,73 +16,68 @@
package org.springframework.data.gemfire.client;
import java.net.InetSocketAddress;
import java.util.List;
import static java.util.stream.StreamSupport.stream;
import static org.springframework.data.gemfire.util.ArrayUtils.nullSafeArray;
import static org.springframework.data.gemfire.util.CollectionUtils.nullSafeCollection;
import static org.springframework.data.gemfire.util.CollectionUtils.nullSafeIterable;
import static org.springframework.data.gemfire.util.RuntimeExceptionFactory.newIllegalArgumentException;
import java.net.InetSocketAddress;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.geode.cache.client.ClientCache;
import org.apache.geode.cache.client.Pool;
import org.apache.geode.cache.client.PoolFactory;
import org.apache.geode.cache.client.PoolManager;
import org.apache.geode.cache.query.QueryService;
import org.apache.geode.distributed.DistributedSystem;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.data.gemfire.GemfireUtils;
import org.springframework.data.gemfire.config.annotation.PoolConfigurer;
import org.springframework.data.gemfire.support.AbstractFactoryBeanSupport;
import org.springframework.data.gemfire.support.ConnectionEndpoint;
import org.springframework.data.gemfire.support.ConnectionEndpointList;
import org.springframework.data.gemfire.util.DistributedSystemUtils;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
* FactoryBean for easy declaration and configuration of a GemFire {@link Pool}. If a new {@link Pool} is created,
* its lifecycle is bound to that of this declaring factory.
* Spring {@link FactoryBean} to construct, configure and initialize a {@link Pool}.
*
* Note, if a {@link Pool} having the configured name already exists, then the existing {@link Pool} will be returned
* as is without any modifications and its lifecycle will be unaffected by this factory.
* If a new {@link Pool} is created, its lifecycle is bound to that of this declaring {@link FactoryBean}
* and indirectly, the Spring container.
*
* If a {@link Pool} having the configured {@link String name} already exists, then the existing {@link Pool}
* will be returned as is without any modifications and its lifecycle will be unaffected by this {@link FactoryBean}.
*
* @author Costin Leau
* @author John Blum
* @see java.net.InetSocketAddress
* @see org.springframework.beans.factory.BeanNameAware
* @see org.springframework.beans.factory.DisposableBean
* @see org.springframework.beans.factory.FactoryBean
* @see org.springframework.beans.factory.InitializingBean
* @see org.springframework.data.gemfire.support.ConnectionEndpoint
* @see org.springframework.data.gemfire.support.ConnectionEndpointList
* @see org.apache.geode.cache.client.ClientCache
* @see org.apache.geode.cache.client.Pool
* @see org.apache.geode.cache.client.PoolFactory
* @see org.apache.geode.cache.client.PoolManager
* @see org.apache.geode.distributed.DistributedSystem
* @see org.springframework.beans.factory.DisposableBean
* @see org.springframework.beans.factory.InitializingBean
* @see org.springframework.data.gemfire.config.annotation.PoolConfigurer
* @see org.springframework.data.gemfire.support.AbstractFactoryBeanSupport
* @see org.springframework.data.gemfire.support.ConnectionEndpoint
* @see org.springframework.data.gemfire.support.ConnectionEndpointList
*/
@SuppressWarnings("unused")
public class PoolFactoryBean implements FactoryBean<Pool>, InitializingBean, DisposableBean,
BeanNameAware, BeanFactoryAware {
public class PoolFactoryBean extends AbstractFactoryBeanSupport<Pool> implements DisposableBean, InitializingBean {
protected static final int DEFAULT_LOCATOR_PORT = DistributedSystemUtils.DEFAULT_LOCATOR_PORT;
protected static final int DEFAULT_SERVER_PORT = DistributedSystemUtils.DEFAULT_CACHE_SERVER_PORT;
private static final Log log = LogFactory.getLog(PoolFactoryBean.class);
// indicates whether the Pool has been created internally (by this FactoryBean) or not
volatile boolean springBasedPool = true;
private BeanFactory beanFactory;
private ConnectionEndpointList locators = new ConnectionEndpointList();
private ConnectionEndpointList servers = new ConnectionEndpointList();
private volatile Pool pool;
private String beanName;
private String name;
// GemFire Pool Configuration Settings
private boolean keepAlive = false;
private boolean multiUserAuthentication = PoolFactory.DEFAULT_MULTIUSER_AUTHENTICATION;
@@ -105,109 +100,150 @@ public class PoolFactoryBean implements FactoryBean<Pool>, InitializingBean, Dis
private long idleTimeout = PoolFactory.DEFAULT_IDLE_TIMEOUT;
private long pingInterval = PoolFactory.DEFAULT_PING_INTERVAL;
private ConnectionEndpointList locators = new ConnectionEndpointList();
private ConnectionEndpointList servers = new ConnectionEndpointList();
private List<PoolConfigurer> poolConfigurers = Collections.emptyList();
private volatile Pool pool;
private PoolConfigurer compositePoolConfigurer = (beanName, bean) ->
nullSafeCollection(poolConfigurers).forEach(poolConfigurer -> poolConfigurer.configure(beanName, bean));
private String name;
private String serverGroup = PoolFactory.DEFAULT_SERVER_GROUP;
/**
* Constructs and initializes a GemFire {@link Pool}.
* Prepares the construction, configuration and initialization of a new {@link Pool}.
*
* @throws Exception if the {@link Pool} creation and initialization fails.
* @see org.apache.geode.cache.client.Pool
* @see org.apache.geode.cache.client.PoolFactory
* @throws Exception if {@link Pool} initialization fails.
* @see org.apache.geode.cache.client.PoolManager
* @see #createPoolFactory()
* @see org.apache.geode.cache.client.PoolFactory
* @see org.apache.geode.cache.client.Pool
*/
@Override
public void afterPropertiesSet() throws Exception {
if (!StringUtils.hasText(name)) {
Assert.hasText(beanName, "Pool 'name' is required");
this.name = beanName;
}
// check for an existing, configured Pool with name first
Pool existingPool = PoolManager.find(name);
if (existingPool != null) {
if (log.isDebugEnabled()) {
log.debug(String.format("A Pool with name [%1$s] already exists; using existing Pool.", name));
}
this.springBasedPool = false;
this.pool = existingPool;
}
else {
if (log.isDebugEnabled()) {
log.debug(String.format("No Pool with name [%1$s] was found. Creating new Pool.", name));
}
this.springBasedPool = true;
}
init(Optional.ofNullable(PoolManager.find(validatePoolName())));
}
/**
* Destroys the GemFire {@link Pool} if created by this {@link PoolFactoryBean} and releases all system resources
* used by the {@link Pool}.
*
* @throws Exception if the {@link Pool} destruction caused an error.
* @see DisposableBean#destroy()
*/
@Override
public void destroy() throws Exception {
if (springBasedPool && pool != null && !pool.isDestroyed()) {
pool.releaseThreadLocalConnection();
pool.destroy(keepAlive);
pool = null;
/* (non-Javadoc) */
@SuppressWarnings("all")
private void init(Optional<Pool> existingPool) {
if (log.isDebugEnabled()) {
log.debug(String.format("Destroyed Pool [%1$s]", name));
}
if (existingPool.isPresent()) {
this.pool = existingPool.get();
this.springBasedPool = false;
logDebug(() -> String.format(
"Pool with name [%s] already exists; Using existing Pool; Pool Configurers [%d] will not be applied",
existingPool.get().getName(), this.poolConfigurers.size()));
}
else {
this.springBasedPool = true;
applyPoolConfigurers();
logDebug("No Pool with name [%s] was found; Creating new Pool", getName());
}
}
/* (non-Javadoc) */
@Override
public Pool getObject() throws Exception {
if (this.pool == null) {
eagerlyInitializeClientCacheIfNotPresent();
PoolFactory poolFactory = createPoolFactory();
poolFactory.setFreeConnectionTimeout(freeConnectionTimeout);
poolFactory.setIdleTimeout(idleTimeout);
poolFactory.setLoadConditioningInterval(loadConditioningInterval);
poolFactory.setMaxConnections(maxConnections);
poolFactory.setMinConnections(minConnections);
poolFactory.setMultiuserAuthentication(multiUserAuthentication);
poolFactory.setPingInterval(pingInterval);
poolFactory.setPRSingleHopEnabled(prSingleHopEnabled);
poolFactory.setReadTimeout(readTimeout);
poolFactory.setRetryAttempts(retryAttempts);
poolFactory.setServerGroup(serverGroup);
poolFactory.setSocketBufferSize(socketBufferSize);
poolFactory.setStatisticInterval(statisticInterval);
poolFactory.setSubscriptionAckInterval(subscriptionAckInterval);
poolFactory.setSubscriptionEnabled(subscriptionEnabled);
poolFactory.setSubscriptionMessageTrackingTimeout(subscriptionMessageTrackingTimeout);
poolFactory.setSubscriptionRedundancy(subscriptionRedundancy);
poolFactory.setThreadLocalConnections(threadLocalConnections);
for (ConnectionEndpoint locator : this.locators) {
poolFactory.addLocator(locator.getHost(), locator.getPort());
}
for (ConnectionEndpoint server : this.servers) {
poolFactory.addServer(server.getHost(), server.getPort());
}
pool = poolFactory.create(name);
}
return pool;
private void applyPoolConfigurers() {
applyPoolConfigurers(getCompositePoolConfigurer());
}
/**
* Determines whether the GemFire DistributedSystem exists yet or not.
* Null-safe operation to apply the given array of {@link PoolConfigurer PoolConfigurers}
* to this {@link PoolFactoryBean}.
*
* @return a boolean value indicating whether the single, GemFire DistributedSystem has been created already.
* @param poolConfigurers array of {@link PoolConfigurer PoolConfigurers} applied to this {@link PoolFactoryBean}.
* @see org.springframework.data.gemfire.config.annotation.PoolConfigurer
* @see #applyPoolConfigurers(Iterable)
*/
protected void applyPoolConfigurers(PoolConfigurer... poolConfigurers) {
applyPoolConfigurers(Arrays.asList(nullSafeArray(poolConfigurers, PoolConfigurer.class)));
}
/**
* Null-safe operation to apply the given {@link Iterable} of {@link PoolConfigurer PoolConfigurers}
* to this {@link PoolFactoryBean}.
*
* @param poolConfigurers {@link Iterable} of {@link PoolConfigurer PoolConfigurers}
* applied to this {@link PoolFactoryBean}.
* @see org.springframework.data.gemfire.config.annotation.PoolConfigurer
*/
protected void applyPoolConfigurers(Iterable<PoolConfigurer> poolConfigurers) {
stream(nullSafeIterable(poolConfigurers).spliterator(), false)
.forEach(poolConfigurer -> poolConfigurer.configure(getName(), this));
}
/* (non-Javadoc) */
private String validatePoolName() {
if (!StringUtils.hasText(getName())) {
setName(Optional.ofNullable(getBeanName()).filter(StringUtils::hasText)
.orElseThrow(() -> newIllegalArgumentException("Pool name is required")));
}
return getName();
}
/**
* Releases all system resources and destroys the {@link Pool} when created by this {@link PoolFactoryBean}.
*
* @throws Exception if the {@link Pool} destruction caused an error.
* @see org.springframework.beans.factory.DisposableBean#destroy()
*/
@Override
public void destroy() throws Exception {
Optional.ofNullable(this.pool)
.filter(pool -> this.springBasedPool)
.filter(pool -> !pool.isDestroyed())
.ifPresent(pool -> {
pool.releaseThreadLocalConnection();
pool.destroy(this.keepAlive);
setPool(null);
logDebug("Destroyed Pool [%s]", pool.getName());
});
}
/**
* Returns a reference to the Composite {@link PoolConfigurer} used to apply additional configuration
* to this {@link PoolFactoryBean} on Spring container initialization.
*
* @return the Composite {@link PoolConfigurer}.
* @see org.springframework.data.gemfire.config.annotation.PoolConfigurer
*/
protected PoolConfigurer getCompositePoolConfigurer() {
return this.compositePoolConfigurer;
}
/**
* Returns an object reference to the {@link Pool} created by this {@link PoolFactoryBean}.
*
* @return an object reference to the {@link Pool} created by this {@link PoolFactoryBean}.
* @see org.springframework.beans.factory.FactoryBean#getObject()
* @see org.apache.geode.cache.client.Pool
*/
@Override
public Pool getObject() throws Exception {
return Optional.ofNullable(this.pool).orElseGet(() -> {
eagerlyInitializeClientCacheIfNotPresent();
PoolFactory poolFactory = configure(createPoolFactory());
this.pool = create(poolFactory, getName());
return this.pool;
});
}
/**
* Determines whether the {@link DistributedSystem} exists yet or not.
*
* @return a boolean value indicating whether the single, {@link DistributedSystem} has already been created.
* @see org.springframework.data.gemfire.GemfireUtils#getDistributedSystem()
* @see org.springframework.data.gemfire.GemfireUtils#isConnected(DistributedSystem)
* @see org.apache.geode.distributed.DistributedSystem
@@ -217,22 +253,22 @@ public class PoolFactoryBean implements FactoryBean<Pool>, InitializingBean, Dis
}
/**
* Attempts to eagerly initialize the GemFire {@link ClientCache} if not already present so that the single
* {@link org.apache.geode.distributed.DistributedSystem} will exists, which is required to create
* a {@link Pool} instance.
* Attempts to eagerly initialize the {@link ClientCache} if not already present so that a single
* {@link DistributedSystem} will exist, which is required to create a {@link Pool} instance.
*
* @see org.springframework.beans.factory.BeanFactory#getBean(Class)
* @see org.apache.geode.cache.client.ClientCache
* @see org.apache.geode.distributed.DistributedSystem
* @see #isDistributedSystemPresent()
*/
void eagerlyInitializeClientCacheIfNotPresent() {
private void eagerlyInitializeClientCacheIfNotPresent() {
if (!isDistributedSystemPresent()) {
getBeanFactory().getBean(ClientCache.class);
}
}
/**
* Creates an instance of the GemFire {@link PoolFactory} interface to construct, configure and initialize
* a GemFire {@link Pool}.
* Creates an instance of the {@link PoolFactory} interface to construct, configure and initialize a {@link Pool}.
*
* @return a {@link PoolFactory} implementation to create a {@link Pool}.
* @see org.apache.geode.cache.client.PoolManager#createFactory()
@@ -242,16 +278,68 @@ public class PoolFactoryBean implements FactoryBean<Pool>, InitializingBean, Dis
return PoolManager.createFactory();
}
/* (non-Javadoc) */
@Override
public Class<?> getObjectType() {
return (this.pool != null ? this.pool.getClass() : Pool.class);
/**
* Configures the given {@link PoolFactory} from this {@link PoolFactoryBean}.
*
* @param poolFactory {@link PoolFactory} to configure.
* @return the given {@link PoolFactory}.
* @see org.apache.geode.cache.client.PoolFactory
*/
protected PoolFactory configure(PoolFactory poolFactory) {
Optional.ofNullable(poolFactory).ifPresent(it -> {
it.setFreeConnectionTimeout(this.freeConnectionTimeout);
it.setIdleTimeout(this.idleTimeout);
it.setLoadConditioningInterval(this.loadConditioningInterval);
it.setMaxConnections(this.maxConnections);
it.setMinConnections(this.minConnections);
it.setMultiuserAuthentication(this.multiUserAuthentication);
it.setPingInterval(this.pingInterval);
it.setPRSingleHopEnabled(this.prSingleHopEnabled);
it.setReadTimeout(this.readTimeout);
it.setRetryAttempts(this.retryAttempts);
it.setServerGroup(this.serverGroup);
it.setSocketBufferSize(this.socketBufferSize);
it.setStatisticInterval(this.statisticInterval);
it.setSubscriptionAckInterval(this.subscriptionAckInterval);
it.setSubscriptionEnabled(this.subscriptionEnabled);
it.setSubscriptionMessageTrackingTimeout(this.subscriptionMessageTrackingTimeout);
it.setSubscriptionRedundancy(this.subscriptionRedundancy);
it.setThreadLocalConnections(this.threadLocalConnections);
nullSafeCollection(this.locators).forEach(locator ->
it.addLocator(locator.getHost(), locator.getPort()));
nullSafeCollection(this.servers).forEach(server ->
it.addServer(server.getHost(), server.getPort()));
});
return poolFactory;
}
/* (non-Javadoc) */
/**
* Creates a {@link Pool} with the given {@link String name} using the provided {@link PoolFactory}.
*
* @param poolFactory {@link PoolFactory} used to create the {@link Pool}.
* @param poolName {@link String name} of the new {@link Pool}.
* @return a new instance of {@link Pool} with the given {@link String name}.
* @see org.apache.geode.cache.client.PoolFactory#create(String)
* @see org.apache.geode.cache.client.Pool
*/
protected Pool create(PoolFactory poolFactory, String poolName) {
return poolFactory.create(poolName);
}
/**
* Returns the {@link Class} type of the {@link Pool} produced by this {@link PoolFactoryBean}.
*
* @return the {@link Class} type of the {@link Pool} produced by this {@link PoolFactoryBean}.
* @see org.springframework.beans.factory.FactoryBean#getObjectType()
*/
@Override
public boolean isSingleton() {
return true;
@SuppressWarnings("unchecked")
public Class<?> getObjectType() {
return Optional.ofNullable(this.pool).map(Pool::getClass).orElse((Class) Pool.class);
}
/* (non-Javadoc) */
@@ -274,29 +362,14 @@ public class PoolFactoryBean implements FactoryBean<Pool>, InitializingBean, Dis
this.servers.add(servers);
}
/* (non-Javadoc) */
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
}
/* (non-Javadoc) */
protected BeanFactory getBeanFactory() {
return beanFactory;
}
/* (non-Javadoc) */
public void setBeanName(String name) {
this.beanName = name;
}
/* (non-Javadoc) */
public void setName(String name) {
this.name = name;
}
/* (non-Javadoc) */
String getName() {
return name;
protected String getName() {
return this.name;
}
/* (non-Javadoc) */
@@ -350,9 +423,8 @@ public class PoolFactoryBean implements FactoryBean<Pool>, InitializingBean, Dis
@Override
public String getName() {
String name = PoolFactoryBean.this.name;
name = (StringUtils.hasText(name) ? name : PoolFactoryBean.this.beanName);
return name;
return Optional.ofNullable(PoolFactoryBean.this.getName()).filter(StringUtils::hasText)
.orElseGet(PoolFactoryBean.this::getBeanName);
}
@Override
@@ -525,6 +597,31 @@ public class PoolFactoryBean implements FactoryBean<Pool>, InitializingBean, Dis
this.pingInterval = pingInterval;
}
/**
* Null-safe operation to set an array of {@link PoolConfigurer PoolConfigurers} used to apply
* additional configuration to this {@link PoolFactoryBean} when using Annotation-based configuration.
*
* @param poolConfigurers array of {@link PoolConfigurer PoolConfigurers} used to apply
* additional configuration to this {@link PoolFactoryBean}.
* @see org.springframework.data.gemfire.config.annotation.PoolConfigurer
* @see #setPoolConfigurers(List)
*/
public void setPoolConfigurers(PoolConfigurer... poolConfigurers) {
setPoolConfigurers(Arrays.asList(nullSafeArray(poolConfigurers, PoolConfigurer.class)));
}
/**
* Null-safe operation to set an {@link Iterable} of {@link PoolConfigurer PoolConfigurers} used to apply
* additional configuration to this {@link PoolFactoryBean} when using Annotation-based configuration.
*
* @param poolConfigurers {@link Iterable} of {@link PoolConfigurer PoolConfigurers} used to apply
* additional configuration to this {@link PoolFactoryBean}.
* @see org.springframework.data.gemfire.config.annotation.PoolConfigurer
*/
public void setPoolConfigurers(List<PoolConfigurer> poolConfigurers) {
this.poolConfigurers = Optional.ofNullable(poolConfigurers).orElseGet(Collections::emptyList);
}
/* (non-Javadoc) */
public void setPrSingleHopEnabled(boolean prSingleHopEnabled) {
this.prSingleHopEnabled = prSingleHopEnabled;
@@ -596,11 +693,17 @@ public class PoolFactoryBean implements FactoryBean<Pool>, InitializingBean, Dis
this.threadLocalConnections = threadLocalConnections;
}
/* (non-Javadoc; internal framework use only) */
/*
* (non-Javadoc)
* internal framework use only
*/
public final void setLocatorsConfiguration(Object locatorsConfiguration) {
}
/* (non-Javadoc; internal framework use only) */
/*
* (non-Javadoc)
* internal framework use only
*/
public final void setServersConfiguration(Object serversConfiguration) {
}
}

View File

@@ -20,29 +20,26 @@ package org.springframework.data.gemfire.config.annotation;
import static org.springframework.data.gemfire.CacheFactoryBean.DynamicRegionSupport;
import static org.springframework.data.gemfire.CacheFactoryBean.JndiDataSource;
import static org.springframework.data.gemfire.util.CollectionUtils.nullSafeList;
import static org.springframework.data.gemfire.util.SpringUtils.defaultIfNull;
import java.lang.annotation.Annotation;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Properties;
import java.util.concurrent.atomic.AtomicBoolean;
import org.apache.geode.cache.Cache;
import org.apache.geode.cache.TransactionListener;
import org.apache.geode.cache.TransactionWriter;
import org.apache.geode.cache.client.ClientCache;
import org.apache.geode.cache.server.CacheServer;
import org.apache.geode.cache.util.GatewayConflictResolver;
import org.apache.geode.pdx.PdxSerializer;
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.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportAware;
@@ -50,6 +47,7 @@ import org.springframework.core.convert.ConversionService;
import org.springframework.core.io.Resource;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.data.gemfire.CacheFactoryBean;
import org.springframework.data.gemfire.config.annotation.support.AbstractAnnotationConfigSupport;
import org.springframework.data.gemfire.config.support.CustomEditorBeanFactoryPostProcessor;
import org.springframework.data.gemfire.config.support.DefinedIndexesApplicationListener;
import org.springframework.data.gemfire.config.support.DiskStoreDirectoryBeanPostProcessor;
@@ -57,33 +55,48 @@ import org.springframework.data.gemfire.config.support.PdxDiskStoreAwareBeanFact
import org.springframework.data.gemfire.mapping.GemfireMappingContext;
import org.springframework.data.gemfire.mapping.MappingPdxSerializer;
import org.springframework.data.gemfire.util.PropertiesBuilder;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
* {@link AbstractCacheConfiguration} is an abstract base class for configuring either a Pivotal GemFire/Apache Geode
* client or peer-based cache instance using Spring's Java-based, Annotation
* {@link org.springframework.context.annotation.Configuration} support.
* client or peer-based cache instance using Spring's Java-based, Annotation {@link Configuration} support.
*
* This class encapsulates configuration settings common to both GemFire peer
* {@link org.apache.geode.cache.Cache caches} and
* {@link org.apache.geode.cache.client.ClientCache client caches}.
* This class encapsulates configuration settings common to both Pivotal GemFire/Apache Geode
* {@link org.apache.geode.cache.Cache peer caches}
* and {@link org.apache.geode.cache.client.ClientCache client caches}.
*
* @author John Blum
* @see org.springframework.beans.factory.BeanClassLoaderAware
* @see java.lang.annotation.Annotation
* @see java.util.Properties
* @see org.apache.geode.cache.Cache
* @see org.apache.geode.cache.GemFireCache
* @see org.apache.geode.cache.client.ClientCache
* @see org.apache.geode.cache.server.CacheServer
* @see org.apache.geode.pdx.PdxSerializer
* @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
* @see org.springframework.context.annotation.Bean
* @see org.springframework.context.annotation.Configuration
* @see org.springframework.context.annotation.ImportAware
* @see org.springframework.core.convert.ConversionService
* @see org.springframework.core.io.Resource
* @see org.springframework.core.type.AnnotationMetadata
* @see org.springframework.data.gemfire.CacheFactoryBean
* @see org.springframework.data.gemfire.client.ClientCacheFactoryBean
* @see org.springframework.data.gemfire.config.annotation.support.AbstractAnnotationConfigSupport
* @see org.springframework.data.gemfire.config.support.CustomEditorBeanFactoryPostProcessor
* @see org.springframework.data.gemfire.config.support.DefinedIndexesApplicationListener
* @see org.springframework.data.gemfire.config.support.DiskStoreDirectoryBeanPostProcessor
* @see org.springframework.data.gemfire.config.support.PdxDiskStoreAwareBeanFactoryPostProcessor
* @see org.springframework.data.gemfire.mapping.GemfireMappingContext
* @see org.springframework.data.gemfire.mapping.MappingPdxSerializer
* @since 1.9.0
*/
@Configuration
@SuppressWarnings("unused")
public abstract class AbstractCacheConfiguration implements BeanClassLoaderAware, BeanFactoryAware, ImportAware {
public abstract class AbstractCacheConfiguration extends AbstractAnnotationConfigSupport implements ImportAware {
private static final AtomicBoolean CUSTOM_EDITORS_REGISTERED = new AtomicBoolean(false);
private static final AtomicBoolean DEFINED_INDEXES_APPLICATION_LISTENER_REGISTERED = new AtomicBoolean(false);
@@ -104,14 +117,10 @@ public abstract class AbstractCacheConfiguration implements BeanClassLoaderAware
private boolean copyOnRead = DEFAULT_COPY_ON_READ;
private boolean useBeanFactoryLocator = DEFAULT_USE_BEAN_FACTORY_LOCATOR;
private BeanFactory beanFactory;
private Boolean pdxIgnoreUnreadFields;
private Boolean pdxPersistent;
private Boolean pdxReadSerialized;
private ClassLoader beanClassLoader;
private DynamicRegionSupport dynamicRegionSupport;
private Integer mcastPort = 0;
@@ -142,59 +151,30 @@ public abstract class AbstractCacheConfiguration implements BeanClassLoaderAware
private TransactionWriter transactionWriter;
/**
* Determines whether the given {@link Object} has value. The {@link Object} is valuable
* if it is not {@literal null}.
* Returns a {@link Properties} object containing Pivotal GemFire/Apache Geode properties used to configure
* the Pivotal GemFire/Apache Geode cache.
*
* @param value {@link Object} to evaluate.
* @return a boolean value indicating whether the given {@link Object} has value.
*/
protected static boolean hasValue(Object value) {
return (value != null);
}
/**
* Determines whether the given {@link Number} has value. The {@link Number} is valuable
* if it is not {@literal null} and is not equal to 0.0d.
* The {@literal name} of the Pivotal GemFire/Apache Geode member/node in the cluster is set to a default,
* pre-defined and descriptive value depending on the type of configuration meta-data applied.
*
* @param value {@link Number} to evaluate.
* @return a boolean value indicating whether the given {@link Number} has value.
*/
protected static boolean hasValue(Number value) {
return (value != null && value.doubleValue() != 0.0d);
}
/**
* Determines whether the given {@link String} has value. The {@link String} is valuable
* if it is not {@literal null} or empty.
* {@literal mcast-port} is set to {@literal 0} and {@literal locators} is set to an {@link String empty String},
* which is necessary for {@link ClientCache cache client}-based applications. These values can be changed
* and set accoridingly for {@link Cache peer cache} and {@link CacheServer cache server} applications.
*
* @param value {@link String} to evaluate.
* @return a boolean value indicating whether the given {@link String} is valuable.
*/
protected static boolean hasValue(String value) {
return StringUtils.hasText(value);
}
/**
* Returns a {@link Properties} object containing GemFire System properties used to configure the GemFire cache.
* Finally, the {@literal log-level} property defaults to {@literal config}.
*
* The name of the GemFire member/node in the cluster is set to a default, pre-defined, descriptive value
* depending on the type of configuration meta-data applied.
*
* Both 'mcast-port' and 'locators' are to set 0 and empty String respectively, which is necessary
* for {@link org.apache.geode.cache.client.ClientCache cache client}-based applications. These values
* can be changed for peer cache and cache server applications.
*
* Finally, GemFire's {@literal log-level} System property defaults to {@literal config}.
*
* @return a {@link Properties} object containing GemFire System properties used to configure the GemFire cache.
* @return a {@link Properties} object containing Pivotal GemFire/Apache Geode properties used to configure
* the Pivotal GemFire/Apache Geode cache instance.
* @see <a link="http://gemfire.docs.pivotal.io/docs-gemfire/reference/topics/gemfire_properties.html">GemFire Properties</a>
* @see java.util.Properties
* @see #name()
* @see #logLevel()
* @see #locators()
* @see #logLevel()
* @see #mcastPort()
* @see #name()
*/
@Bean
protected Properties gemfireProperties() {
PropertiesBuilder gemfireProperties = PropertiesBuilder.create();
gemfireProperties.setProperty("name", name());
@@ -202,100 +182,87 @@ public abstract class AbstractCacheConfiguration implements BeanClassLoaderAware
gemfireProperties.setProperty("log-level", logLevel());
gemfireProperties.setProperty("locators", locators());
gemfireProperties.setProperty("start-locator", startLocator());
gemfireProperties.add(customGemFireProperties);
gemfireProperties.add(this.customGemFireProperties);
return gemfireProperties.build();
}
/**
* {@inheritDoc}
*/
@Override
public void setBeanClassLoader(ClassLoader beanClassLoader) {
this.beanClassLoader = beanClassLoader;
}
/**
* Returns a reference to the {@link ClassLoader} use by the Spring {@link BeanFactory} to load classes
* for bean definitions.
*
* @return the {@link ClassLoader} used by the Spring {@link BeanFactory} to load classes for bean definitions.
* @see #setBeanClassLoader(ClassLoader)
*/
protected ClassLoader beanClassLoader() {
return beanClassLoader;
}
/**
* {@inheritDoc}
*/
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
}
/**
* Returns a reference to the Spring {@link BeanFactory} in the current application context.
*
* @return a reference to the Spring {@link BeanFactory}.
* @throws IllegalStateException if the Spring {@link BeanFactory} was not properly initialized.
* @see org.springframework.beans.factory.BeanFactory
*/
protected BeanFactory beanFactory() {
Assert.state(this.beanFactory != null, "BeanFactory was not properly initialized");
return this.beanFactory;
}
/**
* {@inheritDoc}
*/
@Override
public void setImportMetadata(AnnotationMetadata importMetadata) {
configureInfrastructure(importMetadata);
configureCache(importMetadata);
configurePdx(importMetadata);
configureOther(importMetadata);
configureTheRest(importMetadata);
}
/**
* Configures Spring container infrastructure components used by Spring Data GemFire
* to enable GemFire to function properly inside a Spring context.
* Configures Spring container infrastructure components and beans used by Spring Data GemFire
* to enable Pivotal GemFire or Apache Geode to function properly inside a Spring context.
*
* @param importMetadata {@link AnnotationMetadata} containing annotation meta-data
* for the Spring GemFire cache application class.
* for the Spring Data GemFire cache application class.
* @see org.springframework.core.type.AnnotationMetadata
*/
protected void configureInfrastructure(AnnotationMetadata importMetadata) {
registerCustomEditorBeanFactoryPostProcessor(importMetadata);
registerDefinedIndexesApplicationListener(importMetadata);
registerDiskStoreDirectoryBeanPostProcessor(importMetadata);
}
/* (non-Javadoc) */
private void registerCustomEditorBeanFactoryPostProcessor(AnnotationMetadata importMetadata) {
if (CUSTOM_EDITORS_REGISTERED.compareAndSet(false, true)) {
register(BeanDefinitionBuilder.rootBeanDefinition(CustomEditorBeanFactoryPostProcessor.class)
.setRole(BeanDefinition.ROLE_INFRASTRUCTURE).getBeanDefinition());
}
}
/* (non-Javadoc) */
private void registerDefinedIndexesApplicationListener(AnnotationMetadata importMetadata) {
if (DEFINED_INDEXES_APPLICATION_LISTENER_REGISTERED.compareAndSet(false, true)) {
register(BeanDefinitionBuilder.rootBeanDefinition(DefinedIndexesApplicationListener.class)
.setRole(BeanDefinition.ROLE_INFRASTRUCTURE).getBeanDefinition());
}
}
/* (non-Javadoc) */
private void registerDiskStoreDirectoryBeanPostProcessor(AnnotationMetadata importMetadata) {
if (DISK_STORE_DIRECTORY_BEAN_POST_PROCESSOR_REGISTERED.compareAndSet(false, true)) {
register(BeanDefinitionBuilder.rootBeanDefinition(DiskStoreDirectoryBeanPostProcessor.class)
.setRole(BeanDefinition.ROLE_INFRASTRUCTURE).getBeanDefinition());
}
}
/**
* Configures the GemFire cache settings.
* Configures Pivotal GemFire/Apache Geode cache specific settings.
*
* @param importMetadata {@link AnnotationMetadata} containing the cache meta-data used to configure
* the GemFire cache.
* @param importMetadata {@link AnnotationMetadata} containing the cache meta-data used to configure the cache.
* @see org.springframework.core.type.AnnotationMetadata
*/
protected void configureCache(AnnotationMetadata importMetadata) {
if (isClientPeerOrServerCacheApplication(importMetadata)) {
Map<String, Object> cacheMetadataAttributes =
importMetadata.getAnnotationAttributes(getAnnotationTypeName());
setCopyOnRead(Boolean.TRUE.equals(cacheMetadataAttributes.get("copyOnRead")));
Float criticalHeapPercentage = (Float) cacheMetadataAttributes.get("criticalHeapPercentage");
Optional.ofNullable((Float) cacheMetadataAttributes.get("criticalHeapPercentage"))
.filter(AbstractAnnotationConfigSupport::hasValue)
.ifPresent(this::setCriticalHeapPercentage);
if (hasValue(criticalHeapPercentage)) {
setCriticalHeapPercentage(criticalHeapPercentage);
}
Float evictionHeapPercentage = (Float) cacheMetadataAttributes.get("evictionHeapPercentage");
if (hasValue(evictionHeapPercentage)) {
setEvictionHeapPercentage(evictionHeapPercentage);
}
Optional.ofNullable((Float) cacheMetadataAttributes.get("evictionHeapPercentage"))
.filter(AbstractAnnotationConfigSupport::hasValue)
.ifPresent(this::setEvictionHeapPercentage);
setLogLevel((String) cacheMetadataAttributes.get("logLevel"));
setName((String) cacheMetadataAttributes.get("name"));
@@ -304,17 +271,19 @@ public abstract class AbstractCacheConfiguration implements BeanClassLoaderAware
}
/**
* Configures GemFire's PDX Serialization components.
* Configures Pivotal GemFire/Apache Geode cache PDX Serialization.
*
* @param importMetadata {@link AnnotationMetadata} containing PDX meta-data used to configure
* the GemFire cache with PDX de/serialization capabilities.
* @param importMetadata {@link AnnotationMetadata} containing PDX meta-data used to configure the cache
* with PDX de/serialization capabilities.
* @see org.springframework.core.type.AnnotationMetadata
* @see <a href="http://gemfire.docs.pivotal.io/docs-gemfire/latest/developing/data_serialization/gemfire_pdx_serialization.html">GemFire PDX Serialization</a>
*/
protected void configurePdx(AnnotationMetadata importMetadata) {
String enablePdxTypeName = EnablePdx.class.getName();
if (importMetadata.hasAnnotation(enablePdxTypeName)) {
Map<String, Object> enablePdxAttributes = importMetadata.getAnnotationAttributes(enablePdxTypeName);
setPdxDiskStoreName((String) enablePdxAttributes.get("diskStoreName"));
@@ -328,97 +297,158 @@ public abstract class AbstractCacheConfiguration implements BeanClassLoaderAware
}
/**
* Callback method to configure other, specific GemFire cache configuration settings.
* Resolves the {@link PdxSerializer} used to configure the cache for PDX De/Serialization.
*
* @param importMetadata {@link AnnotationMetadata} containing meta-data used to configure
* the GemFire cache.
* @see org.springframework.core.type.AnnotationMetadata
*/
protected void configureOther(AnnotationMetadata importMetadata) {
}
/* (non-Javadoc) */
protected PdxSerializer resolvePdxSerializer(String pdxSerializerBeanName) {
BeanFactory beanFactory = beanFactory();
PdxSerializer pdxSerializer = pdxSerializer();
return (beanFactory.containsBean(pdxSerializerBeanName)
? beanFactory.getBean(pdxSerializerBeanName, PdxSerializer.class)
: (pdxSerializer != null ? pdxSerializer : newPdxSerializer()));
}
/* (non-Javadoc) */
@SuppressWarnings("unchecked")
protected <T extends PdxSerializer> T newPdxSerializer() {
BeanFactory beanFactory = beanFactory();
ConversionService conversionService = (beanFactory instanceof ConfigurableBeanFactory
? ((ConfigurableBeanFactory) beanFactory).getConversionService() : null);
return (T) MappingPdxSerializer.create(this.mappingContext, conversionService);
}
/* (non-Javadoc) */
protected void registerCustomEditorBeanFactoryPostProcessor(AnnotationMetadata importMetadata) {
if (CUSTOM_EDITORS_REGISTERED.compareAndSet(false, true)) {
register(BeanDefinitionBuilder.rootBeanDefinition(CustomEditorBeanFactoryPostProcessor.class)
.setRole(BeanDefinition.ROLE_INFRASTRUCTURE).getBeanDefinition());
}
}
/* (non-Javadoc) */
protected void registerDefinedIndexesApplicationListener(AnnotationMetadata importMetadata) {
if (DEFINED_INDEXES_APPLICATION_LISTENER_REGISTERED.compareAndSet(false, true)) {
register(BeanDefinitionBuilder.rootBeanDefinition(DefinedIndexesApplicationListener.class)
.setRole(BeanDefinition.ROLE_INFRASTRUCTURE).getBeanDefinition());
}
}
/* (non-Javadoc) */
protected void registerDiskStoreDirectoryBeanPostProcessor(AnnotationMetadata importMetadata) {
if (DISK_STORE_DIRECTORY_BEAN_POST_PROCESSOR_REGISTERED.compareAndSet(false, true)) {
register(BeanDefinitionBuilder.rootBeanDefinition(DiskStoreDirectoryBeanPostProcessor.class)
.setRole(BeanDefinition.ROLE_INFRASTRUCTURE).getBeanDefinition());
}
}
/* (non-Javadoc) */
protected void registerPdxDiskStoreAwareBeanFactoryPostProcessor(AnnotationMetadata importMetadata) {
if (StringUtils.hasText(pdxDiskStoreName())) {
if (PDX_DISK_STORE_AWARE_BEAN_FACTORY_POST_PROCESSOR_REGISTERED.compareAndSet(false, true)) {
register(BeanDefinitionBuilder.rootBeanDefinition(PdxDiskStoreAwareBeanFactoryPostProcessor.class)
.setRole(BeanDefinition.ROLE_INFRASTRUCTURE)
.addConstructorArgValue(pdxDiskStoreName())
.getBeanDefinition());
}
}
}
/**
* Registers the given {@link BeanDefinition} with the {@link BeanDefinitionRegistry} using a generated bean name.
*
* @param beanDefinition {@link AbstractBeanDefinition} to register.
* @return the given {@link BeanDefinition}.
* @see org.springframework.beans.factory.support.AbstractBeanDefinition
* @see org.springframework.beans.factory.support.BeanDefinitionRegistry
* @see org.springframework.beans.factory.support.BeanDefinitionReaderUtils
* #registerWithGeneratedName(AbstractBeanDefinition, BeanDefinitionRegistry)
* @param pdxSerializerBeanName {@link String} containing the name of a Spring bean
* implementing the {@link PdxSerializer} interface.
* @return the resolved {@link PdxSerializer} from configuration.
* @see org.apache.geode.pdx.PdxSerializer
* @see #newPdxSerializer(BeanFactory)
* @see #beanFactory()
*/
protected AbstractBeanDefinition register(AbstractBeanDefinition beanDefinition) {
if (beanFactory() instanceof BeanDefinitionRegistry) {
BeanDefinitionReaderUtils.registerWithGeneratedName(beanDefinition,
((BeanDefinitionRegistry) beanFactory()));
}
protected PdxSerializer resolvePdxSerializer(String pdxSerializerBeanName) {
return beanDefinition;
BeanFactory beanFactory = beanFactory();
return Optional.ofNullable(pdxSerializerBeanName)
.filter(beanFactory::containsBean)
.map(beanName -> beanFactory.getBean(beanName, PdxSerializer.class))
.orElseGet(() -> Optional.ofNullable(pdxSerializer()).orElseGet(() -> newPdxSerializer(beanFactory)));
}
/**
* Returns the GemFire cache application {@link java.lang.annotation.Annotation} type pertaining to
* this configuration.
* Constructs a new instance of {@link PdxSerializer}.
*
* @return the GemFire cache application {@link java.lang.annotation.Annotation} type used by this application.
* @param <T> {@link Class} type of the {@link PdxSerializer}.
* @return a new instance of {@link PdxSerializer}.
* @see org.apache.geode.pdx.PdxSerializer
* @see #newPdxSerializer(BeanFactory)
*/
@SuppressWarnings("unchecked")
protected <T extends PdxSerializer> T newPdxSerializer() {
return newPdxSerializer(beanFactory());
}
/**
* Constructs a new instance of {@link MappingPdxSerializer}.
*
* @param <T> {@link Class} type of the {@link PdxSerializer}; this method returns a {@link MappingPdxSerializer}.
* @param beanFactory {@link BeanFactory} used to get an instance of {@link ConversionService}
* used by the {@link MappingPdxSerializer}.
* @return a new instance of {@link MappingPdxSerializer}.
* @see org.springframework.data.gemfire.mapping.MappingPdxSerializer
* @see org.springframework.beans.factory.BeanFactory
* @see org.apache.geode.pdx.PdxSerializer
*/
@SuppressWarnings("unchecked")
protected <T extends PdxSerializer> T newPdxSerializer(BeanFactory beanFactory) {
Optional<ConversionService> conversionService = Optional.ofNullable(beanFactory)
.filter(it -> it instanceof ConfigurableBeanFactory)
.map(it -> ((ConfigurableBeanFactory) it).getConversionService());
return (T) MappingPdxSerializer.create(this.mappingContext, conversionService.orElse(null));
}
/* (non-Javadoc) */
private void registerPdxDiskStoreAwareBeanFactoryPostProcessor(AnnotationMetadata importMetadata) {
Optional.ofNullable(pdxDiskStoreName())
.filter(StringUtils::hasText)
.ifPresent(pdxDiskStoreName -> {
if (PDX_DISK_STORE_AWARE_BEAN_FACTORY_POST_PROCESSOR_REGISTERED.compareAndSet(false, true)) {
register(BeanDefinitionBuilder.rootBeanDefinition(PdxDiskStoreAwareBeanFactoryPostProcessor.class)
.setRole(BeanDefinition.ROLE_INFRASTRUCTURE)
.addConstructorArgValue(pdxDiskStoreName)
.getBeanDefinition());
}
});
}
/**
* Callback method allowing developers to configure other cache or application specific configuration settings.
*
* @param importMetadata {@link AnnotationMetadata} containing meta-data used to configure the cache or application.
* @see org.springframework.core.type.AnnotationMetadata
*/
protected void configureTheRest(AnnotationMetadata importMetadata) {
}
/**
* Constructs a new, initialized instance of {@link CacheFactoryBean} based on the Spring application's
* cache type preference (i.e. client or peer), which is expressed via the appropriate annotation.
*
* Use the {@link ClientCacheApplication} Annotation to construct a {@link ClientCache cache client} application.
*
* Use the {@link PeerCacheApplication} Annotation to construct a {@link Cache peer cache} application.
*
* @param <T> {@link Class} specific sub-type of the {@link CacheFactoryBean}.
* @return a new instance of the appropriate {@link CacheFactoryBean} given the Spring application's
* cache type preference (i.e client or peer), (e.g. {@link ClientCacheApplication}
* or {@link PeerCacheApplication}).
* @see org.springframework.data.gemfire.client.ClientCacheFactoryBean
* @see org.springframework.data.gemfire.CacheFactoryBean
* @see #configureCacheFactoryBean(CacheFactoryBean)
* @see #newCacheFactoryBean()
*/
protected <T extends CacheFactoryBean> T constructCacheFactoryBean() {
return configureCacheFactoryBean(this.<T>newCacheFactoryBean());
}
/**
* Constructs a new, uninitialized instance of {@link CacheFactoryBean} based on the Spring application's
* cache type preference (i.e. client or peer), which is expressed via the appropriate annotation.
*
* Use the {@link ClientCacheApplication} Annotation to construct a {@link ClientCache cache client} application.
*
* Use the {@link PeerCacheApplication} Annotation to construct a {@link Cache peer cache} application.
*
* @param <T> {@link Class} specific sub-type of the {@link CacheFactoryBean}.
* @return a new instance of the appropriate {@link CacheFactoryBean} given the Spring application's
* cache type preference (i.e client or peer), (e.g. {@link ClientCacheApplication}
* or {@link PeerCacheApplication}).
* @see org.springframework.data.gemfire.client.ClientCacheFactoryBean
* @see org.springframework.data.gemfire.CacheFactoryBean
*/
protected abstract <T extends CacheFactoryBean> T newCacheFactoryBean();
/**
* Configures the {@link CacheFactoryBean} with common cache configuration settings.
*
* @param <T> {@link Class} specific sub-type of the {@link CacheFactoryBean}.
* @param gemfireCache {@link CacheFactoryBean} to configure.
* @return the given {@link CacheFactoryBean} with common cache configuration settings applied.
* @see org.springframework.data.gemfire.client.ClientCacheFactoryBean
* @see org.springframework.data.gemfire.CacheFactoryBean
*/
protected <T extends CacheFactoryBean> T configureCacheFactoryBean(T gemfireCache) {
gemfireCache.setBeanClassLoader(beanClassLoader());
gemfireCache.setBeanFactory(beanFactory());
gemfireCache.setCacheXml(cacheXml());
gemfireCache.setClose(close());
gemfireCache.setCopyOnRead(copyOnRead());
gemfireCache.setCriticalHeapPercentage(criticalHeapPercentage());
gemfireCache.setDynamicRegionSupport(dynamicRegionSupport());
gemfireCache.setEvictionHeapPercentage(evictionHeapPercentage());
gemfireCache.setGatewayConflictResolver(gatewayConflictResolver());
gemfireCache.setJndiDataSources(jndiDataSources());
gemfireCache.setProperties(gemfireProperties());
gemfireCache.setPdxDiskStoreName(pdxDiskStoreName());
gemfireCache.setPdxIgnoreUnreadFields(pdxIgnoreUnreadFields());
gemfireCache.setPdxPersistent(pdxPersistent());
gemfireCache.setPdxReadSerialized(pdxReadSerialized());
gemfireCache.setPdxSerializer(pdxSerializer());
gemfireCache.setTransactionListeners(transactionListeners());
gemfireCache.setTransactionWriter(transactionWriter());
return gemfireCache;
}
/**
* 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.
* @see org.springframework.data.gemfire.config.annotation.CacheServerApplication
* @see org.springframework.data.gemfire.config.annotation.ClientCacheApplication
* @see org.springframework.data.gemfire.config.annotation.PeerCacheApplication
@@ -426,11 +456,11 @@ public abstract class AbstractCacheConfiguration implements BeanClassLoaderAware
protected abstract Class getAnnotationType();
/**
* Returns the fully-qualified class name of the GemFire cache application {@link java.lang.annotation.Annotation}
* type.
* Returns the fully-qualified {@link Class#getName() class name} of the cache application
* {@link java.lang.annotation.Annotation} type.
*
* @return the fully-qualified class name of the GemFire cache application {@link java.lang.annotation.Annotation}
* type.
* @return the fully-qualified {@link Class#getName() class name} of the cache application
* {@link java.lang.annotation.Annotation} type.
* @see java.lang.Class#getName()
* @see #getAnnotationType()
*/
@@ -439,9 +469,11 @@ public abstract class AbstractCacheConfiguration implements BeanClassLoaderAware
}
/**
* Returns the simple class name of the GemFire cache application {@link java.lang.annotation.Annotation} type.
* Returns the simple {@link Class#getName() class name} of the cache application
* {@link java.lang.annotation.Annotation} type.
*
* @return the simple class name of the GemFire cache application {@link java.lang.annotation.Annotation} type.
* @return the simple {@link Class#getName() class name} of the cache application
* {@link java.lang.annotation.Annotation} type.
* @see java.lang.Class#getSimpleName()
* @see #getAnnotationType()
*/
@@ -449,6 +481,8 @@ public abstract class AbstractCacheConfiguration implements BeanClassLoaderAware
return getAnnotationType().getSimpleName();
}
// REVIEW JAVADOC FROM HERE
/**
* Determines whether this is a GemFire {@link org.apache.geode.cache.server.CacheServer} application,
* which is indicated by the presence of the {@link CacheServerApplication} annotation on a Spring application
@@ -508,7 +542,7 @@ public abstract class AbstractCacheConfiguration implements BeanClassLoaderAware
* @see #getAnnotationType()
*/
protected boolean isTypedCacheApplication(Class<? extends Annotation> annotationType,
AnnotationMetadata importMetadata) {
AnnotationMetadata importMetadata) {
return (annotationType.equals(getAnnotationType()) && importMetadata.hasAnnotation(getAnnotationTypeName()));
}
@@ -549,68 +583,6 @@ public abstract class AbstractCacheConfiguration implements BeanClassLoaderAware
|| isPeerCacheApplication(importMetadata));
}
/**
* Constructs a new, initialized instance of the {@link CacheFactoryBean} based on the Spring application's
* GemFire cache type (i.e. client or peer) preference specified via annotation.
*
* @param <T> Class type of the {@link CacheFactoryBean}.
* @return a new instance of an appropriate {@link CacheFactoryBean} given the Spring application's
* GemFire cache type preference (i.e client or peer) specified with the corresponding annotation
* (e.g. {@link ClientCacheApplication} or {@link PeerCacheApplication});
* @see org.springframework.data.gemfire.client.ClientCacheFactoryBean
* @see org.springframework.data.gemfire.CacheFactoryBean
* @see #setCommonCacheConfiguration(CacheFactoryBean)
* @see #newCacheFactoryBean()
*/
protected <T extends CacheFactoryBean> T constructCacheFactoryBean() {
return setCommonCacheConfiguration(this.<T>newCacheFactoryBean());
}
/**
* Constructs a new, uninitialized instance of the {@link CacheFactoryBean} based on the Spring application's
* GemFire cache type (i.e. client or peer) preference specified via annotation.
*
* @param <T> Class type of the {@link CacheFactoryBean}.
* @return a new instance of an appropriate {@link CacheFactoryBean} given the Spring application's
* GemFire cache type preference (i.e client or peer) specified with the corresponding annotation
* (e.g. {@link ClientCacheApplication} or {@link PeerCacheApplication}).
* @see org.springframework.data.gemfire.client.ClientCacheFactoryBean
* @see org.springframework.data.gemfire.CacheFactoryBean
*/
protected abstract <T extends CacheFactoryBean> T newCacheFactoryBean();
/**
* Configures common GemFire cache configuration settings.
*
* @param <T> Class type of the {@link CacheFactoryBean}.
* @param gemfireCache {@link CacheFactoryBean} instance to configure.
* @return the given {@link CacheFactoryBean} after common configuration settings have been applied.
* @see org.springframework.data.gemfire.client.ClientCacheFactoryBean
* @see org.springframework.data.gemfire.CacheFactoryBean
*/
protected <T extends CacheFactoryBean> T setCommonCacheConfiguration(T gemfireCache) {
gemfireCache.setBeanClassLoader(beanClassLoader());
gemfireCache.setBeanFactory(beanFactory());
gemfireCache.setCacheXml(cacheXml());
gemfireCache.setClose(close());
gemfireCache.setCopyOnRead(copyOnRead());
gemfireCache.setCriticalHeapPercentage(criticalHeapPercentage());
gemfireCache.setDynamicRegionSupport(dynamicRegionSupport());
gemfireCache.setEvictionHeapPercentage(evictionHeapPercentage());
gemfireCache.setGatewayConflictResolver(gatewayConflictResolver());
gemfireCache.setJndiDataSources(jndiDataSources());
gemfireCache.setProperties(gemfireProperties());
gemfireCache.setPdxDiskStoreName(pdxDiskStoreName());
gemfireCache.setPdxIgnoreUnreadFields(pdxIgnoreUnreadFields());
gemfireCache.setPdxPersistent(pdxPersistent());
gemfireCache.setPdxReadSerialized(pdxReadSerialized());
gemfireCache.setPdxSerializer(pdxSerializer());
gemfireCache.setTransactionListeners(transactionListeners());
gemfireCache.setTransactionWriter(transactionWriter());
return gemfireCache;
}
/* (non-Javadoc) */
void setCacheXml(Resource cacheXml) {
this.cacheXml = cacheXml;
@@ -699,7 +671,7 @@ public abstract class AbstractCacheConfiguration implements BeanClassLoaderAware
}
protected String logLevel() {
return defaultIfNull(this.logLevel, DEFAULT_LOG_LEVEL);
return Optional.ofNullable(this.logLevel).orElse(DEFAULT_LOG_LEVEL);
}
/* (non-Javadoc) */
@@ -717,7 +689,7 @@ public abstract class AbstractCacheConfiguration implements BeanClassLoaderAware
}
protected Integer mcastPort() {
return (mcastPort != null ? mcastPort : DEFAULT_MCAST_PORT);
return Optional.ofNullable(mcastPort).orElse(DEFAULT_MCAST_PORT);
}
/* (non-Javadoc) */
@@ -726,7 +698,7 @@ public abstract class AbstractCacheConfiguration implements BeanClassLoaderAware
}
protected String name() {
return (StringUtils.hasText(name) ? name : toString());
return Optional.ofNullable(this.name).filter(StringUtils::hasText).orElseGet(this::toString);
}
/* (non-Javadoc) */

View File

@@ -17,8 +17,22 @@
package org.springframework.data.gemfire.config.annotation;
import java.util.Map;
import static org.springframework.data.gemfire.util.CollectionUtils.nullSafeMap;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
import org.springframework.beans.BeansException;
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;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
@@ -26,27 +40,49 @@ import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.data.gemfire.config.xml.GemfireConstants;
import org.springframework.data.gemfire.server.CacheServerFactoryBean;
import org.springframework.util.StringUtils;
/**
* The {@link AddCacheServerConfiguration} class is a Spring {@link ImportBeanDefinitionRegistrar} that registers
* a {@link CacheServerFactoryBean} definition for the {@link org.apache.geode.cache.server.CacheServer}
* configuration meta-data defined in {@link EnableCacheServer}.
* configuration meta-data defined in {@link EnableCacheServer} annotation.
*
* @author John Blum
* @see org.apache.geode.cache.server.CacheServer
* @see org.springframework.beans.factory.BeanFactory
* @see org.springframework.beans.factory.BeanFactoryAware
* @see org.springframework.beans.factory.config.BeanDefinition
* @see org.springframework.beans.factory.config.BeanDefinitionHolder
* @see org.springframework.beans.factory.support.BeanDefinitionBuilder
* @see org.springframework.beans.factory.support.BeanDefinitionRegistry
* @see org.springframework.context.annotation.ImportBeanDefinitionRegistrar
* @see org.springframework.core.type.AnnotationMetadata
* @see org.springframework.data.gemfire.config.annotation.AddCacheServersConfiguration
* @see org.springframework.data.gemfire.config.annotation.CacheServerApplication
* @see org.springframework.data.gemfire.config.annotation.CacheServerConfiguration
* @see org.springframework.data.gemfire.config.annotation.CacheServerConfigurer
* @see org.springframework.data.gemfire.config.annotation.EnableCacheServers
* @see org.springframework.data.gemfire.config.annotation.EnableCacheServer
* @see org.springframework.data.gemfire.server.CacheServerFactoryBean
* @since 1.9.0
*/
public class AddCacheServerConfiguration implements ImportBeanDefinitionRegistrar {
public class AddCacheServerConfiguration implements BeanFactoryAware, ImportBeanDefinitionRegistrar {
private BeanFactory beanFactory;
@Autowired(required = false)
private List<CacheServerConfigurer> cacheServerConfigurers = Collections.emptyList();
/**
* {@inheritDoc}
*/
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
if (importingClassMetadata.hasAnnotation(EnableCacheServer.class.getName())) {
Map<String, Object> enableCacheServerAttributes = importingClassMetadata.getAnnotationAttributes(
EnableCacheServer.class.getName());
Map<String, Object> enableCacheServerAttributes =
importingClassMetadata.getAnnotationAttributes(EnableCacheServer.class.getName());
registerCacheServerFactoryBeanDefinition(enableCacheServerAttributes, registry);
}
@@ -69,6 +105,7 @@ public class AddCacheServerConfiguration implements ImportBeanDefinitionRegistra
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(CacheServerFactoryBean.class);
builder.addPropertyReference("cache", GemfireConstants.DEFAULT_GEMFIRE_CACHE_NAME);
builder.addPropertyValue("cacheServerConfigurers", resolveCacheServerConfigurers());
builder.addPropertyValue("autoStartup", enableCacheServerAttributes.get("autoStartup"));
builder.addPropertyValue("bindAddress", enableCacheServerAttributes.get("bindAddress"));
builder.addPropertyValue("hostNameForClients", enableCacheServerAttributes.get("hostnameForClients"));
@@ -84,6 +121,49 @@ public class AddCacheServerConfiguration implements ImportBeanDefinitionRegistra
builder.addPropertyValue("subscriptionDiskStore", enableCacheServerAttributes.get("subscriptionDiskStoreName"));
builder.addPropertyValue("subscriptionEvictionPolicy", enableCacheServerAttributes.get("subscriptionEvictionPolicy"));
BeanDefinitionReaderUtils.registerWithGeneratedName(builder.getBeanDefinition(), registry);
registerCacheServerFactoryBeanDefinition(builder.getBeanDefinition(),
(String) enableCacheServerAttributes.get("name"), registry);
}
/* (non-Javadoc) */
private List<CacheServerConfigurer> resolveCacheServerConfigurers() {
return Optional.ofNullable(this.cacheServerConfigurers)
.filter(cacheServerConfigurers -> !cacheServerConfigurers.isEmpty())
.orElseGet(() ->
Optional.of(this.beanFactory)
.filter(beanFactory -> beanFactory instanceof ListableBeanFactory)
.map(beanFactory -> {
Map<String, CacheServerConfigurer> beansOfType = ((ListableBeanFactory) beanFactory)
.getBeansOfType(CacheServerConfigurer.class, true, true);
return nullSafeMap(beansOfType).values().stream().collect(Collectors.toList());
})
.orElseGet(Collections::emptyList)
);
}
/* (non-Javadoc) */
protected void registerCacheServerFactoryBeanDefinition(AbstractBeanDefinition beanDefinition, String beanName,
BeanDefinitionRegistry registry) {
if (StringUtils.hasText(beanName)) {
BeanDefinitionReaderUtils.registerBeanDefinition(
newBeanDefinitionHolder(beanDefinition, beanName), registry);
}
else {
BeanDefinitionReaderUtils.registerWithGeneratedName(beanDefinition, registry);
}
}
/* (non-Javadoc) */
protected BeanDefinitionHolder newBeanDefinitionHolder(BeanDefinition beanDefinition, String beanName) {
return new BeanDefinitionHolder(beanDefinition, beanName);
}
/* (non-Javadoc) */
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
}
}

View File

@@ -17,8 +17,19 @@
package org.springframework.data.gemfire.config.annotation;
import java.util.Map;
import static org.springframework.data.gemfire.util.CollectionUtils.nullSafeMap;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
import org.springframework.beans.BeansException;
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.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
@@ -32,25 +43,42 @@ import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
* The {@link AddCacheServerConfiguration} class is a Spring {@link ImportBeanDefinitionRegistrar} that registers
* The {@link AddPoolConfiguration} class is a Spring {@link ImportBeanDefinitionRegistrar} that registers
* a {@link PoolFactoryBean} definition for the {@link org.apache.geode.cache.client.Pool}
* configuration meta-data defined in {@link EnablePool}.
* configuration meta-data defined in {@link EnablePool} annotations.
*
* @author John Blum
* @see org.apache.geode.cache.client.Pool
* @see org.springframework.beans.factory.BeanFactory
* @see org.springframework.beans.factory.BeanFactoryAware
* @see org.springframework.beans.factory.support.BeanDefinitionBuilder
* @see org.springframework.beans.factory.support.BeanDefinitionRegistry
* @see org.springframework.context.annotation.ImportBeanDefinitionRegistrar
* @see org.springframework.core.type.AnnotationMetadata
* @see org.springframework.data.gemfire.client.PoolFactoryBean
* @see org.springframework.data.gemfire.config.annotation.AddPoolsConfiguration
* @see org.springframework.data.gemfire.config.annotation.PoolConfigurer
* @see org.springframework.data.gemfire.config.annotation.EnablePools
* @see org.springframework.data.gemfire.config.annotation.EnablePool
* @since 1.9.0
*/
public class AddPoolConfiguration implements ImportBeanDefinitionRegistrar {
public class AddPoolConfiguration implements BeanFactoryAware, ImportBeanDefinitionRegistrar {
private BeanFactory beanFactory;
@Autowired(required = false)
private List<PoolConfigurer> poolConfigurers = Collections.emptyList();
/**
* {@inheritDoc}
*/
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
if (importingClassMetadata.hasAnnotation(EnablePool.class.getName())) {
Map<String, Object> enablePoolAttributes = importingClassMetadata.getAnnotationAttributes(
EnablePool.class.getName());
Map<String, Object> enablePoolAttributes =
importingClassMetadata.getAnnotationAttributes(EnablePool.class.getName());
registerPoolFactoryBeanDefinition(enablePoolAttributes, registry);
}
@@ -61,7 +89,7 @@ public class AddPoolConfiguration implements ImportBeanDefinitionRegistrar {
* the {@link EnablePool} annotation meta-data.
*
* @param enablePoolAttributes {@link EnablePool} annotation attributes.
* @param registry Spring {@link BeanDefinitionRegistry used to register the {@link PoolFactoryBean} definition.
* @param registry Spring {@link BeanDefinitionRegistry} used to register the {@link PoolFactoryBean} definition.
* @see org.springframework.beans.factory.support.BeanDefinitionRegistry
* @see org.springframework.data.gemfire.client.PoolFactoryBean
* @see org.springframework.data.gemfire.config.annotation.EnablePool
@@ -81,6 +109,7 @@ public class AddPoolConfiguration implements ImportBeanDefinitionRegistrar {
poolFactoryBean.addPropertyValue("minConnections", enablePoolAttributes.get("minConnections"));
poolFactoryBean.addPropertyValue("multiUserAuthentication", enablePoolAttributes.get("multiUserAuthentication"));
poolFactoryBean.addPropertyValue("pingInterval", enablePoolAttributes.get("pingInterval"));
poolFactoryBean.addPropertyValue("poolConfigurers", resolvePoolConfigurers());
poolFactoryBean.addPropertyValue("prSingleHopEnabled", enablePoolAttributes.get("prSingleHopEnabled"));
poolFactoryBean.addPropertyValue("readTimeout", enablePoolAttributes.get("readTimeout"));
poolFactoryBean.addPropertyValue("retryAttempts", enablePoolAttributes.get("retryAttempts"));
@@ -98,9 +127,27 @@ public class AddPoolConfiguration implements ImportBeanDefinitionRegistrar {
registry.registerBeanDefinition(poolName, poolFactoryBean.getBeanDefinition());
}
/* (non-Javadoc) */
private List<PoolConfigurer> resolvePoolConfigurers() {
return Optional.ofNullable(this.poolConfigurers)
.filter(poolConfigurers -> !poolConfigurers.isEmpty())
.orElseGet(() ->
Optional.of(this.beanFactory)
.filter(beanFactory -> beanFactory instanceof ListableBeanFactory)
.map(beanFactory -> {
Map<String, PoolConfigurer> beansOfType = ((ListableBeanFactory) beanFactory)
.getBeansOfType(PoolConfigurer.class, true, true);
return nullSafeMap(beansOfType).values().stream().collect(Collectors.toList());
})
.orElseGet(Collections::emptyList)
);
}
protected String getAndValidatePoolName(Map<String, Object> enablePoolAttributes) {
String poolName = (String) enablePoolAttributes.get("name");
Assert.hasText(poolName, "Pool name must be specified");
Assert.hasText(poolName, "Pool name is required");
return poolName;
}
@@ -166,4 +213,9 @@ public class AddPoolConfiguration implements ImportBeanDefinitionRegistrar {
protected ConnectionEndpoint newConnectionEndpoint(String host, Integer port) {
return new ConnectionEndpoint(host, port);
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
}
}

View File

@@ -29,6 +29,7 @@ import org.springframework.core.type.AnnotationMetadata;
* the {@link EnablePools} annotation on a GemFire client cache application class.
* @author John Blum
* @see org.apache.geode.cache.client.Pool
* @see org.springframework.data.gemfire.config.annotation.AddPoolConfiguration
* @see org.springframework.data.gemfire.config.annotation.EnablePool
* @see org.springframework.data.gemfire.config.annotation.EnablePools

View File

@@ -43,6 +43,8 @@ import org.springframework.data.gemfire.server.SubscriptionEvictionPolicy;
* @see org.springframework.context.annotation.Configuration
* @see org.springframework.context.annotation.Import
* @see org.springframework.data.gemfire.config.annotation.CacheServerConfiguration
* @see org.springframework.data.gemfire.config.annotation.EnableCacheServers
* @see org.springframework.data.gemfire.config.annotation.EnableCacheServer
* @see org.apache.geode.cache.control.ResourceManager
* @see org.apache.geode.cache.server.CacheServer
* @see org.apache.geode.cache.server.ClientSubscriptionConfig

View File

@@ -17,32 +17,47 @@
package org.springframework.data.gemfire.config.annotation;
import static org.springframework.data.gemfire.util.CollectionUtils.nullSafeMap;
import static org.springframework.data.gemfire.util.CollectionUtils.nullSafeSet;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import org.apache.geode.cache.Cache;
import org.apache.geode.cache.InterestRegistrationListener;
import org.apache.geode.cache.client.ClientCache;
import org.apache.geode.cache.server.CacheServer;
import org.apache.geode.cache.server.ClientSubscriptionConfig;
import org.apache.geode.cache.server.ServerLoadProbe;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.data.gemfire.server.CacheServerFactoryBean;
import org.springframework.data.gemfire.server.SubscriptionEvictionPolicy;
import org.springframework.data.gemfire.util.CollectionUtils;
import org.springframework.data.gemfire.util.SpringUtils;
import org.springframework.util.StringUtils;
/**
* Spring {@link Configuration} class used to configure, construct and initialize and GemFire {@link CacheServer}
* instance in a Spring application context.
* Spring {@link Configuration} class used to construct, configure and initialize a {@link CacheServer} instance
* in a Spring application context.
*
* @author John Blum
* @see org.springframework.context.annotation.Bean
* @see org.springframework.context.annotation.Configuration
* @see org.springframework.data.gemfire.config.annotation.PeerCacheConfiguration
* @see org.apache.geode.cache.Cache
* @see org.apache.geode.cache.server.CacheServer
* @see org.springframework.context.annotation.Bean
* @see org.springframework.context.annotation.Configuration
* @see org.springframework.data.gemfire.config.annotation.AddCacheServerConfiguration
* @see org.springframework.data.gemfire.config.annotation.AddCacheServersConfiguration
* @see org.springframework.data.gemfire.config.annotation.CacheServerConfigurer
* @see org.springframework.data.gemfire.config.annotation.EnableCacheServer
* @see org.springframework.data.gemfire.config.annotation.EnableCacheServers
* @see org.springframework.data.gemfire.config.annotation.PeerCacheConfiguration
* @see org.springframework.data.gemfire.server.CacheServerFactoryBean
* @since 1.9.0
*/
@Configuration
@@ -64,6 +79,9 @@ public class CacheServerConfiguration extends PeerCacheConfiguration {
private Integer socketBufferSize;
private Integer subscriptionCapacity;
@Autowired(required = false)
private List<CacheServerConfigurer> cacheServerConfigurers = Collections.emptyList();
private Long loadPollInterval;
private ServerLoadProbe serverLoadProbe;
@@ -76,11 +94,23 @@ public class CacheServerConfiguration extends PeerCacheConfiguration {
private SubscriptionEvictionPolicy subscriptionEvictionPolicy;
/**
* Bean declaration for a single, {@link CacheServer} to serve {@link ClientCache cache client} applications.
*
* @param gemfireCache peer {@link Cache} instance in which to add the {@link CacheServer}.
* @return a {@link CacheServerFactoryBean} used to construct, configure and initialize
* the {@link CacheServer} instance.
* @see org.springframework.data.gemfire.server.CacheServerFactoryBean
* @see org.apache.geode.cache.server.CacheServer
* @see org.apache.geode.cache.Cache
*/
@Bean
public CacheServerFactoryBean gemfireCacheServer(Cache gemfireCache) {
CacheServerFactoryBean gemfireCacheServer = new CacheServerFactoryBean();
gemfireCacheServer.setCache(gemfireCache);
gemfireCacheServer.setCacheServerConfigurers(resolveCacheServerConfigurers());
gemfireCacheServer.setAutoStartup(autoStartup());
gemfireCacheServer.setBindAddress(bindAddress());
gemfireCacheServer.setHostNameForClients(hostnameForClients());
@@ -101,18 +131,40 @@ public class CacheServerConfiguration extends PeerCacheConfiguration {
return gemfireCacheServer;
}
/* (non-Javadoc) */
private List<CacheServerConfigurer> resolveCacheServerConfigurers() {
return Optional.ofNullable(this.cacheServerConfigurers)
.filter(cacheServerConfigurers -> !cacheServerConfigurers.isEmpty())
.orElseGet(() ->
Optional.of(this.beanFactory())
.filter(beanFactory -> beanFactory instanceof ListableBeanFactory)
.map(beanFactory -> {
Map<String, CacheServerConfigurer> beansOfType = ((ListableBeanFactory) beanFactory)
.getBeansOfType(CacheServerConfigurer.class, true, true);
return nullSafeMap(beansOfType).values().stream().collect(Collectors.toList());
})
.orElseGet(Collections::emptyList)
);
}
/**
* Configures GemFire {@link CacheServer} specific settings.
* Configures {@link CacheServer} specific settings.
*
* @param importMetadata {@link AnnotationMetadata} containing cache server meta-data used to configure
* the GemFire {@link CacheServer}.
* @param importMetadata {@link AnnotationMetadata} containing cache server meta-data used to
* configure the {@link CacheServer}.
* @see org.springframework.core.type.AnnotationMetadata
* @see org.apache.geode.cache.server.CacheServer
*/
@Override
protected void configureOther(AnnotationMetadata importMetadata) {
protected void configureTheRest(AnnotationMetadata importMetadata) {
super.configureCache(importMetadata);
if (isCacheServerApplication(importMetadata)) {
Map<String, Object> cacheServerApplicationMetadata =
importMetadata.getAnnotationAttributes(getAnnotationTypeName());
@@ -129,8 +181,8 @@ public class CacheServerConfiguration extends PeerCacheConfiguration {
setSocketBufferSize((Integer) cacheServerApplicationMetadata.get("socketBufferSize"));
setSubscriptionCapacity((Integer) cacheServerApplicationMetadata.get("subscriptionCapacity"));
setSubscriptionDiskStoreName((String) cacheServerApplicationMetadata.get("subscriptionDiskStoreName"));
setSubscriptionEvictionPolicy((SubscriptionEvictionPolicy) cacheServerApplicationMetadata.get(
"subscriptionEvictionPolicy"));
setSubscriptionEvictionPolicy((SubscriptionEvictionPolicy)
cacheServerApplicationMetadata.get("subscriptionEvictionPolicy"));
}
}
@@ -157,7 +209,8 @@ public class CacheServerConfiguration extends PeerCacheConfiguration {
}
protected String bindAddress() {
return SpringUtils.defaultIfNull(this.bindAddress, CacheServer.DEFAULT_BIND_ADDRESS);
return Optional.ofNullable(this.bindAddress).filter(StringUtils::hasText)
.orElse(CacheServer.DEFAULT_BIND_ADDRESS);
}
/* (non-Javadoc) */
@@ -166,7 +219,8 @@ public class CacheServerConfiguration extends PeerCacheConfiguration {
}
protected String hostnameForClients() {
return SpringUtils.defaultIfNull(this.hostnameForClients, CacheServer.DEFAULT_HOSTNAME_FOR_CLIENTS);
return Optional.ofNullable(this.hostnameForClients).filter(StringUtils::hasText)
.orElse(CacheServer.DEFAULT_HOSTNAME_FOR_CLIENTS);
}
/* (non-Javadoc) */
@@ -175,7 +229,7 @@ public class CacheServerConfiguration extends PeerCacheConfiguration {
}
protected Set<InterestRegistrationListener> interestRegistrationListeners() {
return CollectionUtils.nullSafeSet(this.interestRegistrationListeners);
return nullSafeSet(this.interestRegistrationListeners);
}
/* (non-Javadoc) */
@@ -184,7 +238,7 @@ public class CacheServerConfiguration extends PeerCacheConfiguration {
}
protected Long loadPollInterval() {
return SpringUtils.defaultIfNull(this.loadPollInterval, CacheServer.DEFAULT_LOAD_POLL_INTERVAL);
return Optional.ofNullable(this.loadPollInterval).orElse(CacheServer.DEFAULT_LOAD_POLL_INTERVAL);
}
/* (non-Javadoc) */
@@ -193,7 +247,7 @@ public class CacheServerConfiguration extends PeerCacheConfiguration {
}
protected Integer maxConnections() {
return SpringUtils.defaultIfNull(this.maxConnections, CacheServer.DEFAULT_MAX_CONNECTIONS);
return Optional.ofNullable(this.maxConnections).orElse(CacheServer.DEFAULT_MAX_CONNECTIONS);
}
/* (non-Javadoc) */
@@ -202,7 +256,7 @@ public class CacheServerConfiguration extends PeerCacheConfiguration {
}
protected Integer maxMessageCount() {
return SpringUtils.defaultIfNull(this.maxMessageCount, CacheServer.DEFAULT_MAXIMUM_MESSAGE_COUNT);
return Optional.ofNullable(this.maxMessageCount).orElse(CacheServer.DEFAULT_MAXIMUM_MESSAGE_COUNT);
}
/* (non-Javadoc) */
@@ -211,7 +265,7 @@ public class CacheServerConfiguration extends PeerCacheConfiguration {
}
protected Integer maxThreads() {
return SpringUtils.defaultIfNull(this.maxThreads, CacheServer.DEFAULT_MAX_THREADS);
return Optional.ofNullable(this.maxThreads).orElse(CacheServer.DEFAULT_MAX_THREADS);
}
/* (non-Javadoc) */
@@ -220,7 +274,7 @@ public class CacheServerConfiguration extends PeerCacheConfiguration {
}
protected Integer maxTimeBetweenPings() {
return SpringUtils.defaultIfNull(this.maxTimeBetweenPings, CacheServer.DEFAULT_MAXIMUM_TIME_BETWEEN_PINGS);
return Optional.ofNullable(this.maxTimeBetweenPings).orElse(CacheServer.DEFAULT_MAXIMUM_TIME_BETWEEN_PINGS);
}
/* (non-Javadoc) */
@@ -229,7 +283,7 @@ public class CacheServerConfiguration extends PeerCacheConfiguration {
}
protected Integer messageTimeToLive() {
return SpringUtils.defaultIfNull(this.messageTimeToLive, CacheServer.DEFAULT_MESSAGE_TIME_TO_LIVE);
return Optional.ofNullable(this.messageTimeToLive).orElse(CacheServer.DEFAULT_MESSAGE_TIME_TO_LIVE);
}
/* (non-Javadoc) */
@@ -238,7 +292,7 @@ public class CacheServerConfiguration extends PeerCacheConfiguration {
}
protected Integer port() {
return SpringUtils.defaultIfNull(this.port, CacheServer.DEFAULT_PORT);
return Optional.ofNullable(this.port).orElse(CacheServer.DEFAULT_PORT);
}
/* (non-Javadoc) */
@@ -247,7 +301,7 @@ public class CacheServerConfiguration extends PeerCacheConfiguration {
}
protected ServerLoadProbe serverLoadProbe() {
return SpringUtils.defaultIfNull(this.serverLoadProbe, CacheServer.DEFAULT_LOAD_PROBE);
return Optional.ofNullable(this.serverLoadProbe).orElse(CacheServer.DEFAULT_LOAD_PROBE);
}
/* (non-Javadoc) */
@@ -256,7 +310,7 @@ public class CacheServerConfiguration extends PeerCacheConfiguration {
}
protected Integer socketBufferSize() {
return SpringUtils.defaultIfNull(this.socketBufferSize, CacheServer.DEFAULT_SOCKET_BUFFER_SIZE);
return Optional.ofNullable(this.socketBufferSize).orElse(CacheServer.DEFAULT_SOCKET_BUFFER_SIZE);
}
/* (non-Javadoc) */
@@ -265,7 +319,7 @@ public class CacheServerConfiguration extends PeerCacheConfiguration {
}
protected Integer subscriptionCapacity() {
return SpringUtils.defaultIfNull(this.subscriptionCapacity, ClientSubscriptionConfig.DEFAULT_CAPACITY);
return Optional.ofNullable(this.subscriptionCapacity).orElse(ClientSubscriptionConfig.DEFAULT_CAPACITY);
}
/* (non-Javadoc) */
@@ -283,7 +337,7 @@ public class CacheServerConfiguration extends PeerCacheConfiguration {
}
protected SubscriptionEvictionPolicy subscriptionEvictionPolicy() {
return SpringUtils.defaultIfNull(this.subscriptionEvictionPolicy, SubscriptionEvictionPolicy.DEFAULT);
return Optional.ofNullable(this.subscriptionEvictionPolicy).orElse(SubscriptionEvictionPolicy.DEFAULT);
}
@Override

View File

@@ -0,0 +1,47 @@
/*
* Copyright 2016 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 org.apache.geode.cache.server.CacheServer;
import org.springframework.data.gemfire.server.CacheServerFactoryBean;
/**
* The {@link CacheServerConfigurer} interface defines a contract for implementations to customize the configuration
* of a {@link CacheServerFactoryBean} used to construct, configure and initialize an instance of a {@link CacheServer}.
*
* @author John Blum
* @see org.apache.geode.cache.server.CacheServer
* @see org.springframework.data.gemfire.config.annotation.CacheServerApplication
* @see org.springframework.data.gemfire.config.annotation.EnableCacheServers
* @see org.springframework.data.gemfire.config.annotation.EnableCacheServer
* @see org.springframework.data.gemfire.server.CacheServerFactoryBean
* @since 1.9.0
*/
public interface CacheServerConfigurer {
/**
* Configuration callback method providing a reference to a {@link CacheServerFactoryBean} used to construct,
* configure and initialize an instance of {@link CacheServer}.
*
* @param beanName name of {@link CacheServer} bean declared in the Spring application context.
* @param bean reference to the {@link CacheServerFactoryBean}.
* @see org.springframework.data.gemfire.server.CacheServerFactoryBean
*/
void configure(String beanName, CacheServerFactoryBean bean);
}

View File

@@ -37,11 +37,11 @@ import org.springframework.data.gemfire.support.GemfireBeanFactoryLocator;
* a GemFire cache client (i.e. {@link org.apache.geode.cache.client.ClientCache}).
*
* @author John Blum
* @see org.apache.geode.cache.client.PoolFactory
* @see org.apache.geode.cache.control.ResourceManager
* @see org.springframework.context.annotation.Configuration
* @see org.springframework.context.annotation.Import
* @see org.springframework.data.gemfire.config.annotation.ClientCacheConfiguration
* @see org.apache.geode.cache.client.PoolFactory
* @see org.apache.geode.cache.control.ResourceManager
* @since 1.9.0
*/
@Target(ElementType.TYPE)
@@ -195,7 +195,7 @@ public @interface ClientCacheApplication {
int retryAttempts() default PoolFactory.DEFAULT_RETRY_ATTEMPTS;
/**
* Configures the group that all servers this pool connects to must belong to.
* Configures the group that all servers in which this pool connects to must belong to.
*
* @see org.apache.geode.cache.client.PoolFactory#DEFAULT_SERVER_GROUP
*/

View File

@@ -17,9 +17,19 @@
package org.springframework.data.gemfire.config.annotation;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
import static org.springframework.data.gemfire.util.CollectionUtils.nullSafeMap;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;
import org.apache.geode.cache.client.ClientCache;
import org.apache.geode.cache.client.Pool;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.context.annotation.Bean;
@@ -33,14 +43,24 @@ import org.springframework.data.gemfire.support.ConnectionEndpoint;
import org.springframework.data.gemfire.support.ConnectionEndpointList;
/**
* Spring {@link Configuration} class used to configure, construct and initialize
* a GemFire {@link org.apache.geode.cache.client.ClientCache} instance in a Spring application context.
* Spring {@link Configuration} class used to construct, configure and initialize
* a {@link org.apache.geode.cache.client.ClientCache} instance in a Spring application context.
*
* @author John Blum
* @see org.apache.geode.cache.client.ClientCache
* @see org.apache.geode.cache.client.Pool
* @see org.springframework.beans.factory.config.BeanDefinition
* @see org.springframework.beans.factory.support.BeanDefinitionBuilder
* @see org.springframework.context.annotation.Bean
* @see org.springframework.context.annotation.Configuration
* @see org.springframework.core.type.AnnotationMetadata
* @see org.springframework.data.gemfire.CacheFactoryBean
* @see org.springframework.data.gemfire.client.ClientCacheFactoryBean
* @see org.springframework.data.gemfire.config.annotation.AbstractCacheConfiguration
* @see org.apache.geode.cache.client.ClientCache
* @see org.springframework.data.gemfire.config.annotation.ClientCacheConfigurer
* @see org.springframework.data.gemfire.config.support.ClientRegionPoolBeanFactoryPostProcessor
* @see org.springframework.data.gemfire.support.ConnectionEndpoint
* @see org.springframework.data.gemfire.support.ConnectionEndpointList
* @since 1.0.0
*/
@Configuration
@@ -78,16 +98,30 @@ public class ClientCacheConfiguration extends AbstractCacheConfiguration {
private Iterable<ConnectionEndpoint> locators;
private Iterable<ConnectionEndpoint> servers;
@Autowired(required = false)
private List<ClientCacheConfigurer> clientCacheConfigurers = Collections.emptyList();
private Long idleTimeout;
private Long pingInterval;
private String durableClientId;
private String serverGroup;
/**
* Bean declaration for a single, peer {@link ClientCache} instance.
*
* @return a new instance of a peer {@link ClientCache}.
* @see org.springframework.data.gemfire.client.ClientCacheFactoryBean
* @see org.apache.geode.cache.client.ClientCache
* @see org.apache.geode.cache.GemFireCache
* @see #constructCacheFactoryBean()
*/
@Bean
public ClientCacheFactoryBean gemfireCache() {
ClientCacheFactoryBean gemfireCache = constructCacheFactoryBean();
gemfireCache.setClientCacheConfigurers(resolveClientCacheConfigurers());
gemfireCache.setDurableClientId(durableClientId());
gemfireCache.setDurableClientTimeout(durableClientTimeout());
gemfireCache.setFreeConnectionTimeout(freeConnectionTimeout());
@@ -116,8 +150,30 @@ public class ClientCacheConfiguration extends AbstractCacheConfiguration {
return gemfireCache;
}
/* (non-Javadoc) */
private List<ClientCacheConfigurer> resolveClientCacheConfigurers() {
return Optional.ofNullable(this.clientCacheConfigurers)
.filter(clientCacheConfigurers -> !clientCacheConfigurers.isEmpty())
.orElseGet(() ->
Optional.of(this.beanFactory())
.filter(beanFactory -> beanFactory instanceof ListableBeanFactory)
.map(beanFactory -> {
Map<String, ClientCacheConfigurer> beansOfType = ((ListableBeanFactory) beanFactory)
.getBeansOfType(ClientCacheConfigurer.class, true, true);
return nullSafeMap(beansOfType).values().stream().collect(Collectors.toList());
})
.orElseGet(Collections::emptyList)
);
}
/**
* {@inheritDoc}
* Constructs a new instance of {@link ClientCacheFactoryBean} used to create a peer {@link ClientCache}.
*
* @param <T> {@link Class} sub-type of {@link CacheFactoryBean}.
* @return a new instance of {@link ClientCacheFactoryBean}.
* @see org.springframework.data.gemfire.client.ClientCacheFactoryBean
*/
@Override
@SuppressWarnings("unchecked")
@@ -126,16 +182,27 @@ public class ClientCacheConfiguration extends AbstractCacheConfiguration {
}
/**
* {@inheritDoc}
* Configures Spring container infrastructure components and beans used by Spring Data GemFire
* to enable Pivotal GemFire or Apache Geode to function properly inside a Spring context.
*
* This overridden method configures and registers additional Spring components and bean applicable to
* {@link ClientCache ClientCaches}.
*
* @param importMetadata {@link AnnotationMetadata} containing annotation meta-data
* for the Spring Data GemFire cache application class.
* @see org.springframework.core.type.AnnotationMetadata
*/
@Override
protected void configureInfrastructure(AnnotationMetadata importMetadata) {
super.configureInfrastructure(importMetadata);
registerClientRegionPoolBeanFactoryPostProcessor(importMetadata);
}
/* (non-Javadoc) */
protected void registerClientRegionPoolBeanFactoryPostProcessor(AnnotationMetadata importMetadata) {
private void registerClientRegionPoolBeanFactoryPostProcessor(AnnotationMetadata importMetadata) {
if (CLIENT_REGION_POOL_BEAN_FACTORY_POST_PROCESSOR_REGISTERED.compareAndSet(false, true)) {
register(BeanDefinitionBuilder.rootBeanDefinition(ClientRegionPoolBeanFactoryPostProcessor.class)
.setRole(BeanDefinition.ROLE_INFRASTRUCTURE).getBeanDefinition());
@@ -143,17 +210,20 @@ public class ClientCacheConfiguration extends AbstractCacheConfiguration {
}
/**
* Configures GemFire {@link org.apache.geode.cache.client.ClientCache} specific settings.
* Configures {@link ClientCache} specific settings.
*
* @param importMetadata {@link AnnotationMetadata} containing client cache meta-data used to configure
* the GemFire {@link org.apache.geode.cache.client.ClientCache}.
* @param importMetadata {@link AnnotationMetadata} containing client cache meta-data used to
* configure the {@link ClientCache}.
* @see org.springframework.core.type.AnnotationMetadata
* @see #configureLocatorsAndServers(Map)
*/
@Override
protected void configureCache(AnnotationMetadata importMetadata) {
super.configureCache(importMetadata);
if (isClientCacheApplication(importMetadata)) {
Map<String, Object> clientCacheApplicationAttributes =
importMetadata.getAnnotationAttributes(getAnnotationTypeName());
@@ -185,16 +255,16 @@ public class ClientCacheConfiguration extends AbstractCacheConfiguration {
}
/**
* Uses the list of GemFire Locator and Server connection endpoint definitions and meta-data to configure
* the GemFire client {@link org.apache.geode.cache.client.Pool} used to communicate with the servers
* in the GemFire cluster.
* Uses the list of Pivotal GemFire/Apache Geode Locator and Server connection endpoint definitions and meta-data
* to configure the client {@link Pool} used to communicate with the servers in the cluster.
*
* @param clientCacheApplicationAttributes {@link ClientCacheApplication} annotation containing
* {@link org.apache.geode.cache.client.Pool} Locator/Server connection endpoint meta-data.
* @param clientCacheApplicationAttributes {@link ClientCacheApplication} annotation containing {@link Pool}
* Locator/Server connection endpoint meta-data.
* @see org.springframework.data.gemfire.config.annotation.ClientCacheApplication
* @see java.util.Map
*/
protected void configureLocatorsAndServers(Map<String, Object> clientCacheApplicationAttributes) {
private void configureLocatorsAndServers(Map<String, Object> clientCacheApplicationAttributes) {
ConnectionEndpointList poolLocators = new ConnectionEndpointList();
AnnotationAttributes[] locators = (AnnotationAttributes[]) clientCacheApplicationAttributes.get("locators");

View File

@@ -0,0 +1,45 @@
/*
* Copyright 2016 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 org.apache.geode.cache.client.ClientCache;
import org.springframework.data.gemfire.client.ClientCacheFactoryBean;
/**
* The {@link ClientCacheConfigurer} interface defines a contract for implementations to customize the configuration
* of a {@link ClientCacheFactoryBean} used to construct, configure and initialize an instance of a {@link ClientCache}.
*
* @author John Blum
* @see org.apache.geode.cache.client.ClientCache
* @see org.springframework.data.gemfire.client.ClientCacheFactoryBean
* @see org.springframework.data.gemfire.config.annotation.ClientCacheApplication
* @since 1.9.0
*/
public interface ClientCacheConfigurer {
/**
* Configuration callback method providing a reference to a {@link ClientCacheFactoryBean} used to construct,
* configure and initialize an instance of {@link ClientCache}.
*
* @param beanName name of {@link ClientCache} bean declared in the Spring application context.
* @param bean reference to the {@link ClientCacheFactoryBean}.
* @see org.springframework.data.gemfire.CacheFactoryBean
*/
void configure(String beanName, ClientCacheFactoryBean bean);
}

View File

@@ -17,6 +17,19 @@
package org.springframework.data.gemfire.config.annotation;
import static org.springframework.data.gemfire.util.CollectionUtils.nullSafeMap;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
import org.springframework.beans.BeansException;
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;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
@@ -40,17 +53,25 @@ import org.springframework.data.gemfire.util.ArrayUtils;
* @see org.springframework.data.gemfire.DiskStoreFactoryBean
* @see org.springframework.data.gemfire.config.annotation.EnableDiskStore
* @see org.springframework.data.gemfire.config.annotation.EnableDiskStores
* @see org.springframework.data.gemfire.config.annotation.DiskStoreConfigurer
* @see org.apache.geode.cache.DiskStore
* @since 1.9.0
*/
public class DiskStoreConfiguration implements ImportBeanDefinitionRegistrar {
public class DiskStoreConfiguration implements BeanFactoryAware, ImportBeanDefinitionRegistrar {
private BeanFactory beanFactory;
@Autowired(required = false)
private List<DiskStoreConfigurer> diskStoreConfigurers = Collections.emptyList();
/**
* @inheritDoc
*/
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
if (importingClassMetadata.hasAnnotation(EnableDiskStore.class.getName())) {
AnnotationAttributes enableDiskStoreAttributes = AnnotationAttributes.fromMap(
importingClassMetadata.getAnnotationAttributes(EnableDiskStore.class.getName()));
@@ -71,6 +92,8 @@ public class DiskStoreConfiguration implements ImportBeanDefinitionRegistrar {
diskStoreFactoryBeanBuilder.addPropertyReference("cache", GemfireConstants.DEFAULT_GEMFIRE_CACHE_NAME);
diskStoreFactoryBeanBuilder.addPropertyValue("diskStoreConfigurers", resolveDiskStoreConfigurers());
setPropertyValueIfNotDefault(diskStoreFactoryBeanBuilder, "allowForceCompaction",
enableDiskStoreAttributes.getBoolean("allowForceCompaction"), false);
@@ -103,6 +126,24 @@ public class DiskStoreConfiguration implements ImportBeanDefinitionRegistrar {
registry.registerBeanDefinition(diskStoreName, diskStoreFactoryBeanBuilder.getBeanDefinition());
}
/* (non-Javadoc) */
private List<DiskStoreConfigurer> resolveDiskStoreConfigurers() {
return Optional.ofNullable(this.diskStoreConfigurers)
.filter(diskStoreConfigurers -> !diskStoreConfigurers.isEmpty())
.orElseGet(() ->
Optional.of(this.beanFactory)
.filter(beanFactory -> beanFactory instanceof ListableBeanFactory)
.map(beanFactory -> {
Map<String, DiskStoreConfigurer> beansOfType = ((ListableBeanFactory) beanFactory)
.getBeansOfType(DiskStoreConfigurer.class, true, true);
return nullSafeMap(beansOfType).values().stream().collect(Collectors.toList());
})
.orElseGet(Collections::emptyList)
);
}
/* (non-Javadoc) */
protected BeanDefinitionBuilder parseDiskStoreDiskDirectories(AnnotationMetadata importingClassMetadata,
AnnotationAttributes enableDiskStoreAttributes, BeanDefinitionBuilder diskStoreBeanFactoryBuilder) {
@@ -131,9 +172,14 @@ public class DiskStoreConfiguration implements ImportBeanDefinitionRegistrar {
/* (non-Javadoc) */
private <T> BeanDefinitionBuilder setPropertyValueIfNotDefault(BeanDefinitionBuilder beanDefinitionBuilder,
String propertyName, T value, T defaultValue) {
String propertyName, T value, T defaultValue) {
return (value != null && !value.equals(defaultValue) ?
beanDefinitionBuilder.addPropertyValue(propertyName, value) : beanDefinitionBuilder);
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
}
}

View File

@@ -0,0 +1,45 @@
/*
* Copyright 2017 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 org.apache.geode.cache.DiskStore;
import org.springframework.data.gemfire.DiskStoreFactoryBean;
/**
* The {@link DiskStoreConfigurer} interface defines a contract for implementations to customize the configuration
* of a {@link DiskStoreFactoryBean} used to construct, configure and initialize a {@link DiskStore}.
*
* @author John Blum
* @see org.apache.geode.cache.DiskStore
* @see org.springframework.data.gemfire.DiskStoreFactoryBean
* @see org.springframework.data.gemfire.config.annotation.EnableDiskStore
* @see org.springframework.data.gemfire.config.annotation.EnableDiskStores
* @since 1.1.0
*/
public interface DiskStoreConfigurer {
/**
* Configuration callback method providing a reference to a {@link DiskStoreFactoryBean} used to construct,
* configure and initialize an instance of {@link DiskStore}.
*
* @param beanName name of the {@link DiskStore} bean declared in the Spring application context.
* @param bean reference to the {@link DiskStoreFactoryBean}.
* @see org.springframework.data.gemfire.DiskStoreFactoryBean
*/
void configure(String beanName, DiskStoreFactoryBean bean);
}

View File

@@ -41,8 +41,10 @@ import org.springframework.data.gemfire.server.SubscriptionEvictionPolicy;
* the {@link EnableCacheServers} annotation.
* @author John Blum
* @see org.springframework.data.gemfire.config.annotation.AddCacheServerConfiguration
* @see org.apache.geode.cache.server.CacheServer
* @see org.springframework.data.gemfire.config.annotation.AddCacheServerConfiguration
* @see org.springframework.data.gemfire.config.annotation.CacheServerConfigurer
* @see org.springframework.data.gemfire.config.annotation.EnableCacheServers
* @since 1.9.0
*/
@Target(ElementType.TYPE)
@@ -117,6 +119,13 @@ public @interface EnableCacheServer {
*/
int messageTimeToLive() default CacheServer.DEFAULT_MESSAGE_TIME_TO_LIVE;
/**
* Configures the name of the Spring bean defined in the Spring application context.
*
* Defaults to empty.
*/
String name() default "";
/**
* Configures the port on which this cache server listens for clients.
*

View File

@@ -24,14 +24,17 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.apache.geode.cache.server.CacheServer;
import org.springframework.context.annotation.Import;
/**
* The {@link EnableCacheServers} annotation enables 1 or more GemFire {@link org.apache.geode.cache.server.CacheServer CacheServers}
* to be defined and used in a GemFire peer cache application configured with Spring (Data GemFire).
* The {@link EnableCacheServers} annotation enables 1 or more {@link CacheServer CacheServers}
* to be defined and used in a peer cache application configured with Spring (Data GemFire/Geode).
*
* @author John Blum
* @see org.apache.geode.cache.server.CacheServer
* @see org.springframework.data.gemfire.config.annotation.AddCacheServersConfiguration
* @see org.springframework.data.gemfire.config.annotation.CacheServerConfigurer
* @see org.springframework.data.gemfire.config.annotation.EnableCacheServer
* @since 1.9.0
*/

View File

@@ -34,12 +34,13 @@ import org.springframework.core.annotation.AliasFor;
* {@link org.apache.geode.cache.Region Regions}
*
* @author John Blum
* @see org.apache.geode.cache.DiskStore
* @see org.apache.geode.cache.Region
* @see org.springframework.context.annotation.Import
* @see org.springframework.core.annotation.AliasFor
* @see org.springframework.data.gemfire.config.annotation.DiskStoreConfiguration
* @see org.springframework.data.gemfire.config.annotation.DiskStoreConfigurer
* @see org.springframework.data.gemfire.config.annotation.EnableDiskStores
* @see org.apache.geode.cache.DiskStore
* @see org.apache.geode.cache.Region
* @since 1.9.0
*/
@Target(ElementType.TYPE)

View File

@@ -33,11 +33,12 @@ import org.springframework.context.annotation.Import;
* {@link org.apache.geode.cache.Region Regions}
*
* @author John Blum
* @see org.springframework.context.annotation.Import
* @see org.springframework.data.gemfire.config.annotation.DiskStoresConfiguration
* @see org.springframework.data.gemfire.config.annotation.EnableDiskStore
* @see org.apache.geode.cache.DiskStore
* @see org.apache.geode.cache.Region
* @see org.springframework.context.annotation.Import
* @see org.springframework.data.gemfire.config.annotation.DiskStoresConfiguration
* @see org.springframework.data.gemfire.config.annotation.DiskStoreConfigurer
* @see org.springframework.data.gemfire.config.annotation.EnableDiskStore
* @since 1.9.0
*/
@Target(ElementType.TYPE)

View File

@@ -26,21 +26,26 @@ import java.lang.annotation.Target;
import org.apache.geode.cache.Region;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.core.annotation.AliasFor;
/**
* The {@link EnableEntityDefinedRegions} annotation marks a Spring {@link org.springframework.context.annotation.Configuration @Configuration}
* The {@link EnableEntityDefinedRegions} annotation marks a Spring {@link Configuration @Configuration} application
* annotated class to enable the creation of the GemFire/Geode {@link Region Regions} based on
* the application domain model object entities.
* the application persistent entities.
*
* @author John Blum
* @see org.apache.geode.cache.Region
* @see org.springframework.context.annotation.ComponentScan
* @see org.springframework.context.annotation.ComponentScan.Filter
* @see org.springframework.context.annotation.Import
* @see org.springframework.core.annotation.AliasFor
* @see org.springframework.data.gemfire.RegionFactoryBean
* @see org.springframework.data.gemfire.client.ClientRegionFactoryBean
* @see org.springframework.data.gemfire.config.annotation.EntityDefinedRegionsConfiguration
* @see org.apache.geode.cache.Region
* @see org.springframework.data.gemfire.config.annotation.IndexConfiguration
* @see org.springframework.data.gemfire.config.annotation.support.GemFireCacheTypeAwareRegionFactoryBean
* @since 1.9.0
*/
@Target(ElementType.TYPE)
@@ -62,7 +67,10 @@ public @interface EnableEntityDefinedRegions {
/**
* Base packages to scan for {@link org.springframework.data.gemfire.mapping.annotation.Region @Region} annotated
* application persistent entities. {@link #value()} is an alias for this attribute.
* application persistent entities.
*
* The {@link #value()} attribute is an alias for this attribute.
*
* Use {@link #basePackageClasses()} for a type-safe alternative to String-based package names.
*
* @return a {@link String} array specifying the packages to search for application persistent entities.
@@ -72,10 +80,13 @@ public @interface EnableEntityDefinedRegions {
String[] basePackages() default {};
/**
* Type-safe alternative to {@link #basePackages()} for specifying the packages to scan for
* Type-safe alternative to the {@link #basePackages()} attribute for specifying the packages to scan for
* {@link org.springframework.data.gemfire.mapping.annotation.Region @Region} annotated application persistent entities.
* The package of each class specified will be scanned. Consider creating a special no-op marker class or interface
* in each package that serves no other purpose than being referenced by this attribute.
*
* The package of each class specified will be scanned.
*
* Consider creating a special no-op marker class or interface in each package that serves no other purpose
* than being referenced by this attribute.
*
* @return an array of {@link Class classes} used to determine the packages to scan
* for application persistent entities.
@@ -91,12 +102,13 @@ public @interface EnableEntityDefinedRegions {
ComponentScan.Filter[] excludeFilters() default {};
/**
* Specifies which types are eligible for component scanning. Further narrows the set of candidate components
* from everything in {@link #basePackages()} to everything in the base packages that matches the given filter
* or filters.
* Specifies which types are eligible for component scanning.
*
* @return an array {@link org.springframework.context.annotation.ComponentScan.Filter} of Filters used to
* specify application persistent entities to be included during the component scan.
* Further narrows the set of candidate components from everything in {@link #basePackages()}
* or {@link #basePackageClasses()} to everything in the base packages that matches the given filter or filters.
*
* @return an array {@link ComponentScan.Filter} of Filters used to specify application persistent entities
* to be included during the component scan.
*/
ComponentScan.Filter[] includeFilters() default {};

View File

@@ -26,6 +26,7 @@ import java.lang.annotation.Target;
import org.apache.geode.cache.EvictionAttributes;
import org.apache.geode.cache.Region;
import org.apache.geode.cache.util.ObjectSizer;
import org.springframework.context.annotation.Import;
import org.springframework.data.gemfire.eviction.EvictionActionType;
import org.springframework.data.gemfire.eviction.EvictionPolicyType;
@@ -72,7 +73,7 @@ public @interface EnableEviction {
*
* Defaults to {@link EvictionActionType#LOCAL_DESTROY}.
*
* @see org.springframework.data.gemfire.EvictionActionType
* @see org.springframework.data.gemfire.eviction.EvictionActionType
*/
EvictionActionType action() default EvictionActionType.LOCAL_DESTROY;
@@ -84,8 +85,8 @@ public @interface EnableEviction {
int maximum() default EvictionAttributes.DEFAULT_ENTRIES_MAXIMUM;
/**
* Name of a Spring bean of type {@link ObjectSizer} defined in the Spring context used
* to size {@link Region} entry values.
* Name of a Spring bean of type {@link ObjectSizer} defined in the Spring application context
* used to size {@link Region} entry values.
*
* Defaults to empty.
*
@@ -94,14 +95,14 @@ public @interface EnableEviction {
String objectSizerName() default "";
/**
* Names of {@link Region Regions} for which this Eviction policy applies.
* Names of all the {@link Region Regions} in which this Eviction policy will be applied.
*
* Defaults to empty.
*/
String[] regionNames() default {};
/**
* Eviction alorithm used during Eviction.
* Eviction algorithm used during Eviction.
*
* Defaults to {@link EvictionPolicyType#ENTRY_COUNT}.
*

View File

@@ -133,6 +133,7 @@ public @interface EnableExpiration {
* @see <a href="http://geode.incubator.apache.org/docs/guide/developing/expiration/chapter_overview.html">Geode Expiration</a>
*/
enum ExpirationType {
IDLE_TIMEOUT("TTI"),
TIME_TO_LIVE("TTL");

View File

@@ -24,16 +24,23 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.apache.geode.cache.lucene.LuceneIndex;
import org.apache.geode.cache.query.Index;
import org.springframework.context.annotation.Configuration;
/**
* The {@link EnableIndexing} annotation marks a Spring {@link org.springframework.context.annotation.Configuration @Configuration}
* annotated application class to enable the creation of GemFire/Geode Indexes based on application persistent entity
* field/property annotations, such as the {@link @Id}, {@link @Indexed} and {@link @LuceneIndex} annotations.
* The {@link EnableIndexing} annotation marks a Spring {@link Configuration @Configuration} annotated application class
* to enable the creation of GemFire/Geode {@link Index Indexes} and {@link LuceneIndex LuceneIndexes} based on
* application persistent entity field/property annotations, such as the {@link @Id}, {@link @Indexed}
* and {@link @LuceneIndex} annotations.
*
* @author John Blum
* @see org.springframework.data.gemfire.config.annotation.IndexConfiguration
* @see org.apache.geode.cache.lucene.LuceneIndex
* @see org.apache.geode.cache.query.Index
* @see org.springframework.data.gemfire.IndexFactoryBean
* @see org.springframework.data.gemfire.config.annotation.IndexConfiguration
* @see org.springframework.data.gemfire.config.annotation.IndexConfigurer
* @see org.springframework.data.gemfire.search.lucene.LuceneIndexFactoryBean
* @since 1.9.0
*/
@Target(ElementType.TYPE)
@@ -46,9 +53,12 @@ public @interface EnableIndexing {
/**
* Determines whether all GemFire/Geode {@link Index Indexes} will be defined before created.
* If set to {@literal true}, then all {@link Index Indexes} are defined first and the created
* in a single, bulk operation, thereby improving index creation efficiency.
* in a single, bulk operation, thereby improving {@link Index} creation process efficiency.
*
* Defaults to false.
* Only applies to OQL-based {@link Index Indexes}. {@link LuceneIndex LuceneIndexes} are managed differently
* by GemFire/Geode.
*
* Defaults to {@literal false}.
*/
boolean define() default false;

View File

@@ -40,9 +40,11 @@ import org.springframework.data.gemfire.GemfireUtils;
* annotation.
*
* @author John Blum
* @see org.springframework.data.gemfire.config.annotation.AddPoolConfiguration
* @see org.apache.geode.cache.client.Pool
* @see org.apache.geode.cache.client.PoolFactory
* @see org.springframework.data.gemfire.config.annotation.AddPoolConfiguration
* @see org.springframework.data.gemfire.config.annotation.EnablePools
* @see org.springframework.data.gemfire.config.annotation.PoolConfigurer
* @since 1.9.0
*/
@Target(ElementType.TYPE)

View File

@@ -33,6 +33,7 @@ import org.springframework.context.annotation.Import;
* @author John Blum
* @see org.springframework.data.gemfire.config.annotation.AddPoolsConfiguration
* @see org.springframework.data.gemfire.config.annotation.EnablePool
* @see org.springframework.data.gemfire.config.annotation.PoolConfigurer
* @since 1.9.0
*/
@Target(ElementType.TYPE)

View File

@@ -20,15 +20,20 @@ package org.springframework.data.gemfire.config.annotation;
import static java.util.Arrays.stream;
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.RuntimeExceptionFactory.newIllegalStateException;
import java.lang.annotation.Annotation;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import org.apache.geode.cache.Region;
import org.apache.geode.cache.client.ClientRegionShortcut;
@@ -37,6 +42,8 @@ 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;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
@@ -82,7 +89,9 @@ import org.springframework.util.StringUtils;
* based on the application persistent entity classes.
*
* @author John Blum
* @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
@@ -106,7 +115,6 @@ import org.springframework.util.StringUtils;
* @see org.springframework.data.gemfire.mapping.annotation.PartitionRegion
* @see org.springframework.data.gemfire.mapping.annotation.ReplicateRegion
* @see org.springframework.data.gemfire.mapping.annotation.Region
* @see org.apache.geode.cache.Region
* @since 1.9.0
*/
public class EntityDefinedRegionsConfiguration
@@ -133,6 +141,9 @@ public class EntityDefinedRegionsConfiguration
private GemfireMappingContext mappingContext;
@Autowired(required = false)
private List<RegionConfigurer> regionConfigurers = Collections.emptyList();
/**
* Returns the {@link Annotation} {@link Class type} that configures and creates {@link Region Regions}
* for application persistent entities.
@@ -230,9 +241,9 @@ public class EntityDefinedRegionsConfiguration
/* (non-Javadoc) */
protected GemfirePersistentEntity<?> getPersistentEntity(Class<?> persistentEntityType) {
return resolveMappingContext().getPersistentEntity(persistentEntityType).orElseThrow(
() -> new IllegalStateException(String.format("PersistentEntity for type [%s] not found",
persistentEntityType)));
() -> newIllegalStateException("PersistentEntity for type [%s] not found", persistentEntityType));
}
/* (non-Javadoc) */
@@ -254,19 +265,21 @@ public class EntityDefinedRegionsConfiguration
*/
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
if (isAnnotationPresent(importingClassMetadata)) {
AnnotationAttributes enableEntityDefinedRegionsAttributes = getAnnotationAttributes(importingClassMetadata);
boolean strict = enableEntityDefinedRegionsAttributes.getBoolean("strict");
for (Class<?> persistentEntityClass : newGemFireComponentClassTypeScanner(
importingClassMetadata, enableEntityDefinedRegionsAttributes).scan()) {
newGemFireComponentClassTypeScanner(importingClassMetadata, enableEntityDefinedRegionsAttributes).scan()
.forEach(persistentEntityClass -> {
GemfirePersistentEntity persistentEntity = getPersistentEntity(persistentEntityClass);
GemfirePersistentEntity persistentEntity = getPersistentEntity(persistentEntityClass);
registerRegionBeanDefinition(persistentEntity, strict, registry);
postProcess(importingClassMetadata, registry, persistentEntity);
}
registerRegionBeanDefinition(persistentEntity, strict, registry);
postProcess(importingClassMetadata, registry, persistentEntity);
});
}
}
@@ -274,8 +287,8 @@ public class EntityDefinedRegionsConfiguration
protected GemFireComponentClassTypeScanner newGemFireComponentClassTypeScanner(
AnnotationMetadata importingClassMetadata, AnnotationAttributes enableEntityDefinedRegionsAttributes) {
Set<String> resolvedBasePackages = resolveBasePackages(importingClassMetadata,
enableEntityDefinedRegionsAttributes);
Set<String> resolvedBasePackages =
resolveBasePackages(importingClassMetadata, enableEntityDefinedRegionsAttributes);
return GemFireComponentClassTypeScanner.from(resolvedBasePackages).with(resolveBeanClassLoader())
.withExcludes(resolveExcludes(enableEntityDefinedRegionsAttributes))
@@ -323,6 +336,7 @@ public class EntityDefinedRegionsConfiguration
/* (non-Javadoc) */
private Iterable<TypeFilter> parseFilters(AnnotationAttributes[] componentScanFilterAttributes) {
Set<TypeFilter> typeFilters = new HashSet<>();
stream(nullSafeArray(componentScanFilterAttributes, AnnotationAttributes.class))
@@ -334,43 +348,45 @@ public class EntityDefinedRegionsConfiguration
/* (non-Javadoc) */
@SuppressWarnings("unchecked")
private Iterable<TypeFilter> typeFiltersFor(AnnotationAttributes filterAttributes) {
Set<TypeFilter> typeFilters = new HashSet<>();
FilterType filterType = filterAttributes.getEnum("type");
for (Class<?> filterClass : nullSafeArray(filterAttributes.getClassArray("value"), Class.class)) {
switch (filterType) {
case ANNOTATION:
Assert.isAssignable(Annotation.class, filterClass,
String.format("@ComponentScan.Filter class [%s] must be an Annotation", filterClass));
typeFilters.add(new AnnotationTypeFilter((Class<Annotation>) filterClass));
break;
case ASSIGNABLE_TYPE:
typeFilters.add(new AssignableTypeFilter(filterClass));
break;
case CUSTOM:
Assert.isAssignable(TypeFilter.class, filterClass,
String.format("@ComponentScan.Filter class [%s] must be a TypeFilter", filterClass));
typeFilters.add(BeanUtils.instantiateClass(filterClass, TypeFilter.class));
break;
default:
throw new IllegalArgumentException(String.format(
"Illegal filter type [%s] when 'value' or 'classes' are specified", filterType));
}
for (String pattern : nullSafeGetPatterns(filterAttributes)) {
stream(nullSafeArray(filterAttributes.getClassArray("value"), Class.class))
.forEach(filterClass -> {
switch (filterType) {
case ASPECTJ:
typeFilters.add(new AspectJTypeFilter(pattern, resolveBeanClassLoader()));
case ANNOTATION:
Assert.isAssignable(Annotation.class, filterClass,
String.format("@ComponentScan.Filter class [%s] must be an Annotation", filterClass));
typeFilters.add(new AnnotationTypeFilter((Class<Annotation>) filterClass));
break;
case REGEX:
typeFilters.add(new RegexPatternTypeFilter(Pattern.compile(pattern)));
case ASSIGNABLE_TYPE:
typeFilters.add(new AssignableTypeFilter(filterClass));
break;
case CUSTOM:
Assert.isAssignable(TypeFilter.class, filterClass,
String.format("@ComponentScan.Filter class [%s] must be a TypeFilter", filterClass));
typeFilters.add(BeanUtils.instantiateClass(filterClass, TypeFilter.class));
break;
default:
throw new IllegalArgumentException(String.format(
"Illegal filter type [%s] when 'patterns' are specified", filterType));
throw newIllegalArgumentException(
"Illegal filter type [%s] when 'value' or 'classes' are specified", filterType);
}
}
}
for (String pattern : nullSafeGetPatterns(filterAttributes)) {
switch (filterType) {
case ASPECTJ:
typeFilters.add(new AspectJTypeFilter(pattern, resolveBeanClassLoader()));
break;
case REGEX:
typeFilters.add(new RegexPatternTypeFilter(Pattern.compile(pattern)));
break;
default:
throw newIllegalArgumentException(
"Illegal filter type [%s] when 'patterns' are specified", filterType);
}
}
});
return typeFilters;
}
@@ -394,6 +410,7 @@ public class EntityDefinedRegionsConfiguration
/* (non-Javadoc) */
@SuppressWarnings("unchecked")
protected Iterable<TypeFilter> regionAnnotatedPersistentEntityTypeFilters() {
Set<TypeFilter> regionAnnotatedPersistentEntityTypeFilters = new HashSet<>();
org.springframework.data.gemfire.mapping.annotation.Region.REGION_ANNOTATION_TYPES.forEach(
@@ -409,6 +426,7 @@ public class EntityDefinedRegionsConfiguration
BeanDefinitionBuilder regionFactoryBeanBuilder =
BeanDefinitionBuilder.genericBeanDefinition(resolveRegionFactoryBeanClass(persistentEntity))
.addPropertyReference("cache", GemfireConstants.DEFAULT_GEMFIRE_CACHE_NAME)
.addPropertyValue("regionConfigurers", resolveRegionConfigurers())
.addPropertyValue("close", false);
setRegionAttributes(persistentEntity, regionFactoryBeanBuilder, strict);
@@ -417,6 +435,24 @@ public class EntityDefinedRegionsConfiguration
regionFactoryBeanBuilder.getBeanDefinition());
}
/* (non-Javadoc) */
private List<RegionConfigurer> resolveRegionConfigurers() {
return Optional.ofNullable(this.regionConfigurers)
.filter(regionConfigurers -> !regionConfigurers.isEmpty())
.orElseGet(() ->
Optional.ofNullable(this.beanFactory)
.filter(beanFactory -> beanFactory instanceof ListableBeanFactory)
.map(beanFactory -> {
Map<String, RegionConfigurer> beansOfType = ((ListableBeanFactory) beanFactory)
.getBeansOfType(RegionConfigurer.class, true, true);
return nullSafeMap(beansOfType).values().stream().collect(Collectors.toList());
})
.orElseGet(Collections::emptyList)
);
}
/* (non-Javadoc) */
@SuppressWarnings("unchecked")
protected Class<? extends RegionLookupFactoryBean> resolveRegionFactoryBeanClass(
@@ -492,9 +528,10 @@ public class EntityDefinedRegionsConfiguration
/* (non-Javadoc) */
@SuppressWarnings("unchecked")
protected Class<?> resolveIdType(GemfirePersistentEntity persistentEntity) {
return (Class<?>) persistentEntity.getIdProperty()
.map(idProperty -> ((GemfirePersistentProperty) idProperty).getActualType())
.orElse(Object.class);
.orElse(Object.class);
}
/* (non-Javadoc) */
@@ -570,6 +607,7 @@ public class EntityDefinedRegionsConfiguration
"fixedPartitions", PartitionRegion.FixedPartition.class), PartitionRegion.FixedPartition.class);
if (!ObjectUtils.isEmpty(fixedPartitions)) {
ManagedList<BeanDefinition> fixedPartitionAttributesFactoryBeans =
new ManagedList<BeanDefinition>(fixedPartitions.length);

View File

@@ -18,17 +18,24 @@
package org.springframework.data.gemfire.config.annotation;
import static org.springframework.data.gemfire.config.annotation.EnableEviction.EvictionPolicy;
import static org.springframework.data.gemfire.util.ArrayUtils.nullSafeArray;
import static org.springframework.data.gemfire.util.CollectionUtils.nullSafeIterable;
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.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.function.Supplier;
import org.apache.geode.cache.EvictionAttributes;
import org.apache.geode.cache.Region;
import org.apache.geode.cache.util.ObjectSizer;
import org.apache.shiro.util.Assert;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.ApplicationContext;
@@ -44,14 +51,11 @@ import org.springframework.data.gemfire.client.ClientRegionFactoryBean;
import org.springframework.data.gemfire.eviction.EvictionActionType;
import org.springframework.data.gemfire.eviction.EvictionAttributesFactoryBean;
import org.springframework.data.gemfire.eviction.EvictionPolicyType;
import org.springframework.data.gemfire.util.ArrayUtils;
import org.springframework.data.gemfire.util.CollectionUtils;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
* The {@link EvictionConfiguration} class is a Spring {@link Configuration @Configuration} annotated class to enable
* Eviction policy configuration on GemFire/Geode {@link Region Regions}.
* Eviction policy configuration on cache {@link Region Regions}.
*
* @author John Blum
* @see org.springframework.beans.factory.config.BeanPostProcessor
@@ -76,19 +80,6 @@ public class EvictionConfiguration implements ApplicationContextAware, ImportAwa
private EvictionPolicyConfigurer evictionPolicyConfigurer;
/**
* Determines whether the Spring bean is an instance of {@link RegionFactoryBean}
* or {@link ClientRegionFactoryBean}.
*
* @param bean Spring bean to evaluate.
* @return a boolean value indicating whether the Spring bean is an instance of {@link RegionFactoryBean}.
* @see org.springframework.data.gemfire.RegionFactoryBean
* @see org.springframework.data.gemfire.client.ClientRegionFactoryBean
*/
protected static boolean isRegionFactoryBean(Object bean) {
return (bean instanceof RegionFactoryBean || bean instanceof ClientRegionFactoryBean);
}
/**
* Returns the {@link Annotation} {@link Class type} that enables and configures Eviction.
*
@@ -124,34 +115,52 @@ public class EvictionConfiguration implements ApplicationContextAware, ImportAwa
}
/**
* @inheritDoc
* Sets a reference to the Spring {@link ApplicationContext}.
*
* @param applicationContext Spring {@link ApplicationContext} in use.
* @throws BeansException if an error occurs while storing a reference to the Spring {@link ApplicationContext}.
* @see org.springframework.context.ApplicationContextAware#setApplicationContext(ApplicationContext)
* @see org.springframework.context.ApplicationContext
*/
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
/**
* Determines whether the Spring bean is an instance of {@link RegionFactoryBean}
* or {@link ClientRegionFactoryBean}.
*
* @param bean Spring bean to evaluate.
* @return a boolean value indicating whether the Spring bean is an instance of {@link RegionFactoryBean}
* or the {@link ClientRegionFactoryBean}.
* @see org.springframework.data.gemfire.RegionFactoryBean
* @see org.springframework.data.gemfire.client.ClientRegionFactoryBean
*/
protected static boolean isRegionFactoryBean(Object bean) {
return (bean instanceof RegionFactoryBean || bean instanceof ClientRegionFactoryBean);
}
/**
* @inheritDoc
*/
@Override
public void setImportMetadata(AnnotationMetadata importMetadata) {
if (importMetadata.hasAnnotation(getAnnotationTypeName())) {
Map<String, Object> enableEvictionAttributes =
importMetadata.getAnnotationAttributes(getAnnotationTypeName());
AnnotationAttributes[] policies = (AnnotationAttributes[]) enableEvictionAttributes.get("policies");
for (AnnotationAttributes evictionPolicyAttributes
: ArrayUtils.nullSafeArray(policies, AnnotationAttributes.class)) {
for (AnnotationAttributes evictionPolicyAttributes : nullSafeArray(policies, AnnotationAttributes.class)) {
this.evictionPolicyConfigurer = ComposableEvictionPolicyConfigurer.compose(
this.evictionPolicyConfigurer, EvictionPolicyMetaData.from(evictionPolicyAttributes,
this.applicationContext));
}
this.evictionPolicyConfigurer = (this.evictionPolicyConfigurer != null ? this.evictionPolicyConfigurer
: EvictionPolicyMetaData.fromDefaults());
this.evictionPolicyConfigurer = Optional.ofNullable(this.evictionPolicyConfigurer)
.orElseGet(EvictionPolicyMetaData::fromDefaults);
}
}
@@ -163,16 +172,16 @@ public class EvictionConfiguration implements ApplicationContextAware, ImportAwa
* @see org.springframework.data.gemfire.config.annotation.EvictionConfiguration.EvictionPolicyConfigurer
*/
protected EvictionPolicyConfigurer getEvictionPolicyConfigurer() {
Assert.state(this.evictionPolicyConfigurer != null,
"EvictionPolicyConfigurer was not properly configured and initialized");
return this.evictionPolicyConfigurer;
return Optional.ofNullable(this.evictionPolicyConfigurer).orElseThrow(() ->
newIllegalStateException("EvictionPolicyConfigurer was not properly configured and initialized"));
}
@Bean
@SuppressWarnings("unused")
public BeanPostProcessor evictionBeanPostProcessor() {
return new BeanPostProcessor() {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return (isRegionFactoryBean(bean) ? getEvictionPolicyConfigurer().configure(bean) : bean);
@@ -228,7 +237,7 @@ public class EvictionConfiguration implements ApplicationContextAware, ImportAwa
*/
@SuppressWarnings("unused")
protected static EvictionPolicyConfigurer compose(EvictionPolicyConfigurer[] array) {
return compose(Arrays.asList(ArrayUtils.nullSafeArray(array, EvictionPolicyConfigurer.class)));
return compose(Arrays.asList(nullSafeArray(array, EvictionPolicyConfigurer.class)));
}
/**
@@ -242,9 +251,10 @@ public class EvictionConfiguration implements ApplicationContextAware, ImportAwa
* @see #compose(EvictionPolicyConfigurer, EvictionPolicyConfigurer)
*/
protected static EvictionPolicyConfigurer compose(Iterable<EvictionPolicyConfigurer> iterable) {
EvictionPolicyConfigurer current = null;
for (EvictionPolicyConfigurer evictionPolicyConfigurer : CollectionUtils.nullSafeIterable(iterable)) {
for (EvictionPolicyConfigurer evictionPolicyConfigurer : nullSafeIterable(iterable)) {
current = compose(current, evictionPolicyConfigurer);
}
@@ -291,26 +301,28 @@ public class EvictionConfiguration implements ApplicationContextAware, ImportAwa
private final EvictionAttributes evictionAttributes;
private final Set<String> regionNames = new HashSet<String>();
private final Set<String> regionNames = new HashSet<>();
protected static EvictionPolicyMetaData from(AnnotationAttributes evictionPolicyAttributes,
ApplicationContext applicationContext) {
return from((Integer) evictionPolicyAttributes.get("maximum"),
evictionPolicyAttributes.<EvictionPolicyType>getEnum("type"),
evictionPolicyAttributes.<EvictionActionType>getEnum("action"),
resolveObjectSizer(evictionPolicyAttributes.getString("objectSizerName"), applicationContext),
evictionPolicyAttributes.getStringArray("regionNames"));
Assert.isAssignable(EvictionPolicy.class, evictionPolicyAttributes.annotationType());
return from(evictionPolicyAttributes.getEnum("type"),
(Integer) evictionPolicyAttributes.get("maximum"),
evictionPolicyAttributes.getEnum("action"),
resolveObjectSizer(evictionPolicyAttributes.getString("objectSizerName"), applicationContext),
evictionPolicyAttributes.getStringArray("regionNames"));
}
protected static EvictionPolicyMetaData from(EvictionPolicy evictionPolicy,
ApplicationContext applicationContext) {
return from(evictionPolicy.maximum(), evictionPolicy.type(), evictionPolicy.action(),
return from(evictionPolicy.type(), evictionPolicy.maximum(), evictionPolicy.action(),
resolveObjectSizer(evictionPolicy.objectSizerName(), applicationContext), evictionPolicy.regionNames());
}
protected static EvictionPolicyMetaData from(int maximum, EvictionPolicyType type, EvictionActionType action,
protected static EvictionPolicyMetaData from(EvictionPolicyType type, int maximum, EvictionActionType action,
ObjectSizer objectSizer, String... regionNames) {
EvictionAttributesFactoryBean factoryBean = new EvictionAttributesFactoryBean();
@@ -329,6 +341,7 @@ public class EvictionConfiguration implements ApplicationContextAware, ImportAwa
}
protected static ObjectSizer resolveObjectSizer(String objectSizerName, ApplicationContext applicationContext) {
boolean resolvable = StringUtils.hasText(objectSizerName)
&& applicationContext.containsBean(objectSizerName);
@@ -374,10 +387,11 @@ public class EvictionConfiguration implements ApplicationContextAware, ImportAwa
* @see org.apache.geode.cache.EvictionAttributes
*/
protected EvictionPolicyMetaData(EvictionAttributes evictionAttributes, String[] regionNames) {
Assert.notNull(evictionAttributes, "EvictionAttributes must not be null");
this.evictionAttributes = evictionAttributes;
Collections.addAll(this.regionNames, ArrayUtils.nullSafeArray(regionNames, String.class));
this.evictionAttributes = Optional.ofNullable(evictionAttributes)
.orElseThrow(() -> newIllegalArgumentException("EvictionAttributes are required"));
Collections.addAll(this.regionNames, nullSafeArray(regionNames, String.class));
}
/**
@@ -390,10 +404,8 @@ public class EvictionConfiguration implements ApplicationContextAware, ImportAwa
* @see org.apache.geode.cache.EvictionAttributes
*/
protected EvictionAttributes getEvictionAttributes() {
Assert.state(this.evictionAttributes != null,
"EvictionAttributes was not properly configured and initialized");
return this.evictionAttributes;
return Optional.ofNullable(this.evictionAttributes).orElseThrow(() ->
newIllegalStateException("EvictionAttributes was not properly configured and initialized"));
}
/**
@@ -403,10 +415,10 @@ public class EvictionConfiguration implements ApplicationContextAware, ImportAwa
* @return a boolean value indicating whether the {@link Object} is accepted for Eviction policy configuration.
* @see #isRegionFactoryBean(Object)
* @see #resolveRegionName(Object)
* @see #accepts(String)
* @see #accepts(Supplier)
*/
protected boolean accepts(Object regionFactoryBean) {
return (isRegionFactoryBean(regionFactoryBean) && accepts(resolveRegionName(regionFactoryBean)));
return (isRegionFactoryBean(regionFactoryBean) && accepts(() -> resolveRegionName(regionFactoryBean)));
}
/**
@@ -415,8 +427,8 @@ public class EvictionConfiguration implements ApplicationContextAware, ImportAwa
* @param regionName name of the {@link Region} targeted for Eviction policy configuration.
* @return a boolean value if the named {@link Region} is accepted for Eviction policy configuration.
*/
protected boolean accepts(String regionName) {
return (this.regionNames.isEmpty() || this.regionNames.contains(regionName));
protected boolean accepts(Supplier<String> regionName) {
return (this.regionNames.isEmpty() || this.regionNames.contains(regionName.get()));
}
/**
@@ -444,6 +456,7 @@ public class EvictionConfiguration implements ApplicationContextAware, ImportAwa
* @see #getEvictionAttributes()
*/
protected Object setEvictionAttributes(Object regionFactoryBean) {
if (regionFactoryBean instanceof RegionFactoryBean) {
((RegionFactoryBean) regionFactoryBean).setEvictionAttributes(getEvictionAttributes());
}

View File

@@ -19,11 +19,15 @@ package org.springframework.data.gemfire.config.annotation;
import static org.springframework.data.gemfire.config.annotation.EnableExpiration.ExpirationPolicy;
import static org.springframework.data.gemfire.config.annotation.EnableExpiration.ExpirationType;
import static org.springframework.data.gemfire.util.ArrayUtils.nullSafeArray;
import static org.springframework.data.gemfire.util.CollectionUtils.nullSafeIterable;
import static org.springframework.data.gemfire.util.RuntimeExceptionFactory.newIllegalStateException;
import java.lang.annotation.Annotation;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import org.apache.geode.cache.AttributesMutator;
@@ -39,9 +43,7 @@ import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.data.gemfire.expiration.AnnotationBasedExpiration;
import org.springframework.data.gemfire.expiration.ExpirationActionType;
import org.springframework.data.gemfire.util.ArrayUtils;
import org.springframework.data.gemfire.util.CollectionUtils;
import org.springframework.data.gemfire.util.SpringUtils;
import org.springframework.util.Assert;
/**
@@ -70,7 +72,7 @@ public class ExpirationConfiguration implements ImportAware {
/**
* Returns the {@link Annotation} {@link Class type} that enables and configures Expiration.
*
* @return {@link Annotation} {@link Class type} that enables and configures Expiration.
* @return the {@link Annotation} {@link Class type} that enables and configures Expiration.
* @see java.lang.annotation.Annotation
* @see java.lang.Class
*/
@@ -106,22 +108,22 @@ public class ExpirationConfiguration implements ImportAware {
*/
@Override
public void setImportMetadata(AnnotationMetadata importMetadata) {
if (importMetadata.hasAnnotation(getAnnotationTypeName())) {
Map<String, Object> enableExpirationAttributes =
importMetadata.getAnnotationAttributes(getAnnotationTypeName());
AnnotationAttributes[] policies =
(AnnotationAttributes[]) enableExpirationAttributes.get("policies");
AnnotationAttributes[] policies = (AnnotationAttributes[]) enableExpirationAttributes.get("policies");
for (AnnotationAttributes expirationPolicyAttributes :
ArrayUtils.nullSafeArray(policies, AnnotationAttributes.class)) {
nullSafeArray(policies, AnnotationAttributes.class)) {
this.expirationPolicyConfigurer = ComposableExpirationPolicyConfigurer.compose(
this.expirationPolicyConfigurer, ExpirationPolicyMetaData.from(expirationPolicyAttributes));
}
this.expirationPolicyConfigurer = (this.expirationPolicyConfigurer != null ? this.expirationPolicyConfigurer
: ExpirationPolicyMetaData.fromDefaults());
this.expirationPolicyConfigurer = Optional.ofNullable(this.expirationPolicyConfigurer)
.orElseGet(ExpirationPolicyMetaData::fromDefaults);
}
}
@@ -137,16 +139,16 @@ public class ExpirationConfiguration implements ImportAware {
}
protected ExpirationPolicyConfigurer getExpirationPolicyConfigurer() {
Assert.state(this.expirationPolicyConfigurer != null,
"ExpirationPolicyConfigurer was not properly configured and initialized");
return expirationPolicyConfigurer;
return Optional.ofNullable(this.expirationPolicyConfigurer).orElseThrow(() ->
newIllegalStateException("ExpirationPolicyConfigurer was not properly configured and initialized"));
}
@Bean
@SuppressWarnings("unused")
public BeanPostProcessor expirationBeanPostProcessor() {
return new BeanPostProcessor() {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
@@ -158,7 +160,6 @@ public class ExpirationConfiguration implements ImportAware {
return (isRegion(bean) ? getExpirationPolicyConfigurer().configure((Region<Object, Object>) bean)
: bean);
}
};
}
@@ -170,13 +171,11 @@ public class ExpirationConfiguration implements ImportAware {
/**
* Configures the expiration policy for the given {@link Region}.
*
* @param <K> {@link Class type} of the {@link Region} keys.
* @param <V> {@link Class type} of the {@link Region} values.
* @param region {@link Region} who's expiration policy will be configured.
* @return the given {@link Region}.
* @param region {@link Region} object who's expiration policy will be configured.
* @return the given {@link Region} object.
* @see org.apache.geode.cache.Region
*/
<K, V> Region<K, V> configure(Region<K, V> region);
Object configure(Object region);
}
@@ -202,7 +201,7 @@ public class ExpirationConfiguration implements ImportAware {
* @see #compose(Iterable)
*/
protected static ExpirationPolicyConfigurer compose(ExpirationPolicyConfigurer[] array) {
return compose(Arrays.asList(ArrayUtils.nullSafeArray(array, ExpirationPolicyConfigurer.class)));
return compose(Arrays.asList(nullSafeArray(array, ExpirationPolicyConfigurer.class)));
}
/**
@@ -214,9 +213,10 @@ public class ExpirationConfiguration implements ImportAware {
* @see #compose(ExpirationPolicyConfigurer, ExpirationPolicyConfigurer)
*/
protected static ExpirationPolicyConfigurer compose(Iterable<ExpirationPolicyConfigurer> iterable) {
ExpirationPolicyConfigurer current = null;
for (ExpirationPolicyConfigurer configurer : CollectionUtils.nullSafeIterable(iterable)) {
for (ExpirationPolicyConfigurer configurer : nullSafeIterable(iterable)) {
current = compose(current, configurer);
}
@@ -255,7 +255,7 @@ public class ExpirationConfiguration implements ImportAware {
* @inheritDoc
*/
@Override
public <K, V> Region<K, V> configure(Region<K, V> region) {
public Object configure(Object region) {
return this.two.configure(this.one.configure(region));
}
}
@@ -276,9 +276,9 @@ public class ExpirationConfiguration implements ImportAware {
private final ExpirationAttributes defaultExpirationAttributes;
private final Set<String> regionNames = new HashSet<String>();
private final Set<String> regionNames = new HashSet<>();
private final Set<ExpirationType> types = new HashSet<ExpirationType>();
private final Set<ExpirationType> types = new HashSet<>();
/**
* Factory method to construct an instance of {@link ExpirationPolicyMetaData} initialized with
@@ -294,12 +294,13 @@ public class ExpirationConfiguration implements ImportAware {
* @see org.springframework.core.annotation.AnnotationAttributes
*/
protected static ExpirationPolicyMetaData from(AnnotationAttributes expirationPolicyAttributes) {
Assert.isAssignable(ExpirationPolicy.class, expirationPolicyAttributes.annotationType());
return newExpirationPolicyMetaData((Integer) expirationPolicyAttributes.get("timeout"),
expirationPolicyAttributes.<ExpirationActionType>getEnum("action"),
expirationPolicyAttributes.getStringArray("regionNames"),
(ExpirationType[]) expirationPolicyAttributes.get("types"));
expirationPolicyAttributes.getEnum("action"),
expirationPolicyAttributes.getStringArray("regionNames"),
(ExpirationType[]) expirationPolicyAttributes.get("types"));
}
/**
@@ -378,8 +379,8 @@ public class ExpirationConfiguration implements ImportAware {
String[] regionNames, ExpirationType[] types) {
return new ExpirationPolicyMetaData(newExpirationAttributes(timeout, action),
CollectionUtils.asSet(ArrayUtils.nullSafeArray(regionNames, String.class)),
CollectionUtils.asSet(ArrayUtils.nullSafeArray(types, ExpirationType.class)));
CollectionUtils.asSet(nullSafeArray(regionNames, String.class)),
CollectionUtils.asSet(nullSafeArray(types, ExpirationType.class)));
}
/**
@@ -391,7 +392,7 @@ public class ExpirationConfiguration implements ImportAware {
* @see org.springframework.data.gemfire.ExpirationActionType
*/
protected static ExpirationActionType resolveAction(ExpirationActionType action) {
return SpringUtils.defaultIfNull(action, DEFAULT_ACTION);
return Optional.ofNullable(action).orElse(DEFAULT_ACTION);
}
/**
@@ -421,6 +422,7 @@ public class ExpirationConfiguration implements ImportAware {
* @see #resolveAction(ExpirationActionType)
* @see #resolveTimeout(int)
*/
@SuppressWarnings("unused")
protected ExpirationPolicyMetaData(int timeout, ExpirationActionType action, Set<String> regionNames,
Set<ExpirationType> types) {
@@ -442,7 +444,7 @@ public class ExpirationConfiguration implements ImportAware {
protected ExpirationPolicyMetaData(ExpirationAttributes expirationAttributes, Set<String> regionNames,
Set<ExpirationType> types) {
Assert.notEmpty(types, "At least one ExpirationPolicy type [TTI, TTL] must be specified");
Assert.notEmpty(types, "At least one ExpirationPolicy type [TTI, TTL] is required");
this.defaultExpirationAttributes = expirationAttributes;
this.regionNames.addAll(CollectionUtils.nullSafeSet(regionNames));
@@ -457,8 +459,8 @@ public class ExpirationConfiguration implements ImportAware {
* @see org.apache.geode.cache.Region
* @see #accepts(String)
*/
protected boolean accepts(Region region) {
return (region != null && accepts(region.getName()));
protected boolean accepts(Object region) {
return (region instanceof Region && accepts(((Region) region).getName()));
}
/**
@@ -496,24 +498,27 @@ public class ExpirationConfiguration implements ImportAware {
* @inheritDoc
*/
@Override
public <K, V> Region<K, V> configure(Region<K, V> region) {
if (accepts(region)) {
AttributesMutator<K, V> regionAttributesMutator = region.getAttributesMutator();
public Object configure(Object regionObject) {
if (accepts(regionObject)) {
Region<?, ?> region = (Region<?, ?>) regionObject;
AttributesMutator<?, ?> regionAttributesMutator = region.getAttributesMutator();
ExpirationAttributes defaultExpirationAttributes = defaultExpirationAttributes();
if (isIdleTimeout()) {
regionAttributesMutator.setCustomEntryIdleTimeout(
AnnotationBasedExpiration.<K, V>forIdleTimeout(defaultExpirationAttributes));
AnnotationBasedExpiration.forIdleTimeout(defaultExpirationAttributes));
}
if (isTimeToLive()) {
regionAttributesMutator.setCustomEntryTimeToLive(
AnnotationBasedExpiration.<K, V>forTimeToLive(defaultExpirationAttributes));
AnnotationBasedExpiration.forTimeToLive(defaultExpirationAttributes));
}
}
return region;
return regionObject;
}
/**

View File

@@ -17,12 +17,20 @@
package org.springframework.data.gemfire.config.annotation;
import static org.springframework.data.gemfire.util.CollectionUtils.nullSafeMap;
import java.lang.annotation.Annotation;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
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.ListableBeanFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.core.annotation.AnnotationAttributes;
@@ -48,23 +56,29 @@ import org.springframework.util.StringUtils;
*
* @author John Blum
* @see java.lang.annotation.Annotation
* @see org.apache.geode.cache.Region
* @see org.apache.geode.cache.lucene.LuceneIndex
* @see org.apache.geode.cache.query.Index
* @see org.springframework.beans.factory.support.BeanDefinitionBuilder
* @see org.springframework.beans.factory.support.BeanDefinitionRegistry
* @see org.springframework.core.type.AnnotationMetadata
* @see org.springframework.data.annotation.Id
* @see org.springframework.data.gemfire.IndexFactoryBean
* @see org.springframework.data.gemfire.IndexType
* @see org.springframework.data.gemfire.search.lucene.LuceneIndexFactoryBean
* @see org.springframework.data.gemfire.config.annotation.EnableIndexing
* @see org.springframework.data.gemfire.config.annotation.EntityDefinedRegionsConfiguration
* @see org.springframework.data.gemfire.mapping.GemfirePersistentEntity
* @see org.springframework.data.gemfire.mapping.GemfirePersistentProperty
* @see org.springframework.data.gemfire.mapping.annotation.Indexed
* @see org.apache.geode.cache.Region
* @see org.apache.geode.cache.lucene.LuceneIndex
* @see org.apache.geode.cache.query.Index
* @see org.springframework.data.gemfire.mapping.annotation.LuceneIndexed
* @see org.springframework.data.gemfire.search.lucene.LuceneIndexFactoryBean
* @since 1.9.0
*/
public class IndexConfiguration extends EntityDefinedRegionsConfiguration {
@Autowired(required = false)
private List<IndexConfigurer> indexConfigurers = Collections.emptyList();
/**
* Returns the {@link Annotation} {@link Class type} that configures and creates {@link Region} Indexes
* from application persistent entity properties.
@@ -117,6 +131,7 @@ public class IndexConfiguration extends EntityDefinedRegionsConfiguration {
super.postProcess(importingClassMetadata, registry, persistentEntity);
if (isAnnotationPresent(importingClassMetadata, getEnableIndexingAnnotationTypeName())) {
AnnotationAttributes enableIndexingAttributes =
getAnnotationAttributes(importingClassMetadata, getEnableIndexingAnnotationTypeName());
@@ -162,6 +177,7 @@ public class IndexConfiguration extends EntityDefinedRegionsConfiguration {
IndexType indexType, Annotation indexAnnotation, BeanDefinitionRegistry registry) {
Optional.ofNullable(indexAnnotation).ifPresent(localIndexAnnotation -> {
AnnotationAttributes indexedAttributes = getAnnotationAttributes(localIndexAnnotation);
BeanDefinitionBuilder indexFactoryBeanBuilder =
@@ -179,6 +195,8 @@ public class IndexConfiguration extends EntityDefinedRegionsConfiguration {
indexFactoryBeanBuilder.addPropertyValue("from",
resolveFrom(persistentEntity, persistentProperty, indexedAttributes));
indexFactoryBeanBuilder.addPropertyValue("indexConfigurers", resolveIndexConfigurers());
indexFactoryBeanBuilder.addPropertyValue("name", indexName);
indexFactoryBeanBuilder.addPropertyValue("override",
@@ -215,6 +233,7 @@ public class IndexConfiguration extends EntityDefinedRegionsConfiguration {
Annotation luceneIndexAnnotation, BeanDefinitionRegistry registry) {
Optional.ofNullable(luceneIndexAnnotation).ifPresent(localLuceneIndexAnnotation -> {
AnnotationAttributes luceneIndexAttributes =
AnnotationAttributes.fromMap(AnnotationUtils.getAnnotationAttributes(localLuceneIndexAnnotation));
@@ -230,6 +249,8 @@ public class IndexConfiguration extends EntityDefinedRegionsConfiguration {
luceneIndexFactoryBeanBuilder.addPropertyValue("fields", persistentProperty.getName());
luceneIndexFactoryBeanBuilder.addPropertyValue("indexConfigurers", resolveIndexConfigurers());
luceneIndexFactoryBeanBuilder.addPropertyValue("indexName", indexName);
luceneIndexFactoryBeanBuilder.addPropertyValue("regionPath", persistentEntity.getRegionName());
@@ -238,6 +259,24 @@ public class IndexConfiguration extends EntityDefinedRegionsConfiguration {
});
}
/* (non-Javadoc) */
private List<IndexConfigurer> resolveIndexConfigurers() {
return Optional.ofNullable(this.indexConfigurers)
.filter(indexConfigurers -> !indexConfigurers.isEmpty())
.orElseGet(() ->
Optional.of(getBeanFactory())
.filter(beanFactory -> beanFactory instanceof ListableBeanFactory)
.map(beanFactory -> {
Map<String, IndexConfigurer> beansOfType = ((ListableBeanFactory) beanFactory)
.getBeansOfType(IndexConfigurer.class, true, true);
return nullSafeMap(beansOfType).values().stream().collect(Collectors.toList());
})
.orElseGet(Collections::emptyList)
);
}
/* (non-Javadoc) */
private boolean resolveDefine(AnnotationAttributes enableIndexingAttributes) {
return (enableIndexingAttributes.containsKey("define")

View File

@@ -0,0 +1,62 @@
/*
* Copyright 2017 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 org.apache.geode.cache.lucene.LuceneIndex;
import org.apache.geode.cache.query.Index;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.gemfire.IndexFactoryBean;
import org.springframework.data.gemfire.search.lucene.LuceneIndexFactoryBean;
/**
* The {@link IndexConfigurer} interface defines a contract for implementations to customize the configuration
* of Entity-defined {@link Index Indexes} when a user annotates her Spring application {@link Configuration}
* class with {@link EnableIndexing}.
*
* @author John Blum
* @see org.apache.geode.cache.lucene.LuceneIndex
* @see org.apache.geode.cache.query.Index
* @see org.springframework.data.gemfire.IndexFactoryBean
* @see org.springframework.data.gemfire.config.annotation.EnableIndexing
* @see org.springframework.data.gemfire.config.annotation.IndexConfiguration
* @see org.springframework.data.gemfire.search.lucene.LuceneIndexFactoryBean
* @since 1.1.0
*/
public interface IndexConfigurer {
/**
* Configuration callback method providing a reference to a {@link IndexFactoryBean} used to construct, configure
* and initialize an instance of a peer {@link Index}.
*
* @param beanName name of {@link Index} bean declared in the Spring application context.
* @param bean reference to the {@link IndexFactoryBean}.
* @see org.springframework.data.gemfire.IndexFactoryBean
*/
default void configure(String beanName, IndexFactoryBean bean) {
}
/**
* Configuration callback method providing a reference to a {@link LuceneIndexFactoryBean} used to construct,
* configure and initialize an instance of a peer {@link LuceneIndex}.
*
* @param beanName name of {@link LuceneIndex} bean declared in the Spring application context.
* @param bean reference to the {@link LuceneIndexFactoryBean}.
* @see org.springframework.data.gemfire.search.lucene.LuceneIndexFactoryBean
*/
default void configure(String beanName, LuceneIndexFactoryBean bean) {
}
}

View File

@@ -50,7 +50,7 @@ public class LocatorConfiguration extends EmbeddedServiceConfigurationSupport {
String host = resolveHost((String) annotationAttributes.get("host"));
int port = resolvePort((Integer) annotationAttributes.get("port"), DEFAULT_LOCATOR_PORT);
return new PropertiesBuilder()
return PropertiesBuilder.create()
.setProperty(START_LOCATOR_GEMFIRE_SYSTEM_PROPERTY_NAME, String.format("%s[%d]", host, port))
.build();
}

View File

@@ -44,7 +44,7 @@ public class ManagerConfiguration extends EmbeddedServiceConfigurationSupport {
@Override
protected Properties toGemFireProperties(Map<String, Object> annotationAttributes) {
PropertiesBuilder gemfireProperties = new PropertiesBuilder();
PropertiesBuilder gemfireProperties = PropertiesBuilder.create();
gemfireProperties.setProperty("jmx-manager", Boolean.TRUE.toString());
gemfireProperties.setProperty("jmx-manager-access-file", annotationAttributes.get("accessFile"));

View File

@@ -44,8 +44,9 @@ public class MemcachedServerConfiguration extends EmbeddedServiceConfigurationSu
@Override
protected Properties toGemFireProperties(Map<String, Object> annotationAttributes) {
return new PropertiesBuilder()
.setProperty("memcached-port", resolvePort((Integer) annotationAttributes.get("port"), DEFAULT_MEMCACHED_SERVER_PORT))
return PropertiesBuilder.create()
.setProperty("memcached-port", resolvePort((Integer) annotationAttributes.get("port"),
DEFAULT_MEMCACHED_SERVER_PORT))
.setProperty("memcached-protocol", annotationAttributes.get("protocol"))
.build();
}

View File

@@ -17,22 +17,31 @@
package org.springframework.data.gemfire.config.annotation;
import java.util.Map;
import static org.springframework.data.gemfire.util.CollectionUtils.nullSafeMap;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
import org.apache.geode.cache.Cache;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.data.gemfire.CacheFactoryBean;
/**
* Spring {@link Configuration} class used to configure, construct and initialize
* a GemFire peer {@link org.apache.geode.cache.Cache} instance in a Spring application context.
* Spring {@link Configuration} class used to construct, configure and initialize a peer {@link Cache} instance
* in a Spring application context.
*
* @author John Blum
* @see org.apache.geode.cache.Cache
* @see org.springframework.context.annotation.Bean
* @see org.springframework.context.annotation.Configuration
* @see org.springframework.data.gemfire.config.annotation.AbstractCacheConfiguration
* @see org.apache.geode.cache.Cache
* @since 1.9.0
*/
@Configuration
@@ -52,14 +61,28 @@ public class PeerCacheConfiguration extends AbstractCacheConfiguration {
private Integer messageSyncInterval;
private Integer searchTimeout;
@Autowired(required = false)
private List<PeerCacheConfigurer> peerCacheConfigurers = Collections.emptyList();
/**
* Bean declaration for a single, peer {@link Cache} instance.
*
* @return a new instance of a peer {@link Cache}.
* @see org.springframework.data.gemfire.CacheFactoryBean
* @see org.apache.geode.cache.GemFireCache
* @see org.apache.geode.cache.Cache
* @see #constructCacheFactoryBean()
*/
@Bean
public CacheFactoryBean gemfireCache() {
CacheFactoryBean gemfireCache = constructCacheFactoryBean();
gemfireCache.setEnableAutoReconnect(enableAutoReconnect());
gemfireCache.setLockLease(lockLease());
gemfireCache.setLockTimeout(lockTimeout());
gemfireCache.setMessageSyncInterval(messageSyncInterval());
gemfireCache.setPeerCacheConfigurers(resolvePeerCacheConfigurers());
gemfireCache.setSearchTimeout(searchTimeout());
gemfireCache.setUseBeanFactoryLocator(useBeanFactoryLocator());
gemfireCache.setUseClusterConfiguration(useClusterConfiguration());
@@ -67,8 +90,30 @@ public class PeerCacheConfiguration extends AbstractCacheConfiguration {
return gemfireCache;
}
/* (non-Javadoc) */
private List<PeerCacheConfigurer> resolvePeerCacheConfigurers() {
return Optional.ofNullable(this.peerCacheConfigurers)
.filter(peerCacheConfigurers -> !peerCacheConfigurers.isEmpty())
.orElseGet(() ->
Optional.of(this.beanFactory())
.filter(beanFactory -> beanFactory instanceof ListableBeanFactory)
.map(beanFactory -> {
Map<String, PeerCacheConfigurer> beansOfType = ((ListableBeanFactory) beanFactory)
.getBeansOfType(PeerCacheConfigurer.class, true, true);
return nullSafeMap(beansOfType).values().stream().collect(Collectors.toList());
})
.orElseGet(Collections::emptyList)
);
}
/**
* {@inheritDoc}
* Constructs a new instance of {@link CacheFactoryBean} used to create a peer {@link Cache}.
*
* @param <T> {@link Class} sub-type of {@link CacheFactoryBean}.
* @return a new instance of {@link CacheFactoryBean}.
* @see org.springframework.data.gemfire.CacheFactoryBean
*/
@Override
@SuppressWarnings("unchecked")
@@ -77,18 +122,20 @@ public class PeerCacheConfiguration extends AbstractCacheConfiguration {
}
/**
* Configures GemFire peer {@link org.apache.geode.cache.Cache} specific settings.
* Configures peer {@link Cache} specific settings.
*
* @param importMetadata {@link AnnotationMetadata} containing peer cache meta-data used to configure
* the GemFire peer {@link org.apache.geode.cache.Cache}.
* @param importMetadata {@link AnnotationMetadata} containing peer cache meta-data used to
* configure the peer {@link Cache}.
* @see org.springframework.core.type.AnnotationMetadata
* @see #isCacheServerOrPeerCacheApplication(AnnotationMetadata)
*/
@Override
protected void configureCache(AnnotationMetadata importMetadata) {
super.configureCache(importMetadata);
if (isCacheServerOrPeerCacheApplication(importMetadata)) {
Map<String, Object> peerCacheApplicationAttributes =
importMetadata.getAnnotationAttributes(getAnnotationTypeName());
@@ -99,11 +146,9 @@ public class PeerCacheConfiguration extends AbstractCacheConfiguration {
setSearchTimeout((Integer) peerCacheApplicationAttributes.get("searchTimeout"));
setUseClusterConfiguration(Boolean.TRUE.equals(peerCacheApplicationAttributes.get("useClusterConfiguration")));
String locators = (String) peerCacheApplicationAttributes.get("locators");
if (hasValue(locators)) {
setLocators(locators);
}
Optional.ofNullable((String) peerCacheApplicationAttributes.get("locators"))
.filter(PeerCacheConfiguration::hasValue)
.ifPresent(this::setLocators);
}
}

View File

@@ -0,0 +1,45 @@
/*
* Copyright 2016 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 org.apache.geode.cache.Cache;
import org.springframework.data.gemfire.CacheFactoryBean;
/**
* The {@link PeerCacheConfigurer} interface defines a contract for implementations to customize the configuration
* of a {@link CacheFactoryBean} used to construct, configure and initialize an instance of a peer {@link Cache}.
*
* @author John Blum
* @see org.apache.geode.cache.Cache
* @see org.springframework.data.gemfire.CacheFactoryBean
* @see org.springframework.data.gemfire.config.annotation.PeerCacheApplication
* @since 1.9.0
*/
public interface PeerCacheConfigurer {
/**
* Configuration callback method providing a reference to a {@link CacheFactoryBean} used to construct,
* configure and initialize an instance of a peer {@link Cache}.
*
* @param beanName name of peer {@link Cache} bean declared in the Spring application context.
* @param bean reference to the {@link CacheFactoryBean}.
* @see org.springframework.data.gemfire.CacheFactoryBean
*/
void configure(String beanName, CacheFactoryBean bean);
}

View File

@@ -0,0 +1,47 @@
/*
* Copyright 2017 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 org.apache.geode.cache.client.Pool;
import org.springframework.data.gemfire.client.PoolFactoryBean;
/**
* The {@link PoolConfigurer} interface defines a contract for implementations to customize the configuration
* of a {@link PoolFactoryBean} used to construct, configure and initialize a {@link Pool}.
*
* @author John Blum
* @see org.apache.geode.cache.client.Pool
* @see org.springframework.data.gemfire.client.PoolFactoryBean
* @see org.springframework.data.gemfire.config.annotation.AddPoolConfiguration
* @see org.springframework.data.gemfire.config.annotation.AddPoolsConfiguration
* @see org.springframework.data.gemfire.config.annotation.EnablePool
* @see org.springframework.data.gemfire.config.annotation.EnablePools
* @since 1.1.0
*/
public interface PoolConfigurer {
/**
* Configuration callback method providing a reference to a {@link PoolFactoryBean} used to construct,
* configure and initialize an instance of a {@link Pool}.
*
* @param beanName name of the {@link Pool} bean declared in the Spring application context.
* @param bean reference to the {@link PoolFactoryBean}.
* @see org.springframework.data.gemfire.client.PoolFactoryBean
*/
void configure(String beanName, PoolFactoryBean bean);
}

View File

@@ -44,7 +44,7 @@ public class RedisServerConfiguration extends EmbeddedServiceConfigurationSuppor
@Override
protected Properties toGemFireProperties(Map<String, Object> annotationAttributes) {
return new PropertiesBuilder()
return PropertiesBuilder.create()
.setProperty("redis-bind-address", annotationAttributes.get("bindAddress"))
.setProperty("redis-port", resolvePort((Integer)annotationAttributes.get("port"), DEFAULT_REDIS_PORT))
.build();

View File

@@ -0,0 +1,60 @@
/*
* Copyright 2017 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 org.apache.geode.cache.Region;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.gemfire.RegionFactoryBean;
import org.springframework.data.gemfire.client.ClientRegionFactoryBean;
/**
* The {@link RegionConfigurer} interface defines a contract for implementations to customize the configuration
* of Entity-defined {@link Region Regions} when a user annotates her Spring application {@link Configuration}
* class with {@link EnableEntityDefinedRegions}.
*
* @author John Blum
* @see org.apache.geode.cache.Region
* @see org.springframework.data.gemfire.RegionFactoryBean
* @see org.springframework.data.gemfire.client.ClientRegionFactoryBean
* @see org.springframework.data.gemfire.config.annotation.EnableEntityDefinedRegions
* @see org.springframework.data.gemfire.config.annotation.support.GemFireCacheTypeAwareRegionFactoryBean
* @since 1.1.0
*/
public interface RegionConfigurer {
/**
* Configuration callback method providing a reference to a {@link RegionFactoryBean} used to construct, configure
* and initialize an instance of a peer {@link Region}.
*
* @param beanName name of {@link Region} bean declared in the Spring application context.
* @param bean reference to the {@link RegionFactoryBean}.
* @see org.springframework.data.gemfire.RegionFactoryBean
*/
default void configure(String beanName, RegionFactoryBean<?, ?> bean) {
}
/**
* Configuration callback method providing a reference to a {@link ClientRegionFactoryBean} used to construct,
* configure and initialize an instance of a client {@link Region}.
*
* @param beanName name of {@link Region} bean declared in the Spring application context.
* @param bean reference to the {@link ClientRegionFactoryBean}.
* @see org.springframework.data.gemfire.client.ClientRegionFactoryBean
*/
default void configure(String beanName, ClientRegionFactoryBean<?, ?> bean) {
}
}

View File

@@ -0,0 +1,249 @@
/*
* Copyright 2016 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.support;
import static org.springframework.data.gemfire.util.RuntimeExceptionFactory.newIllegalStateException;
import java.util.Optional;
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.InitializingBean;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.expression.BeanFactoryAccessor;
import org.springframework.context.expression.EnvironmentAccessor;
import org.springframework.context.expression.MapAccessor;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.expression.spel.support.StandardTypeConverter;
import org.springframework.expression.spel.support.StandardTypeLocator;
import org.springframework.util.StringUtils;
/**
* The {@link AbstractAnnotationConfigSupport} class is an abstract base class encapsulating functionality
* common to all Annotations and configuration classes used to configure Pivotal GemFire/Apache Geode objects
* with Spring Data GemFire or Spring Data Geode.
*
* @author John Blum
* @see java.lang.ClassLoader
* @see org.springframework.beans.factory.BeanClassLoaderAware
* @see org.springframework.beans.factory.BeanFactory
* @see org.springframework.beans.factory.BeanFactoryAware
* @see org.springframework.beans.factory.InitializingBean
* @see org.springframework.beans.factory.config.ConfigurableBeanFactory
* @see org.springframework.beans.factory.support.AbstractBeanDefinition
* @see org.springframework.beans.factory.support.BeanDefinitionRegistry
* @see org.springframework.expression.EvaluationContext
* @since 1.9.0
*/
@SuppressWarnings("unused")
public abstract class AbstractAnnotationConfigSupport
implements BeanClassLoaderAware, BeanFactoryAware, InitializingBean {
private BeanFactory beanFactory;
private ClassLoader beanClassLoader;
private EvaluationContext evaluationContext;
/**
* Determines whether the given {@link Object} has value. The {@link Object} is valuable
* if it is not {@literal null}.
*
* @param value {@link Object} to evaluate.
* @return a boolean value indicating whether the given {@link Object} has value.
*/
protected static boolean hasValue(Object value) {
return Optional.ofNullable(value).isPresent();
}
/**
* Determines whether the given {@link Number} has value. The {@link Number} is valuable
* if it is not {@literal null} and is not equal to 0.0d.
*
* @param value {@link Number} to evaluate.
* @return a boolean value indicating whether the given {@link Number} has value.
*/
protected static boolean hasValue(Number value) {
return Optional.ofNullable(value).filter(it -> it.doubleValue() != 0.0d).isPresent();
}
/**
* Determines whether the given {@link String} has value. The {@link String} is valuable
* if it is not {@literal null} or empty.
*
* @param value {@link String} to evaluate.
* @return a boolean value indicating whether the given {@link String} is valuable.
*/
protected static boolean hasValue(String value) {
return StringUtils.hasText(value);
}
@Override
public void afterPropertiesSet() throws Exception {
this.evaluationContext = newEvaluationContext();
}
/**
* Constructs, configures and initializes a new instance of an {@link EvaluationContext}.
*
* @return a new {@link EvaluationContext}.
* @see org.springframework.expression.EvaluationContext
* @see #beanFactory()
*/
protected EvaluationContext newEvaluationContext() {
StandardEvaluationContext evaluationContext = new StandardEvaluationContext();
evaluationContext.addPropertyAccessor(new BeanFactoryAccessor());
evaluationContext.addPropertyAccessor(new EnvironmentAccessor());
evaluationContext.addPropertyAccessor(new MapAccessor());
evaluationContext.setTypeLocator(new StandardTypeLocator(beanClassLoader()));
Optional.ofNullable(beanFactory())
.filter(beanFactory -> beanFactory instanceof ConfigurableBeanFactory)
.map(beanFactory -> ((ConfigurableBeanFactory) beanFactory).getConversionService())
.ifPresent(conversionService ->
evaluationContext.setTypeConverter(new StandardTypeConverter(conversionService)));
return evaluationContext;
}
/**
* 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();
/**
* Returns the fully-qualified {@link Class#getName() class name} of the cache application
* {@link java.lang.annotation.Annotation} type.
*
* @return the fully-qualified {@link Class#getName() class name} of the cache application
* {@link java.lang.annotation.Annotation} type.
* @see java.lang.Class#getName()
* @see #getAnnotationType()
*/
protected String getAnnotationTypeName() {
return getAnnotationType().getName();
}
/**
* Returns the simple {@link Class#getName() class name} of the cache application
* {@link java.lang.annotation.Annotation} type.
*
* @return the simple {@link Class#getName() class name} of the cache application
* {@link java.lang.annotation.Annotation} type.
* @see java.lang.Class#getSimpleName()
* @see #getAnnotationType()
*/
protected String getAnnotationTypeSimpleName() {
return getAnnotationType().getSimpleName();
}
/**
* {@inheritDoc}
*/
@Override
public void setBeanClassLoader(ClassLoader beanClassLoader) {
this.beanClassLoader = beanClassLoader;
}
/**
* Returns a reference to the {@link ClassLoader} use by the Spring {@link BeanFactory} to load classes
* for bean definitions.
*
* @return the {@link ClassLoader} used by the Spring {@link BeanFactory} to load classes for bean definitions.
* @see #setBeanClassLoader(ClassLoader)
*/
protected ClassLoader beanClassLoader() {
return this.beanClassLoader;
}
/**
* {@inheritDoc}
*/
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
}
/**
* Returns a reference to the Spring {@link BeanFactory} in the current application context.
*
* @return a reference to the Spring {@link BeanFactory}.
* @throws IllegalStateException if the Spring {@link BeanFactory} was not properly configured.
* @see org.springframework.beans.factory.BeanFactory
*/
protected BeanFactory beanFactory() {
return Optional.ofNullable(this.beanFactory)
.orElseThrow(() -> newIllegalStateException("BeanFactory is required"));
}
/**
*
* @return
*/
protected EvaluationContext evaluationContext() {
return this.evaluationContext;
}
/**
* Registers the {@link AbstractBeanDefinition} with the {@link BeanDefinitionRegistry} using a generated bean name.
*
* @param beanDefinition {@link AbstractBeanDefinition} to register.
* @return the given {@link AbstractBeanDefinition}.
* @see org.springframework.beans.factory.BeanFactory
* @see org.springframework.beans.factory.support.AbstractBeanDefinition
* @see org.springframework.beans.factory.support.BeanDefinitionRegistry
* @see org.springframework.beans.factory.support.BeanDefinitionReaderUtils#registerWithGeneratedName(AbstractBeanDefinition, BeanDefinitionRegistry)
* @see #beanFactory()
*/
protected AbstractBeanDefinition register(AbstractBeanDefinition beanDefinition) {
BeanFactory beanFactory = beanFactory();
return (beanFactory instanceof BeanDefinitionRegistry
? register(beanDefinition, (BeanDefinitionRegistry) beanFactory)
: beanDefinition);
}
/**
* Registers the {@link AbstractBeanDefinition} with the {@link BeanDefinitionRegistry} using a generated bean name.
*
* @param beanDefinition {@link AbstractBeanDefinition} to register.
* @param registry {@link BeanDefinitionRegistry} used to register the {@link AbstractBeanDefinition}.
* @return the given {@link AbstractBeanDefinition}.
* @see org.springframework.beans.factory.support.AbstractBeanDefinition
* @see org.springframework.beans.factory.support.BeanDefinitionRegistry
* @see org.springframework.beans.factory.support.BeanDefinitionReaderUtils#registerWithGeneratedName(AbstractBeanDefinition, BeanDefinitionRegistry)
*/
protected AbstractBeanDefinition register(AbstractBeanDefinition beanDefinition, BeanDefinitionRegistry registry) {
Optional.ofNullable(registry).ifPresent(it ->
BeanDefinitionReaderUtils.registerWithGeneratedName(beanDefinition, it)
);
return beanDefinition;
}
}

View File

@@ -17,12 +17,14 @@
package org.springframework.data.gemfire.config.annotation.support;
import static org.springframework.data.gemfire.util.RuntimeExceptionFactory.newIllegalStateException;
import java.util.Map;
import java.util.Optional;
import java.util.Properties;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
@@ -39,18 +41,25 @@ import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
* The {@link EmbeddedServiceConfigurationSupport} class is an abstract base class supporting the configuration
* of Pivotal GemFire and Apache Geode embedded services.
* The {@link EmbeddedServiceConfigurationSupport} class is an abstract base class supporting
* the configuration of Pivotal GemFire and Apache Geode embedded services.
*
* @author John Blum
* @see java.util.Properties
* @see org.springframework.beans.factory.BeanFactory
* @see org.springframework.beans.factory.BeanFactoryAware
* @see org.springframework.beans.factory.config.AutowireCapableBeanFactory
* @see org.springframework.beans.factory.config.BeanDefinitionHolder
* @see org.springframework.beans.factory.support.BeanDefinitionBuilder
* @see org.springframework.beans.factory.support.BeanDefinitionRegistry
* @see org.springframework.context.annotation.ImportBeanDefinitionRegistrar
* @see org.springframework.core.type.AnnotationMetadata
* @see org.springframework.data.gemfire.config.annotation.AbstractCacheConfiguration
* @see org.springframework.data.gemfire.config.annotation.support.AbstractAnnotationConfigSupport
* @since 1.9.0
*/
@SuppressWarnings("unused")
public abstract class EmbeddedServiceConfigurationSupport implements ImportBeanDefinitionRegistrar, BeanFactoryAware {
public abstract class EmbeddedServiceConfigurationSupport extends AbstractAnnotationConfigSupport
implements ImportBeanDefinitionRegistrar {
public static final Integer DEFAULT_PORT = 0;
public static final String DEFAULT_HOST = "localhost";
@@ -59,8 +68,6 @@ public abstract class EmbeddedServiceConfigurationSupport implements ImportBeanD
@SuppressWarnings("all")
private AbstractCacheConfiguration cacheConfiguration;
private BeanFactory beanFactory;
/**
* Returns a reference to an instance of the {@link AbstractCacheConfiguration} class used to configure
* a GemFire (Singleton, client or peer) cache instance along with it's associated, embedded services.
@@ -72,59 +79,8 @@ public abstract class EmbeddedServiceConfigurationSupport implements ImportBeanD
*/
@SuppressWarnings("unchecked")
protected <T extends AbstractCacheConfiguration> T cacheConfiguration() {
Assert.state(cacheConfiguration != null, "AbstractCacheConfiguration was not properly initialized");
return (T) this.cacheConfiguration;
}
/**
* Returns the configured GemFire cache application annotation type
* (e.g. {@link org.springframework.data.gemfire.config.annotation.ClientCacheApplication}
* or {@link org.springframework.data.gemfire.config.annotation.PeerCacheApplication}.
*
* @return an {@link Class annotation} defining the GemFire cache application type.
*/
protected abstract Class getAnnotationType();
/**
* Returns the fully-qualified class name of the GemFire cache application annotation type.
*
* @return a fully-qualified class name of the GemFire cache application annotation type.
* @see java.lang.Class#getName()
* @see #getAnnotationType()
*/
protected String getAnnotationTypeName() {
return getAnnotationType().getName();
}
/**
* Returns the simple class name of the GemFire cache application annotation type.
*
* @return the simple class name of the GemFire cache application annotation type.
* @see java.lang.Class#getSimpleName()
* @see #getAnnotationType()
*/
protected String getAnnotationTypeSimpleName() {
return getAnnotationType().getSimpleName();
}
/**
* @inheritDoc
*/
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
}
/**
* Returns a reference to the Spring {@link BeanFactory}.
*
* @return a reference to the Spring {@link BeanFactory}.
* @throws IllegalStateException if the Spring {@link BeanFactory} was not properly initialized.
* @see org.springframework.beans.factory.BeanFactory
*/
protected BeanFactory getBeanFactory() {
Assert.state(this.beanFactory != null, "BeanFactory was not properly initialized");
return this.beanFactory;
return Optional.ofNullable((T) this.cacheConfiguration)
.orElseThrow(() -> newIllegalStateException("AbstractCacheConfiguration is required"));
}
/**
@@ -132,7 +88,7 @@ public abstract class EmbeddedServiceConfigurationSupport implements ImportBeanD
*/
@Override
public final void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
BeanDefinitionRegistry registry) {
BeanDefinitionRegistry registry) {
if (isAnnotationPresent(importingClassMetadata)) {
Map<String, Object> annotationAttributes = getAnnotationAttributes(importingClassMetadata);
@@ -144,12 +100,12 @@ public abstract class EmbeddedServiceConfigurationSupport implements ImportBeanD
/* (non-Javadoc) */
@SuppressWarnings("unused")
protected void registerBeanDefinitions(AnnotationMetadata importingClassMetaData,
Map<String, Object> annotationAttributes, BeanDefinitionRegistry registry) {
Map<String, Object> annotationAttributes, BeanDefinitionRegistry registry) {
}
/* (non-Javadoc) */
protected void setGemFireProperties(AnnotationMetadata importingClassMetadata,
Map<String, Object> annotationAttributes, BeanDefinitionRegistry registry) {
Map<String, Object> annotationAttributes, BeanDefinitionRegistry registry) {
Properties gemfireProperties = toGemFireProperties(annotationAttributes);
@@ -183,10 +139,10 @@ public abstract class EmbeddedServiceConfigurationSupport implements ImportBeanD
/* (non-Javadoc) */
protected void registerGemFirePropertiesBeanPostProcessor(BeanDefinitionRegistry registry,
Properties customGemFireProperties) {
Properties customGemFireProperties) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(
GemFirePropertiesBeanPostProcessor.class);
BeanDefinitionBuilder builder =
BeanDefinitionBuilder.genericBeanDefinition(GemFirePropertiesBeanPostProcessor.class);
builder.addConstructorArgValue(customGemFireProperties);
@@ -200,7 +156,7 @@ public abstract class EmbeddedServiceConfigurationSupport implements ImportBeanD
/* (non-Javadoc) */
protected String generateBeanName() {
return generateBeanName(getAnnotationTypeSimpleName());
return generateBeanName(getAnnotationType());
}
/* (non-Javadoc) */
@@ -228,11 +184,12 @@ public abstract class EmbeddedServiceConfigurationSupport implements ImportBeanD
* @return a Spring managed bean instance for the given, required {@link Class} type, or {@literal null}
* if no bean instance of the given, required {@link Class} type could be found.
* @throws BeansException if the Spring manage bean of the required {@link Class} type could not be resolved.
* @see #getBeanFactory()
* @see #beanFactory()
*/
@SuppressWarnings("unchecked")
protected <T> T resolveBean(Class<T> beanType) {
BeanFactory beanFactory = getBeanFactory();
BeanFactory beanFactory = beanFactory();
if (beanFactory instanceof AutowireCapableBeanFactory) {
AutowireCapableBeanFactory autowiringBeanFactory = (AutowireCapableBeanFactory) beanFactory;
@@ -252,7 +209,7 @@ public abstract class EmbeddedServiceConfigurationSupport implements ImportBeanD
/* (non-Javadoc) */
protected String resolveHost(String hostname, String defaultHostname) {
return (StringUtils.hasText(hostname) ? hostname : defaultHostname);
return Optional.ofNullable(hostname).filter(StringUtils::hasText).orElse(defaultHostname);
}
/* (non-Javadoc) */
@@ -262,12 +219,12 @@ public abstract class EmbeddedServiceConfigurationSupport implements ImportBeanD
/* (non-Javadoc) */
protected Integer resolvePort(Integer port, Integer defaultPort) {
return (port != null ? port : defaultPort);
return Optional.ofNullable(port).orElse(defaultPort);
}
/**
* Spring {@link BeanPostProcessor} used to process GemFire System properties defined as a Spring bean
* in the Spring application context before initialization.
* Spring {@link BeanPostProcessor} used to process before initialization Pivotal GemFire or Apache Geode
* {@link Properties} defined as a bean in the Spring application context.
*
* @see org.springframework.beans.factory.config.BeanPostProcessor
*/
@@ -278,15 +235,15 @@ public abstract class EmbeddedServiceConfigurationSupport implements ImportBeanD
private final Properties gemfireProperties;
/**
* Construct an instance of the {@link GemFirePropertiesBeanPostProcessor} initialized with
* the given GemFire {@link Properties}.
* Constructs a new instance of the {@link GemFirePropertiesBeanPostProcessor} initialized with
* the given GemFire/Geode {@link Properties}.
*
* @param gemfireProperties {@link Properties} used to configure GemFire.
* @throws IllegalArgumentException if the {@link Properties} are null or empty.
* @param gemfireProperties {@link Properties} used to configure Pivotal GemFire or Apache Geode.
* @throws IllegalArgumentException if {@link Properties} are {@literal null} or empty.
* @see java.util.Properties
*/
protected GemFirePropertiesBeanPostProcessor(Properties gemfireProperties) {
Assert.notEmpty(gemfireProperties, "GemFire Properties must not be null or empty");
Assert.notEmpty(gemfireProperties, "GemFire Properties are required");
this.gemfireProperties = gemfireProperties;
}
@@ -295,6 +252,7 @@ public abstract class EmbeddedServiceConfigurationSupport implements ImportBeanD
*/
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof Properties && GEMFIRE_PROPERTIES_BEAN_NAME.equals(beanName)) {
Properties gemfirePropertiesBean = (Properties) bean;
gemfirePropertiesBean.putAll(gemfireProperties);
@@ -302,13 +260,5 @@ public abstract class EmbeddedServiceConfigurationSupport implements ImportBeanD
return bean;
}
/**
* {@inheritDoc}
*/
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
}
}

View File

@@ -17,8 +17,12 @@
package org.springframework.data.gemfire.config.annotation.support;
import static org.apache.geode.internal.lang.ObjectUtils.defaultIfNull;
import static org.springframework.data.gemfire.util.SpringUtils.defaultIfEmpty;
import static org.springframework.data.gemfire.util.ArrayUtils.nullSafeArray;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import org.apache.geode.cache.DataPolicy;
import org.apache.geode.cache.GemFireCache;
@@ -26,16 +30,14 @@ 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.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
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.Assert;
import org.springframework.util.StringUtils;
/**
* The {@link GemFireCacheTypeAwareRegionFactoryBean} class is a smart Spring {@link FactoryBean} that knows how to
@@ -43,22 +45,21 @@ import org.springframework.util.Assert;
* a {@link org.apache.geode.cache.client.ClientCache} or a peer {@link org.apache.geode.cache.Cache}.
*
* @author John Blum
* @see org.springframework.beans.factory.BeanFactory
* @see org.springframework.beans.factory.BeanFactoryAware
* @see org.springframework.beans.factory.FactoryBean
* @see org.springframework.data.gemfire.RegionLookupFactoryBean
* @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
* @see org.springframework.data.gemfire.client.ClientRegionFactoryBean
* @see org.springframework.data.gemfire.config.annotation.RegionConfigurer
* @since 1.9.0
*/
@SuppressWarnings("unused")
public class GemFireCacheTypeAwareRegionFactoryBean<K, V> extends RegionLookupFactoryBean<K, V>
implements BeanFactoryAware {
public class GemFireCacheTypeAwareRegionFactoryBean<K, V> extends RegionLookupFactoryBean<K, V> {
private GemFireCache gemfireCache;
private BeanFactory beanFactory;
private Boolean close = false;
private Class<K> keyConstraint;
@@ -68,6 +69,8 @@ public class GemFireCacheTypeAwareRegionFactoryBean<K, V> extends RegionLookupFa
private DataPolicy dataPolicy = DataPolicy.DEFAULT;
private List<RegionConfigurer> regionConfigurers = Collections.emptyList();
private RegionAttributes<K, V> regionAttributes;
private RegionShortcut serverRegionShortcut;
@@ -79,7 +82,8 @@ public class GemFireCacheTypeAwareRegionFactoryBean<K, V> extends RegionLookupFa
* @inheritDoc
*/
@Override
public Region<K, V> lookupRegion(GemFireCache gemfireCache, String regionName) throws Exception {
public Region<K, V> createRegion(GemFireCache gemfireCache, String regionName) throws Exception {
return (GemfireUtils.isClient(gemfireCache) ? newClientRegion(gemfireCache, regionName)
: newServerRegion(gemfireCache, regionName));
}
@@ -97,20 +101,23 @@ public class GemFireCacheTypeAwareRegionFactoryBean<K, V> extends RegionLookupFa
* @see org.apache.geode.cache.Region
*/
protected Region<K, V> newClientRegion(GemFireCache gemfireCache, String regionName) throws Exception {
ClientRegionFactoryBean<K, V> clientRegion = new ClientRegionFactoryBean<K, V>();
clientRegion.setAttributes(getRegionAttributes());
clientRegion.setBeanFactory(getBeanFactory());
clientRegion.setCache(gemfireCache);
clientRegion.setClose(isClose());
clientRegion.setKeyConstraint(getKeyConstraint());
clientRegion.setPoolName(getPoolName());
clientRegion.setRegionName(regionName);
clientRegion.setShortcut(getClientRegionShortcut());
clientRegion.setValueConstraint(getValueConstraint());
clientRegion.afterPropertiesSet();
ClientRegionFactoryBean<K, V> clientRegionFactory = new ClientRegionFactoryBean<>();
return clientRegion.getObject();
clientRegionFactory.setAttributes(getRegionAttributes());
clientRegionFactory.setBeanFactory(getBeanFactory());
clientRegionFactory.setCache(gemfireCache);
clientRegionFactory.setClose(isClose());
clientRegionFactory.setKeyConstraint(getKeyConstraint());
clientRegionFactory.setPoolName(getPoolName());
clientRegionFactory.setRegionConfigurers(this.regionConfigurers);
clientRegionFactory.setRegionName(regionName);
clientRegionFactory.setShortcut(getClientRegionShortcut());
clientRegionFactory.setValueConstraint(getValueConstraint());
clientRegionFactory.afterPropertiesSet();
return clientRegionFactory.getObject();
}
/**
@@ -126,19 +133,22 @@ public class GemFireCacheTypeAwareRegionFactoryBean<K, V> extends RegionLookupFa
* @see org.apache.geode.cache.Region
*/
protected Region<K, V> newServerRegion(GemFireCache gemfireCache, String regionName) throws Exception {
GenericRegionFactoryBean<K, V> serverRegion = new GenericRegionFactoryBean<K, V>();
serverRegion.setAttributes(getRegionAttributes());
serverRegion.setCache(gemfireCache);
serverRegion.setClose(isClose());
serverRegion.setDataPolicy(getDataPolicy());
serverRegion.setKeyConstraint(getKeyConstraint());
serverRegion.setRegionName(regionName);
serverRegion.setShortcut(getServerRegionShortcut());
serverRegion.setValueConstraint(getValueConstraint());
serverRegion.afterPropertiesSet();
GenericRegionFactoryBean<K, V> serverRegionFactory = new GenericRegionFactoryBean<>();
return serverRegion.getObject();
serverRegionFactory.setAttributes(getRegionAttributes());
serverRegionFactory.setCache(gemfireCache);
serverRegionFactory.setClose(isClose());
serverRegionFactory.setDataPolicy(getDataPolicy());
serverRegionFactory.setKeyConstraint(getKeyConstraint());
serverRegionFactory.setRegionConfigurers(this.regionConfigurers);
serverRegionFactory.setRegionName(regionName);
serverRegionFactory.setShortcut(getServerRegionShortcut());
serverRegionFactory.setValueConstraint(getValueConstraint());
serverRegionFactory.afterPropertiesSet();
return serverRegionFactory.getObject();
}
public void setAttributes(RegionAttributes<K, V> regionAttributes) {
@@ -149,25 +159,12 @@ public class GemFireCacheTypeAwareRegionFactoryBean<K, V> extends RegionLookupFa
return this.regionAttributes;
}
/**
* @inheritDoc
*/
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
}
protected BeanFactory getBeanFactory() {
Assert.state(this.beanFactory != null, "BeanFactory was not properly initialized");
return this.beanFactory;
}
public void setClientRegionShortcut(ClientRegionShortcut clientRegionShortcut) {
this.clientRegionShortcut = clientRegionShortcut;
}
protected ClientRegionShortcut getClientRegionShortcut() {
return defaultIfNull(this.clientRegionShortcut, ClientRegionShortcut.PROXY);
return Optional.ofNullable(this.clientRegionShortcut).orElse(ClientRegionShortcut.PROXY);
}
public void setClose(Boolean close) {
@@ -187,7 +184,7 @@ public class GemFireCacheTypeAwareRegionFactoryBean<K, V> extends RegionLookupFa
}
protected DataPolicy getDataPolicy() {
return defaultIfNull(this.dataPolicy, DataPolicy.DEFAULT);
return Optional.ofNullable(this.dataPolicy).orElse(DataPolicy.DEFAULT);
}
public void setKeyConstraint(Class<K> keyConstraint) {
@@ -203,7 +200,33 @@ public class GemFireCacheTypeAwareRegionFactoryBean<K, V> extends RegionLookupFa
}
protected String getPoolName() {
return defaultIfEmpty(this.poolName, GemfireConstants.DEFAULT_GEMFIRE_POOL_NAME);
return Optional.ofNullable(this.poolName).filter(StringUtils::hasText)
.orElse(GemfireConstants.DEFAULT_GEMFIRE_POOL_NAME);
}
/**
* Null-safe operation used to set an array of {@link RegionConfigurer RegionConfigurers} used to apply
* additional configuration to this {@link RegionLookupFactoryBean} when using Annotation-based configuration.
*
* @param regionConfigurers array of {@link RegionConfigurer RegionConfigurers} used to apply
* additional configuration to this {@link RegionLookupFactoryBean}.
* @see org.springframework.data.gemfire.config.annotation.RegionConfigurer
* @see #setRegionConfigurers(List)
*/
public void setRegionConfigurers(RegionConfigurer... regionConfigurers) {
setRegionConfigurers(Arrays.asList(nullSafeArray(regionConfigurers, RegionConfigurer.class)));
}
/**
* Null-safe operation used to set an {@link Iterable} of {@link RegionConfigurer RegionConfigurers} used to apply
* additional configuration to this {@link RegionLookupFactoryBean} when using Annotation-based configuration.
*
* @param regionConfigurers {@link Iterable} of {@link RegionConfigurer RegionConfigurers} used to apply
* additional configuration to this {@link RegionLookupFactoryBean}.
* @see org.springframework.data.gemfire.config.annotation.RegionConfigurer
*/
public void setRegionConfigurers(List<RegionConfigurer> regionConfigurers) {
this.regionConfigurers = Optional.ofNullable(regionConfigurers).orElseGet(Collections::emptyList);
}
public void setServerRegionShortcut(RegionShortcut shortcut) {

View File

@@ -17,7 +17,10 @@
package org.springframework.data.gemfire.search.lucene;
import static java.util.stream.StreamSupport.stream;
import static org.springframework.data.gemfire.util.ArrayUtils.nullSafeArray;
import static org.springframework.data.gemfire.util.CollectionUtils.nullSafeCollection;
import static org.springframework.data.gemfire.util.CollectionUtils.nullSafeIterable;
import static org.springframework.data.gemfire.util.CollectionUtils.nullSafeList;
import static org.springframework.data.gemfire.util.CollectionUtils.nullSafeMap;
import static org.springframework.util.CollectionUtils.isEmpty;
@@ -27,6 +30,7 @@ import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.function.Supplier;
import org.apache.geode.cache.GemFireCache;
import org.apache.geode.cache.Region;
@@ -35,43 +39,53 @@ import org.apache.geode.cache.lucene.LuceneService;
import org.apache.geode.cache.lucene.LuceneServiceProvider;
import org.apache.lucene.analysis.Analyzer;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.data.gemfire.config.annotation.IndexConfigurer;
import org.springframework.data.gemfire.support.AbstractFactoryBeanSupport;
import org.springframework.data.gemfire.util.CacheUtils;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
* Spring {@link FactoryBean} used to construct {@link LuceneIndex Lucene Indexes} on application domain object fields.
* Spring {@link FactoryBean} used to construct, configure and initialize {@link LuceneIndex Lucene Indexes}
* on application domain object fields.
*
* @author John Blum
* @see org.springframework.beans.factory.BeanNameAware
* @see org.springframework.beans.factory.DisposableBean
* @see org.springframework.beans.factory.FactoryBean
* @see org.springframework.beans.factory.InitializingBean
* @see org.apache.geode.cache.GemFireCache
* @see org.apache.geode.cache.Region
* @see org.apache.geode.cache.lucene.LuceneIndex
* @see org.apache.geode.cache.lucene.LuceneService
* @see org.apache.geode.cache.lucene.LuceneServiceProvider
* @see org.apache.lucene.analysis.Analyzer
* @see org.springframework.beans.factory.DisposableBean
* @see org.springframework.beans.factory.FactoryBean
* @see org.springframework.beans.factory.InitializingBean
* @see org.springframework.data.gemfire.config.annotation.IndexConfigurer
* @see org.springframework.data.gemfire.support.AbstractFactoryBeanSupport
* @since 1.1.0
*/
@SuppressWarnings("unused")
public class LuceneIndexFactoryBean implements FactoryBean<LuceneIndex>,
BeanFactoryAware, BeanNameAware, InitializingBean, DisposableBean {
public class LuceneIndexFactoryBean extends AbstractFactoryBeanSupport<LuceneIndex>
implements DisposableBean, InitializingBean {
protected static final boolean DEFAULT_DESTROY = false;
private boolean destroy = DEFAULT_DESTROY;
private BeanFactory beanFactory;
private GemFireCache gemfireCache;
private List<IndexConfigurer> indexConfigurers = Collections.emptyList();
private IndexConfigurer compositeIndexConfigurer = new IndexConfigurer() {
@Override
public void configure(String beanName, LuceneIndexFactoryBean bean) {
nullSafeCollection(indexConfigurers).forEach(indexConfigurer -> indexConfigurer.configure(beanName, bean));
}
};
private List<String> fields;
private LuceneIndex luceneIndex;
@@ -90,13 +104,72 @@ public class LuceneIndexFactoryBean implements FactoryBean<LuceneIndex>,
*/
@Override
public void afterPropertiesSet() throws Exception {
String indexName = getIndexName();
applyIndexConfigurers(indexName);
this.gemfireCache = resolveCache();
this.luceneService = resolveLuceneService();
this.regionPath = resolveRegionPath();
setLuceneIndex(createIndex(indexName, getRegionPath()));
setLuceneIndex(resolveLuceneIndex(indexName, getRegionPath()));
}
/* (non-Javadoc) */
private void applyIndexConfigurers(String indexName) {
applyIndexConfigurers(indexName, getCompositeRegionConfigurer());
}
/**
* Null-safe operation to apply the given array of {@link IndexConfigurer IndexConfigurers}
* to this {@link LuceneIndexFactoryBean}.
*
* @param indexName {@link String} containing the name of the {@link LuceneIndex}.
* @param indexConfigurers array of {@link IndexConfigurer IndexConfigurers} applied
* to this {@link LuceneIndexFactoryBean}.
* @see org.springframework.data.gemfire.config.annotation.RegionConfigurer
* @see #applyIndexConfigurers(String, Iterable)
*/
protected void applyIndexConfigurers(String indexName, IndexConfigurer... indexConfigurers) {
applyIndexConfigurers(indexName, Arrays.asList(nullSafeArray(indexConfigurers, IndexConfigurer.class)));
}
/**
* Null-safe operation to apply the given {@link Iterable} of {@link IndexConfigurer IndexConfigurers}
* to this {@link LuceneIndexFactoryBean}.
*
* @param indexName {@link String} containing the name of the {@link LuceneIndex}.
* @param indexConfigurers {@link Iterable} of {@link IndexConfigurer IndexConfigurers} applied
* to this {@link LuceneIndexFactoryBean}.
* @see org.springframework.data.gemfire.config.annotation.RegionConfigurer
*/
protected void applyIndexConfigurers(String indexName, Iterable<IndexConfigurer> indexConfigurers) {
stream(nullSafeIterable(indexConfigurers).spliterator(), false)
.forEach(indexConfigurer -> indexConfigurer.configure(indexName, this));
}
/**
* Attempts to resolve a {@link LuceneIndex} by the given {@link String indexName} first then attempts to create
* the {@link LuceneIndex} with the given {@link Region#getFullPath() Region path}.
*
* @param indexName {@link String name} of the {@link LuceneIndex} to resolve.
* @param regionPath {@link Region#getFullPath() Region path} on which the {@link LuceneIndex} is applied.
* @return the resolved {@link LuceneIndex} by the given {@link String indexName} or the created {@link LuceneIndex}
* with the given {@link Region#getFullPath() Region path} if the {@link LuceneIndex} could not be resolved by
* {@link String indexName}.
* @see org.apache.geode.cache.lucene.LuceneService#getIndex(String, String)
* @see #createLuceneIndex(String, String)
* @see #getLuceneIndex()
*/
protected LuceneIndex resolveLuceneIndex(String indexName, String regionPath) {
Supplier<LuceneIndex> luceneIndexSupplier = () ->
Optional.ofNullable(resolveLuceneService())
.map(luceneService -> luceneService.getIndex(indexName, regionPath))
.orElseGet(() -> createLuceneIndex(indexName, regionPath));
return getLuceneIndex().orElseGet(luceneIndexSupplier);
}
/**
@@ -115,7 +188,8 @@ public class LuceneIndexFactoryBean implements FactoryBean<LuceneIndex>,
* @see #getFields()
* @see #resolveFields(List)
*/
protected LuceneIndex createIndex(String indexName, String regionPath) {
protected LuceneIndex createLuceneIndex(String indexName, String regionPath) {
LuceneService luceneService = resolveLuceneService();
Map<String, Analyzer> fieldAnalyzers = getFieldAnalyzers();
@@ -147,6 +221,7 @@ public class LuceneIndexFactoryBean implements FactoryBean<LuceneIndex>,
@Override
@SuppressWarnings("deprecation")
public void destroy() throws Exception {
LuceneIndex luceneIndex = getObject();
if (isLuceneIndexDestroyable(luceneIndex)) {
@@ -172,6 +247,7 @@ public class LuceneIndexFactoryBean implements FactoryBean<LuceneIndex>,
*/
@Override
public LuceneIndex getObject() throws Exception {
if (this.luceneIndex == null) {
setLuceneIndex(Optional.ofNullable(resolveLuceneService())
.map((luceneService) -> luceneService.getIndex(getIndexName(), resolveRegionPath()))
@@ -189,14 +265,6 @@ public class LuceneIndexFactoryBean implements FactoryBean<LuceneIndex>,
return Optional.ofNullable(this.luceneIndex).<Class<?>>map(LuceneIndex::getClass).orElse(LuceneIndex.class);
}
/**
* @inheritDoc
*/
@Override
public boolean isSingleton() {
return true;
}
/**
* Resolves a reference to the {@link GemFireCache}.
*
@@ -231,6 +299,7 @@ public class LuceneIndexFactoryBean implements FactoryBean<LuceneIndex>,
* @see #resolveLuceneService(GemFireCache)
*/
protected LuceneService resolveLuceneService() {
return Optional.ofNullable(getLuceneService()).orElseGet(() ->
Optional.ofNullable(getBeanFactory()).map(beanFactory -> {
try {
@@ -267,6 +336,7 @@ public class LuceneIndexFactoryBean implements FactoryBean<LuceneIndex>,
* @see #getRegionPath()
*/
protected Region<?, ?> resolveRegion() {
return Optional.ofNullable(getRegion()).orElseGet(() -> {
GemFireCache cache = resolveCache();
String regionPath = getRegionPath();
@@ -286,6 +356,7 @@ public class LuceneIndexFactoryBean implements FactoryBean<LuceneIndex>,
* @see #getRegionPath()
*/
protected String resolveRegionPath() {
String regionPath = Optional.ofNullable(resolveRegion())
.map(Region::getFullPath).orElseGet(this::getRegionPath);
@@ -294,29 +365,12 @@ public class LuceneIndexFactoryBean implements FactoryBean<LuceneIndex>,
return regionPath;
}
/**
* @inheritDoc
*/
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
}
/**
* Returns a reference to the containing Spring {@link BeanFactory} if set.
*
* @return a reference to the containing Spring {@link BeanFactory} if set.
* @see org.springframework.beans.factory.BeanFactory
*/
protected BeanFactory getBeanFactory() {
return this.beanFactory;
}
/**
* @inheritDoc
*/
@Override
public void setBeanName(String name) {
super.setBeanName(name);
setIndexName(name);
}
@@ -341,6 +395,17 @@ public class LuceneIndexFactoryBean implements FactoryBean<LuceneIndex>,
return this.gemfireCache;
}
/**
* Returns a reference to the Composite {@link IndexConfigurer} used to apply additional configuration
* to this {@link LuceneIndexFactoryBean} on Spring container initialization.
*
* @return the Composite {@link IndexConfigurer}.
* @see org.springframework.data.gemfire.config.annotation.IndexConfigurer
*/
protected IndexConfigurer getCompositeRegionConfigurer() {
return this.compositeIndexConfigurer;
}
/**
* Sets whether to destroy the {@link LuceneIndex} on shutdown.
*
@@ -415,6 +480,31 @@ public class LuceneIndexFactoryBean implements FactoryBean<LuceneIndex>,
return nullSafeList(this.fields);
}
/**
* Null-safe operation to set an array of {@link IndexConfigurer IndexConfigurers} used to apply
* additional configuration to this {@link LuceneIndexFactoryBean} when using Annotation-based configuration.
*
* @param indexConfigurers array of {@link IndexConfigurer IndexConfigurers} used to apply
* additional configuration to this {@link LuceneIndexFactoryBean}.
* @see org.springframework.data.gemfire.config.annotation.IndexConfigurer
* @see #setIndexConfigurers(List)
*/
public void setIndexConfigurers(IndexConfigurer... indexConfigurers) {
setIndexConfigurers(Arrays.asList(nullSafeArray(indexConfigurers, IndexConfigurer.class)));
}
/**
* Null-safe operation to set an {@link Iterable} of {@link IndexConfigurer IndexConfigurers} used to apply
* additional configuration to this {@link LuceneIndexFactoryBean} when using Annotation-based configuration.
*
* @param indexConfigurers {@link Iterable } of {@link IndexConfigurer IndexConfigurers} used to apply
* additional configuration to this {@link LuceneIndexFactoryBean}.
* @see org.springframework.data.gemfire.config.annotation.IndexConfigurer
*/
public void setIndexConfigurers(List<IndexConfigurer> indexConfigurers) {
this.indexConfigurers = Optional.ofNullable(indexConfigurers).orElseGet(Collections::emptyList);
}
/**
* Sets the name of the {@link LuceneIndex} as identified in the {@link GemFireCache}.
*
@@ -437,16 +527,27 @@ public class LuceneIndexFactoryBean implements FactoryBean<LuceneIndex>,
}
/**
* Sets the {@link LuceneIndex} as the index created by this {@link FactoryBean}.
* Returns an {@link Optional} reference to the {@link LuceneIndex} created by this {@link LuceneIndexFactoryBean}.
*
* This method is for testing purposes only!
* @return an {@link Optional} reference to the {@link LuceneIndex} created by this {@link LuceneIndexFactoryBean}.
* @see org.apache.geode.cache.lucene.LuceneIndex
* @see java.util.Optional
*/
public Optional<LuceneIndex> getLuceneIndex() {
return Optional.ofNullable(this.luceneIndex);
}
/**
* Sets the given {@link LuceneIndex} as the index created by this {@link FactoryBean}.
*
* This method is generally used for testing purposes only.
*
* @param luceneIndex {@link LuceneIndex} created by this {@link FactoryBean}.
* @return this {@link LuceneIndexFactoryBean}.
* @see org.springframework.data.gemfire.search.lucene.LuceneIndexFactoryBean
* @see org.apache.geode.cache.lucene.LuceneIndex
*/
protected LuceneIndexFactoryBean setLuceneIndex(LuceneIndex luceneIndex) {
public LuceneIndexFactoryBean setLuceneIndex(LuceneIndex luceneIndex) {
this.luceneIndex = luceneIndex;
return this;
}

View File

@@ -15,12 +15,22 @@
*/
package org.springframework.data.gemfire.server;
import static java.util.stream.StreamSupport.stream;
import static org.springframework.data.gemfire.util.ArrayUtils.nullSafeArray;
import static org.springframework.data.gemfire.util.CollectionUtils.nullSafeCollection;
import static org.springframework.data.gemfire.util.CollectionUtils.nullSafeIterable;
import static org.springframework.data.gemfire.util.RuntimeExceptionFactory.newIllegalArgumentException;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import org.apache.geode.cache.Cache;
import org.apache.geode.cache.InterestRegistrationListener;
import org.apache.geode.cache.client.ClientCache;
import org.apache.geode.cache.server.CacheServer;
import org.apache.geode.cache.server.ClientSubscriptionConfig;
import org.apache.geode.cache.server.ServerLoadProbe;
@@ -29,18 +39,28 @@ import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.SmartLifecycle;
import org.springframework.util.Assert;
import org.springframework.data.gemfire.config.annotation.CacheServerConfigurer;
import org.springframework.data.gemfire.support.AbstractFactoryBeanSupport;
import org.springframework.util.StringUtils;
/**
* FactoryBean for easy creation and configuration of GemFire {@link CacheServer} instances.
* Spring {@link FactoryBean} used to construct, configure and initialize a {@link CacheServer}.
*
* @author Costin Leau
* @author John Blum
* @see org.apache.geode.cache.Cache
* @see org.apache.geode.cache.client.ClientCache
* @see org.apache.geode.cache.server.CacheServer
* @see org.springframework.beans.factory.DisposableBean
* @see org.springframework.beans.factory.FactoryBean
* @see org.springframework.beans.factory.InitializingBean
* @see org.springframework.context.SmartLifecycle
* @see org.springframework.data.gemfire.config.annotation.CacheServerConfigurer
* @see org.springframework.data.gemfire.support.AbstractFactoryBeanSupport
*/
@SuppressWarnings("unused")
public class CacheServerFactoryBean implements FactoryBean<CacheServer>,
InitializingBean, DisposableBean, SmartLifecycle {
public class CacheServerFactoryBean extends AbstractFactoryBeanSupport<CacheServer>
implements DisposableBean, InitializingBean, SmartLifecycle {
private boolean autoStartup = true;
private boolean notifyBySubscription = CacheServer.DEFAULT_NOTIFY_BY_SUBSCRIPTION;
@@ -60,6 +80,12 @@ public class CacheServerFactoryBean implements FactoryBean<CacheServer>,
private CacheServer cacheServer;
private List<CacheServerConfigurer> cacheServerConfigurers = Collections.emptyList();
private CacheServerConfigurer compositeCacheServerConfigurer = (beanName, bean) ->
nullSafeCollection(cacheServerConfigurers).forEach(cacheServerConfigurer ->
cacheServerConfigurer.configure(beanName, bean));
private ServerLoadProbe serverLoadProbe = CacheServer.DEFAULT_LOAD_PROBE;
private Set<InterestRegistrationListener> listeners = Collections.emptySet();
@@ -75,68 +101,149 @@ public class CacheServerFactoryBean implements FactoryBean<CacheServer>,
/**
* {@inheritDoc}
*/
@Override
@SuppressWarnings("deprecation")
public void afterPropertiesSet() throws IOException {
Assert.notNull(cache, "A GemFire Cache is required.");
cacheServer = cache.addCacheServer();
cacheServer.setBindAddress(bindAddress);
cacheServer.setGroups(serverGroups);
cacheServer.setHostnameForClients(hostNameForClients);
cacheServer.setLoadPollInterval(loadPollInterval);
cacheServer.setLoadProbe(serverLoadProbe);
cacheServer.setMaxConnections(maxConnections);
cacheServer.setMaximumMessageCount(maxMessageCount);
cacheServer.setMaximumTimeBetweenPings(maxTimeBetweenPings);
cacheServer.setMaxThreads(maxThreads);
cacheServer.setMessageTimeToLive(messageTimeToLive);
cacheServer.setNotifyBySubscription(notifyBySubscription);
cacheServer.setPort(port);
cacheServer.setSocketBufferSize(socketBufferSize);
applyCacheServerConfigurers();
for (InterestRegistrationListener listener : listeners) {
cacheServer.registerInterestRegistrationListener(listener);
}
Cache cache = resolveCache();
ClientSubscriptionConfig config = cacheServer.getClientSubscriptionConfig();
this.cacheServer = postProcess(configure(addCacheServer(cache)));
}
config.setCapacity(subscriptionCapacity);
getSubscriptionEvictionPolicy().setEvictionPolicy(config);
if (StringUtils.hasText(subscriptionDiskStore)) {
config.setDiskStoreName(subscriptionDiskStore);
}
/* (non-Javadoc) */
private void applyCacheServerConfigurers() {
applyCacheServerConfigurers(getCompositeCacheServerConfigurer());
}
/**
* {@inheritDoc}
* Null-safe operation to apply the given array of {@link CacheServerConfigurer CacheServerConfigurers}
* to this {@link CacheServerFactoryBean}.
*
* @param cacheServerConfigurers array of {@link CacheServerConfigurer CacheServerConfigurers} applied to
* this {@link CacheServerFactoryBean}.
* @see org.springframework.data.gemfire.config.annotation.CacheServerConfigurer
* @see #applyCacheServerConfigurers(Iterable)
*/
public CacheServer getObject() {
protected void applyCacheServerConfigurers(CacheServerConfigurer... cacheServerConfigurers) {
applyCacheServerConfigurers(Arrays.asList(nullSafeArray(cacheServerConfigurers, CacheServerConfigurer.class)));
}
/**
* Null-safe operation to apply the given {@link Iterable} of {@link CacheServerConfigurer CacheServerConfigurers}
* to this {@link CacheServerFactoryBean}.
*
* @param cacheServerConfigurers {@link Iterable} of {@link CacheServerConfigurer CacheServerConfigurers} applied to
* this {@link CacheServerFactoryBean}.
* @see org.springframework.data.gemfire.config.annotation.CacheServerConfigurer
*/
protected void applyCacheServerConfigurers(Iterable<CacheServerConfigurer> cacheServerConfigurers) {
stream(nullSafeIterable(cacheServerConfigurers).spliterator(), false)
.forEach(cacheServerConfigurer -> cacheServerConfigurer.configure(getBeanName(), this));
}
/* (non-Javadoc) */
private Cache resolveCache() {
return Optional.ofNullable(this.cache)
.orElseThrow(() -> newIllegalArgumentException("Cache is required"));
}
/**
* Adds a {@link CacheServer} to the given {@link Cache} for server {@link ClientCache cache clients}.
*
* @param cache {@link Cache} used to add a {@link CacheServer}.
* @return the newly added {@link CacheServer}.
* @see org.apache.geode.cache.Cache#addCacheServer()
* @see org.apache.geode.cache.server.CacheServer
*/
protected CacheServer addCacheServer(Cache cache) {
return cache.addCacheServer();
}
/**
* Configures the provided {@link CacheServer} with any custom, application-specific configuration.
*
* @param cacheServer {@link CacheServer} to configure.
* @return the given {@link CacheServer}.
* @see org.apache.geode.cache.server.CacheServer
*/
protected CacheServer configure(CacheServer cacheServer) {
cacheServer.setBindAddress(this.bindAddress);
cacheServer.setGroups(this.serverGroups);
cacheServer.setHostnameForClients(this.hostNameForClients);
cacheServer.setLoadPollInterval(this.loadPollInterval);
cacheServer.setLoadProbe(this.serverLoadProbe);
cacheServer.setMaxConnections(this.maxConnections);
cacheServer.setMaximumMessageCount(this.maxMessageCount);
cacheServer.setMaximumTimeBetweenPings(this.maxTimeBetweenPings);
cacheServer.setMaxThreads(this.maxThreads);
cacheServer.setMessageTimeToLive(this.messageTimeToLive);
cacheServer.setNotifyBySubscription(this.notifyBySubscription);
cacheServer.setPort(this.port);
cacheServer.setSocketBufferSize(this.socketBufferSize);
nullSafeCollection(this.listeners).forEach(cacheServer::registerInterestRegistrationListener);
ClientSubscriptionConfig config = cacheServer.getClientSubscriptionConfig();
config.setCapacity(this.subscriptionCapacity);
getSubscriptionEvictionPolicy().setEvictionPolicy(config);
Optional.ofNullable(this.subscriptionDiskStore).filter(StringUtils::hasText)
.ifPresent(config::setDiskStoreName);
return cacheServer;
}
/**
* {@inheritDoc}
* Post-process the {@link CacheServer} with any necessary follow-up actions.
*
* @param cacheServer {@link CacheServer} to process.
* @return the given {@link CacheServer}.
* @see org.apache.geode.cache.server.CacheServer
*/
public Class<?> getObjectType() {
return (this.cacheServer != null ? cacheServer.getClass() : CacheServer.class);
protected CacheServer postProcess(CacheServer cacheServer) {
return cacheServer;
}
/**
* Returns a reference to the Composite {@link CacheServerConfigurer} used to apply additional configuration
* to this {@link CacheServerFactoryBean} on Spring container initialization.
*
* @return the Composite {@link CacheServerConfigurer}.
* @see org.springframework.data.gemfire.config.annotation.CacheServerConfigurer
*/
protected CacheServerConfigurer getCompositeCacheServerConfigurer() {
return this.compositeCacheServerConfigurer;
}
/**
* {@inheritDoc}
*/
public boolean isSingleton() {
return true;
@Override
public CacheServer getObject() {
return this.cacheServer;
}
/**
* {@inheritDoc}
*/
@Override
@SuppressWarnings("unchecked")
public Class<?> getObjectType() {
return Optional.ofNullable(this.cacheServer).map(CacheServer::getClass).orElse((Class) CacheServer.class);
}
/* (non-Javadoc) */
public boolean isRunning() {
return (cacheServer != null && cacheServer.isRunning());
return Optional.ofNullable(this.cacheServer).map(CacheServer::isRunning).orElse(false);
}
/* (non-Javadoc) */
public boolean isAutoStartup() {
return autoStartup;
return this.autoStartup;
}
/**
@@ -149,10 +256,11 @@ public class CacheServerFactoryBean implements FactoryBean<CacheServer>,
/* (non-Javadoc) */
public void destroy() {
stop();
cacheServer = null;
this.cacheServer = null;
}
/* (non-Javadoc) */
@Override
public void start() {
try {
cacheServer.start();
@@ -163,16 +271,15 @@ public class CacheServerFactoryBean implements FactoryBean<CacheServer>,
}
/* (non-Javadoc) */
public void stop(final Runnable callback) {
@Override
public void stop(Runnable callback) {
stop();
callback.run();
}
/* (non-Javadoc) */
public void stop() {
if (cacheServer != null) {
cacheServer.stop();
}
Optional.ofNullable(this.cacheServer).ifPresent(CacheServer::stop);
}
/* (non-Javadoc) */
@@ -198,6 +305,32 @@ public class CacheServerFactoryBean implements FactoryBean<CacheServer>,
this.cacheServer = cacheServer;
}
/**
* Null-safe operation to set an array of {@link CacheServerConfigurer CacheServerConfigurers} used to apply
* additional configuration to this {@link CacheServerFactoryBean} when using Annotation-based configuration.
*
* @param cacheServerConfigurers array of {@link CacheServerConfigurer CacheServerConfigurers} used to apply
* additional configuration to this {@link CacheServerFactoryBean}.
* @see org.springframework.data.gemfire.config.annotation.PeerCacheConfigurer
* @see #setCacheServerConfigurers(List)
*/
public void setCacheServerConfigurers(CacheServerConfigurer... cacheServerConfigurers) {
setCacheServerConfigurers(Arrays.asList(nullSafeArray(cacheServerConfigurers, CacheServerConfigurer.class)));
}
/**
* Null-safe operation to set an {@link Iterable} of {@link CacheServerConfigurer CacheServerConfigurers}
* used to apply additional configuration to this {@link CacheServerFactoryBean} when using
* Annotation-based configuration.
*
* @param cacheServerConfigurers {@literal Iterable} of {@link CacheServerConfigurer CacheServerConfigurers}
* used to apply additional configuration to this {@link CacheServerFactoryBean}.
* @see org.springframework.data.gemfire.config.annotation.PeerCacheConfigurer
*/
public void setCacheServerConfigurers(List<CacheServerConfigurer> cacheServerConfigurers) {
this.cacheServerConfigurers = Optional.ofNullable(cacheServerConfigurers).orElseGet(Collections::emptyList);
}
/* (non-Javadoc) */
public void setHostNameForClients(String hostNameForClients) {
this.hostNameForClients = hostNameForClients;
@@ -275,7 +408,7 @@ public class CacheServerFactoryBean implements FactoryBean<CacheServer>,
/* (non-Javadoc) */
SubscriptionEvictionPolicy getSubscriptionEvictionPolicy() {
return (subscriptionEvictionPolicy != null ? subscriptionEvictionPolicy : SubscriptionEvictionPolicy.DEFAULT);
return Optional.ofNullable(this.subscriptionEvictionPolicy).orElse(SubscriptionEvictionPolicy.DEFAULT);
}
/* (non-Javadoc) */

View File

@@ -0,0 +1,206 @@
/*
* Copyright 2017 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.support;
import java.util.Optional;
import java.util.function.Supplier;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
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.BeanNameAware;
import org.springframework.beans.factory.FactoryBean;
/**
* The {@link AbstractFactoryBeanSupport} class is an abstract Spring {@link FactoryBean} base class implementation
* encapsulating operations common to SDG's {@link FactoryBean} implementations.
*
* @author John Blum
* @see org.springframework.beans.factory.BeanClassLoaderAware
* @see org.springframework.beans.factory.BeanFactory
* @see org.springframework.beans.factory.BeanFactoryAware
* @see org.springframework.beans.factory.BeanNameAware
* @see org.springframework.beans.factory.FactoryBean
* @since 1.0.0
*/
public abstract class AbstractFactoryBeanSupport<T> implements FactoryBean<T>,
BeanClassLoaderAware, BeanFactoryAware, BeanNameAware {
protected static final boolean DEFAULT_SINGLETON = true;
private ClassLoader beanClassLoader;
private BeanFactory beanFactory;
private final Log log = newLog();
private String beanName;
/**
* Constructs a new instance of {@link Log} to log statements printed by Spring Data GemFire/Geode.
*
* @return a new instance of {@link Log}.
* @see org.apache.commons.logging.LogFactory#getLog(Class)
* @see org.apache.commons.logging.Log
*/
protected Log newLog() {
return LogFactory.getLog(getClass());
}
/**
* Sets a reference to the {@link ClassLoader} used by the Spring container to load and create bean classes.
*
* @param classLoader {@link ClassLoader} used by the Spring container to load and create bean classes.
* @see org.springframework.beans.factory.BeanClassLoaderAware#setBeanClassLoader(ClassLoader)
* @see java.lang.ClassLoader
*/
@Override
public void setBeanClassLoader(ClassLoader classLoader) {
this.beanClassLoader = classLoader;
}
/**
* Returns a reference to the {@link ClassLoader} used by the Spring container to load and create bean classes.
*
* @return the {@link ClassLoader} used by the Spring container to load and create bean classes.
* @see org.springframework.beans.factory.BeanClassLoaderAware#setBeanClassLoader(ClassLoader)
* @see java.lang.ClassLoader
*/
public ClassLoader getBeanClassLoader() {
return this.beanClassLoader;
}
/**
* Sets a reference to the Spring {@link BeanFactory} in which this {@link FactoryBean} was declared.
*
* @param beanFactory reference to the declaring Spring {@link BeanFactory}.
* @see org.springframework.beans.factory.BeanFactoryAware#setBeanFactory(BeanFactory)
* @see org.springframework.beans.factory.BeanFactory
*/
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
}
/**
* Returns a reference to the Spring {@link BeanFactory} in which this {@link FactoryBean} was declared.
*
* @return a reference to the declaring Spring {@link BeanFactory}.
* @see org.springframework.beans.factory.BeanFactoryAware#setBeanFactory(BeanFactory)
* @see org.springframework.beans.factory.BeanFactory
*/
public BeanFactory getBeanFactory() {
return this.beanFactory;
}
/**
* Sets the {@link String bean name} assigned to this {@link FactoryBean} as declared in the Spring container.
*
* @param name {@link String bean name} assigned to this {@link FactoryBean} as declared in the Spring container.
* @see org.springframework.beans.factory.BeanNameAware#setBeanName(String)
* @see java.lang.String
*/
@Override
public void setBeanName(String name) {
this.beanName = name;
}
/**
* Returns the {@link String bean name} assigned to this {@link FactoryBean} as declared in the Spring container.
*
* @return the {@link String bean name} assigned to this {@link FactoryBean} as declared in the Spring container.
* @see org.springframework.beans.factory.BeanNameAware#setBeanName(String)
* @see java.lang.String
*/
public String getBeanName() {
return this.beanName;
}
/**
* Returns a reference to the {@link Log} used by this {@link FactoryBean} to log {@link String messages}.
*
* @return a reference to the {@link Log} used by this {@link FactoryBean} to log {@link String messages}.
* @see org.apache.commons.logging.Log
*/
protected Log getLog() {
return this.log;
}
/**
* Indicates that this {@link FactoryBean} produces a single bean instance.
*
* @return {@literal true} by default.
* @see org.springframework.beans.factory.FactoryBean#isSingleton()
*/
@Override
public boolean isSingleton() {
return DEFAULT_SINGLETON;
}
/**
* Logs the {@link String message} formatted with the array of {@link Object arguments} at debug level.
*
* @param message {@link String} containing the message to log.
* @param args array of {@link Object arguments} used to format the {@code message}.
* @see #logDebug(Supplier)
*/
protected void logDebug(String message, Object... args) {
logDebug(() -> String.format(message, args));
}
/**
* Logs the {@link String message} supplied by the given {@link Supplier} at debug level.
*
* @param message {@link Supplier} containing the {@link String message} and arguments to log.
* @see org.apache.commons.logging.Log#isDebugEnabled()
* @see org.apache.commons.logging.Log#debug(Object)
* @see #getLog()
*/
protected void logDebug(Supplier<String> message) {
Optional.ofNullable(getLog())
.filter(Log::isDebugEnabled)
.ifPresent(log -> log.debug(message.get()));
}
/**
* Logs the {@link String message} formatted with the array of {@link Object arguments} at info level.
*
* @param message {@link String} containing the message to log.
* @param args array of {@link Object arguments} used to format the {@code message}.
* @see #logInfo(Supplier)
*/
protected void logInfo(String message, Object... args) {
logInfo(() -> String.format(message, args));
}
/**
* Logs the {@link String message} supplied by the given {@link Supplier} at info level.
*
* @param message {@link Supplier} containing the {@link String message} and arguments to log.
* @see org.apache.commons.logging.Log#isInfoEnabled()
* @see org.apache.commons.logging.Log#info(Object)
* @see #getLog()
*/
protected void logInfo(Supplier<String> message) {
Optional.ofNullable(getLog())
.filter(Log::isInfoEnabled)
.ifPresent(log -> log.info(message.get()));
}
}

View File

@@ -17,6 +17,8 @@
package org.springframework.data.gemfire.util;
import java.util.Optional;
import org.apache.geode.cache.Cache;
import org.apache.geode.cache.CacheClosedException;
import org.apache.geode.cache.CacheFactory;
@@ -29,11 +31,10 @@ import org.apache.geode.internal.cache.GemFireCacheImpl;
import org.springframework.util.StringUtils;
/**
* CacheUtils is an abstract utility class encapsulating common operations for working with GemFire Cache
* and ClientCache instances.
* {@link CacheUtils} is an abstract utility class encapsulating common operations for working with
* {@link Cache} and {@link ClientCache} instances.
*
* @author John Blum
* @see org.springframework.data.gemfire.util.DistributedSystemUtils
* @see org.apache.geode.cache.Cache
* @see org.apache.geode.cache.CacheFactory
* @see org.apache.geode.cache.GemFireCache
@@ -42,6 +43,7 @@ import org.springframework.util.StringUtils;
* @see org.apache.geode.cache.client.ClientCacheFactory
* @see org.apache.geode.distributed.DistributedSystem
* @see org.apache.geode.internal.cache.GemFireCacheImpl
* @see org.springframework.data.gemfire.util.DistributedSystemUtils
* @since 1.8.0
*/
@SuppressWarnings("unused")
@@ -52,6 +54,7 @@ public abstract class CacheUtils extends DistributedSystemUtils {
/* (non-Javadoc) */
@SuppressWarnings("all")
public static boolean isClient(GemFireCache cache) {
boolean client = (cache instanceof ClientCache);
if (cache instanceof GemFireCacheImpl) {
@@ -63,6 +66,7 @@ public abstract class CacheUtils extends DistributedSystemUtils {
/* (non-Javadoc) */
public static boolean isDurable(ClientCache clientCache) {
DistributedSystem distributedSystem = getDistributedSystem(clientCache);
// NOTE technically the following code snippet would be more useful/valuable but is not "testable"!
@@ -75,6 +79,7 @@ public abstract class CacheUtils extends DistributedSystemUtils {
/* (non-Javadoc) */
@SuppressWarnings("all")
public static boolean isPeer(GemFireCache cache) {
boolean peer = (cache instanceof Cache);
if (cache instanceof GemFireCacheImpl) {
@@ -128,7 +133,7 @@ public abstract class CacheUtils extends DistributedSystemUtils {
/* (non-Javadoc) */
public static GemFireCache resolveGemFireCache() {
return defaultIfNull(getCache(), CacheUtils::getClientCache);
return Optional.<GemFireCache>ofNullable(getCache()).orElseGet(CacheUtils::getClientCache);
}
/* (non-Javadoc) */

View File

@@ -16,12 +16,10 @@
package org.springframework.data.gemfire;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.notNullValue;
import static org.hamcrest.Matchers.nullValue;
import static org.hamcrest.Matchers.sameInstance;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -58,11 +56,13 @@ import org.apache.geode.cache.control.ResourceManager;
import org.apache.geode.cache.util.GatewayConflictResolver;
import org.apache.geode.distributed.DistributedMember;
import org.apache.geode.distributed.DistributedSystem;
import org.apache.geode.distributed.Role;
import org.apache.geode.pdx.PdxSerializer;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.core.io.Resource;
import org.springframework.data.gemfire.support.GemfireBeanFactoryLocator;
@@ -74,13 +74,27 @@ import org.springframework.data.util.ReflectionUtils;
* @author John Blum
* @see org.junit.Rule
* @see org.junit.Test
* @see org.junit.runner.RunWith
* @see org.mockito.Mock
* @see org.mockito.Mockito
* @see org.springframework.data.gemfire.CacheFactoryBean
* @see org.mockito.junit.MockitoJUnitRunner
* @see org.apache.geode.cache.Cache
* @see org.apache.geode.cache.CacheFactory
* @see org.apache.geode.cache.CacheTransactionManager
* @see org.apache.geode.cache.GemFireCache
* @see org.apache.geode.distributed.DistributedMember
* @see org.apache.geode.distributed.DistributedSystem
* @see org.apache.geode.pdx.PdxSerializer
* @see org.springframework.beans.factory.BeanFactory
* @see org.springframework.data.gemfire.CacheFactoryBean
* @since 1.7.0
*/
@RunWith(MockitoJUnitRunner.class)
public class CacheFactoryBeanTest {
@Mock
private Cache mockCache;
@Rule
public ExpectedException exception = ExpectedException.none();
@@ -90,7 +104,9 @@ public class CacheFactoryBeanTest {
final Properties gemfireProperties = new Properties();
CacheFactoryBean cacheFactoryBean = new CacheFactoryBean() {
@Override protected void postProcessBeforeCacheInitialization(Properties actualGemfireProperties) {
@Override
protected void postProcessBeforeCacheInitialization(Properties actualGemfireProperties) {
assertThat(actualGemfireProperties, is(sameInstance(gemfireProperties)));
postProcessBeforeCacheInitializationCalled.set(true);
}
@@ -178,7 +194,7 @@ public class CacheFactoryBeanTest {
final AtomicBoolean initCalled = new AtomicBoolean(false);
CacheFactoryBean cacheFactoryBean = new CacheFactoryBean() {
@Override Cache init() throws Exception {
@Override Cache init() {
initCalled.set(true);
return mockCache;
}
@@ -203,6 +219,7 @@ public class CacheFactoryBeanTest {
}
@Test
@SuppressWarnings("deprecation")
public void init() throws Exception {
BeanFactory mockBeanFactory = mock(BeanFactory.class);
Cache mockCache = mock(Cache.class);
@@ -227,8 +244,8 @@ public class CacheFactoryBeanTest {
when(mockDistributedSystem.getDistributedMember()).thenReturn(mockDistributedMember);
when(mockDistributedSystem.getName()).thenReturn("MockDistributedSystem");
when(mockDistributedMember.getId()).thenReturn("MockDistributedMember");
when(mockDistributedMember.getGroups()).thenReturn(Collections.<String>emptyList());
when(mockDistributedMember.getRoles()).thenReturn(Collections.<Role>emptySet());
when(mockDistributedMember.getGroups()).thenReturn(Collections.emptyList());
when(mockDistributedMember.getRoles()).thenReturn(Collections.emptySet());
when(mockDistributedMember.getHost()).thenReturn("skullbox");
when(mockDistributedMember.getProcessId()).thenReturn(12345);
@@ -401,8 +418,7 @@ public class CacheFactoryBeanTest {
public void prepareFactoryWithUnspecifiedPdxOptions() {
CacheFactory mockCacheFactory = mock(CacheFactory.class);
assertThat((CacheFactory) new CacheFactoryBean().prepareFactory(mockCacheFactory),
is(sameInstance(mockCacheFactory)));
assertThat(new CacheFactoryBean().prepareFactory(mockCacheFactory), is(sameInstance(mockCacheFactory)));
verify(mockCacheFactory, never()).setPdxDiskStore(any(String.class));
verify(mockCacheFactory, never()).setPdxIgnoreUnreadFields(any(Boolean.class));
@@ -421,8 +437,7 @@ public class CacheFactoryBeanTest {
CacheFactory mockCacheFactory = mock(CacheFactory.class);
assertThat((CacheFactory) cacheFactoryBean.prepareFactory(mockCacheFactory),
is(sameInstance(mockCacheFactory)));
assertThat(cacheFactoryBean.prepareFactory(mockCacheFactory), is(sameInstance(mockCacheFactory)));
verify(mockCacheFactory, never()).setPdxDiskStore(any(String.class));
verify(mockCacheFactory, times(1)).setPdxIgnoreUnreadFields(eq(false));
@@ -443,8 +458,7 @@ public class CacheFactoryBeanTest {
CacheFactory mockCacheFactory = mock(CacheFactory.class);
assertThat((CacheFactory) cacheFactoryBean.prepareFactory(mockCacheFactory),
is(sameInstance(mockCacheFactory)));
assertThat(cacheFactoryBean.prepareFactory(mockCacheFactory), is(sameInstance(mockCacheFactory)));
verify(mockCacheFactory, times(1)).setPdxDiskStore(eq("testPdxDiskStoreName"));
verify(mockCacheFactory, times(1)).setPdxIgnoreUnreadFields(eq(false));
@@ -453,52 +467,25 @@ public class CacheFactoryBeanTest {
verify(mockCacheFactory, times(1)).setPdxSerializer(any(PdxSerializer.class));
}
@Test
public void prepareFactoryWithInvalidTypeForPdxSerializer() {
CacheFactory mockCacheFactory = mock(CacheFactory.class);
Object pdxSerializer = new Object();
try {
CacheFactoryBean cacheFactoryBean = new CacheFactoryBean();
cacheFactoryBean.setPdxSerializer(pdxSerializer);
cacheFactoryBean.setPdxIgnoreUnreadFields(false);
cacheFactoryBean.setPdxReadSerialized(true);
exception.expect(IllegalArgumentException.class);
exception.expectCause(is(nullValue(Throwable.class)));
exception.expectMessage(containsString(String.format(
"[%1$s] of type [java.lang.Object] is not a PdxSerializer", pdxSerializer)));
cacheFactoryBean.prepareFactory(mockCacheFactory);
}
finally {
verify(mockCacheFactory, never()).setPdxSerializer(any(PdxSerializer.class));
verify(mockCacheFactory, never()).setPdxDiskStore(any(String.class));
verify(mockCacheFactory, never()).setPdxIgnoreUnreadFields(any(Boolean.class));
verify(mockCacheFactory, never()).setPdxPersistent(any(Boolean.class));
verify(mockCacheFactory, never()).setPdxReadSerialized(any(Boolean.class));
}
}
@Test
public void createCacheWithExistingCache() throws Exception {
Cache mockCache = mock(Cache.class);
CacheFactory mockCacheFactory = mock(CacheFactory.class);
CacheFactoryBean cacheFactoryBean = new CacheFactoryBean();
cacheFactoryBean.setCache(mockCache);
Cache actualCache = cacheFactoryBean.createCache(null);
assertThat(cacheFactoryBean.getCache(), is(sameInstance(mockCache)));
Cache actualCache = cacheFactoryBean.createCache(mockCacheFactory);
assertThat(actualCache, is(sameInstance(mockCache)));
verify(mockCacheFactory, never()).create();
verifyZeroInteractions(mockCache);
}
@Test
public void createCacheWithNoExistingCache() {
Cache mockCache = mock(Cache.class);
CacheFactory mockCacheFactory = mock(CacheFactory.class);
when(mockCacheFactory.create()).thenReturn(mockCache);
@@ -519,13 +506,17 @@ public class CacheFactoryBeanTest {
CacheFactoryBean cacheFactoryBean = new CacheFactoryBean();
cacheFactoryBean.setCriticalHeapPercentage(200.0f);
cacheFactoryBean.postProcess(null);
cacheFactoryBean.postProcess(mockCache);
}
catch (IllegalArgumentException expected) {
assertEquals("'criticalHeapPercentage' (200.0) is invalid; must be > 0.0 and <= 100.0",
assertEquals("criticalHeapPercentage [200.0] is not valid; must be > 0.0 and <= 100.0",
expected.getMessage());
throw expected;
}
finally {
verifyZeroInteractions(mockCache);
}
}
@Test(expected = IllegalArgumentException.class)
@@ -534,19 +525,23 @@ public class CacheFactoryBeanTest {
CacheFactoryBean cacheFactoryBean = new CacheFactoryBean();
cacheFactoryBean.setEvictionHeapPercentage(-75.0f);
cacheFactoryBean.postProcess(null);
cacheFactoryBean.postProcess(mockCache);
}
catch (IllegalArgumentException expected) {
assertEquals("'evictionHeapPercentage' (-75.0) is invalid; must be > 0.0 and <= 100.0",
assertEquals("evictionHeapPercentage [-75.0] is not valid; must be > 0.0 and <= 100.0",
expected.getMessage());
throw expected;
}
finally {
verifyZeroInteractions(mockCache);
}
}
@Test
@SuppressWarnings("unchecked")
public void getObjectType() {
assertThat((Class<Cache>) new CacheFactoryBean().getObjectType(), is(equalTo(Cache.class)));
assertThat(new CacheFactoryBean().getObjectType(), is(equalTo(Cache.class)));
}
@Test
@@ -695,10 +690,10 @@ public class CacheFactoryBeanTest {
assertTrue(Boolean.FALSE.equals(TestUtils.readField("useBeanFactoryLocator", cacheFactoryBean)));
assertTrue(Boolean.FALSE.equals(TestUtils.readField("close", cacheFactoryBean)));
assertTrue(cacheFactoryBean.getCopyOnRead());
assertEquals(0.95f, cacheFactoryBean.getCriticalHeapPercentage().floatValue(), 0.0f);
assertEquals(0.95f, cacheFactoryBean.getCriticalHeapPercentage(), 0.0f);
assertNotNull(cacheFactoryBean.getDynamicRegionSupport());
assertTrue(cacheFactoryBean.getEnableAutoReconnect());
assertEquals(0.70f, cacheFactoryBean.getEvictionHeapPercentage().floatValue(), 0.0f);
assertEquals(0.70f, cacheFactoryBean.getEvictionHeapPercentage(), 0.0f);
assertSame(mockGatewayConflictResolver, cacheFactoryBean.getGatewayConflictResolver());
assertNotNull(cacheFactoryBean.getJndiDataSources());
assertEquals(1, cacheFactoryBean.getJndiDataSources().size());

View File

@@ -22,11 +22,11 @@ import org.junit.Before;
import org.junit.Test;
/**
* The DiskStoreFactoryBeanTest class is a test suite of test cases testing the contract and functionality of the
* DiskStoreFactoryBean class.
* Unit tests for {@link DiskStoreFactoryBean}.
*
* @author John Blum
* @see org.junit.Test
* @see org.apache.geode.cache.DiskStore
* @see org.springframework.data.gemfire.DiskStoreFactoryBean
* @since 1.3.4
*/
@@ -58,7 +58,7 @@ public class DiskStoreFactoryBeanTest {
}
catch (IllegalArgumentException expected) {
assertEquals(String.format("The DiskStore's (%1$s) compaction threshold (%2$d) must be an integer value between 0 and 100 inclusive.",
factoryBean.getName(), -1), expected.getMessage());
factoryBean.resolveDiskStoreName(), -1), expected.getMessage());
throw expected;
}
}
@@ -70,7 +70,7 @@ public class DiskStoreFactoryBeanTest {
}
catch (IllegalArgumentException expected) {
assertEquals(String.format("The DiskStore's (%1$s) compaction threshold (%2$d) must be an integer value between 0 and 100 inclusive.",
factoryBean.getName(), 101), expected.getMessage());
factoryBean.resolveDiskStoreName(), 101), expected.getMessage());
throw expected;
}
}
@@ -88,7 +88,7 @@ public class DiskStoreFactoryBeanTest {
catch (IllegalArgumentException expected) {
assertEquals(String.format(
"The DiskStore's (%1$s) compaction threshold (%2$d) must be an integer value between 0 and 100 inclusive.",
factoryBean.getName(), 200), expected.getMessage());
factoryBean.resolveDiskStoreName(), 200), expected.getMessage());
throw expected;
}
}
@@ -99,9 +99,8 @@ public class DiskStoreFactoryBeanTest {
factoryBean.afterPropertiesSet();
}
catch (IllegalStateException expected) {
assertEquals("A reference to the GemFire Cache must be set for Disk Store 'testDiskStore'.", expected.getMessage());
assertEquals("Cache is required to create DiskStore [testDiskStore]", expected.getMessage());
throw expected;
}
}
}

View File

@@ -22,10 +22,24 @@ import static org.hamcrest.CoreMatchers.isA;
import static org.hamcrest.CoreMatchers.nullValue;
import static org.hamcrest.CoreMatchers.sameInstance;
import static org.hamcrest.Matchers.startsWith;
import static org.junit.Assert.*;
import static org.mockito.ArgumentMatchers.*;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.*;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.same;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
import java.util.ArrayList;
import java.util.Arrays;
@@ -55,16 +69,14 @@ import org.springframework.data.gemfire.config.xml.GemfireConstants;
import org.springframework.data.util.ReflectionUtils;
/**
* The IndexFactoryBeanTest class is a test suite of test cases testing the contract and functionality
* of the IndexFactoryBean class.
* Unit tests for {@link IndexFactoryBean}.
*
* @author John Blum
* @see org.junit.Test
* @see org.springframework.data.gemfire.IndexFactoryBean
* @see org.apache.geode.cache.Cache
* @see org.apache.geode.cache.client.ClientCache
* @see org.apache.geode.cache.query.Index
* @see org.apache.geode.cache.query.QueryService
* @see org.springframework.data.gemfire.IndexFactoryBean
* @since 1.5.2
*/
public class IndexFactoryBeanTest {
@@ -136,10 +148,12 @@ public class IndexFactoryBeanTest {
@Test(expected = IllegalArgumentException.class)
public void afterPropertiesSetWithNullCache() throws Exception {
try {
new IndexFactoryBean().afterPropertiesSet();
IndexFactoryBean indexFactoryBean = new IndexFactoryBean();
indexFactoryBean.setName("TestIndex");
indexFactoryBean.afterPropertiesSet();
}
catch (IllegalArgumentException expected) {
assertEquals("The GemFire Cache reference must not be null!", expected.getMessage());
assertEquals("Cache is required", expected.getMessage());
throw expected;
}
}
@@ -154,6 +168,7 @@ public class IndexFactoryBeanTest {
};
indexFactoryBean.setCache(mockCache);
indexFactoryBean.setName("TestIndex");
indexFactoryBean.afterPropertiesSet();
}
catch (IllegalArgumentException expected) {
@@ -165,10 +180,12 @@ public class IndexFactoryBeanTest {
@Test(expected = IllegalArgumentException.class)
public void afterPropertiesSetWithUnspecifiedExpression() throws Exception {
try {
newIndexFactoryBean().afterPropertiesSet();
IndexFactoryBean indexFactoryBean = newIndexFactoryBean();
indexFactoryBean.setName("TestIndex");
indexFactoryBean.afterPropertiesSet();
}
catch (IllegalArgumentException expected) {
assertEquals("Index 'expression' is required", expected.getMessage());
assertEquals("Index expression is required", expected.getMessage());
throw expected;
}
}
@@ -177,11 +194,12 @@ public class IndexFactoryBeanTest {
public void afterPropertiesSetWithUnspecifiedFromClause() throws Exception {
expectedException.expect(IllegalArgumentException.class);
expectedException.expectCause(is(nullValue(Throwable.class)));
expectedException.expectMessage("Index 'from clause' is required");
expectedException.expectMessage("Index from clause is required");
IndexFactoryBean indexFactoryBean = newIndexFactoryBean();
indexFactoryBean.setExpression("id");
indexFactoryBean.setName("TestIndex");
indexFactoryBean.afterPropertiesSet();
}
@@ -194,7 +212,7 @@ public class IndexFactoryBeanTest {
indexFactoryBean.afterPropertiesSet();
}
catch (IllegalArgumentException expected) {
assertEquals("Index 'name' is required", expected.getMessage());
assertEquals("Index name is required", expected.getMessage());
throw expected;
}
}
@@ -211,7 +229,7 @@ public class IndexFactoryBeanTest {
indexFactoryBean.afterPropertiesSet();
}
catch (IllegalArgumentException expected) {
assertEquals("'imports' are not supported with a KEY Index", expected.getMessage());
assertEquals("imports are not supported with a KEY Index", expected.getMessage());
throw expected;
}
}
@@ -1076,5 +1094,4 @@ public class IndexFactoryBeanTest {
throw expected;
}
}
}

View File

@@ -169,7 +169,7 @@ public class PartitionedRegionFactoryBeanTest {
factoryBean.resolveDataPolicy(mockRegionFactory, true, "PARTITION");
}
catch (IllegalArgumentException e) {
assertEquals("Data Policy 'PARTITION' is invalid when persistent is true.", e.getMessage());
assertEquals("Data Policy [PARTITION] is invalid when persistent is true.", e.getMessage());
throw e;
}
finally {
@@ -195,7 +195,7 @@ public class PartitionedRegionFactoryBeanTest {
factoryBean.resolveDataPolicy(mockRegionFactory, false, "PERSISTENT_PARTITION");
}
catch (IllegalArgumentException e) {
assertEquals("Data Policy 'PERSISTENT_PARTITION' is invalid when persistent is false.", e.getMessage());
assertEquals("Data Policy [PERSISTENT_PARTITION] is invalid when persistent is false.", e.getMessage());
throw e;
}
finally {
@@ -212,5 +212,4 @@ public class PartitionedRegionFactoryBeanTest {
factoryBean.resolveDataPolicy(mockRegionFactory, true, "PERSISTENT_PARTITION");
verify(mockRegionFactory).setDataPolicy(eq(DataPolicy.PERSISTENT_PARTITION));
}
}

View File

@@ -54,12 +54,10 @@ import org.springframework.data.gemfire.test.support.AbstractRegionFactoryBeanTe
import org.springframework.data.gemfire.util.ArrayUtils;
/**
* The RegionFactoryBeanTest class is a test suite of test cases testing the contract and functionality of the
* RegionFactoryBean class.
* Unit tests for {@link RegionFactoryBean}.
*
* @author David Turanski
* @author John Blum
* @see org.springframework.data.gemfire.RegionFactoryBean
* @see org.apache.geode.cache.Cache
* @see org.apache.geode.cache.DataPolicy
* @see org.apache.geode.cache.PartitionAttributes
@@ -67,6 +65,8 @@ import org.springframework.data.gemfire.util.ArrayUtils;
* @see org.apache.geode.cache.RegionAttributes
* @see org.apache.geode.cache.RegionFactory
* @see org.apache.geode.cache.RegionShortcut
* @see org.springframework.data.gemfire.RegionFactoryBean
* @see org.springframework.data.gemfire.test.support.AbstractRegionFactoryBeanTests
*/
@SuppressWarnings("unchecked")
public class RegionFactoryBeanTest extends AbstractRegionFactoryBeanTests {
@@ -122,7 +122,7 @@ public class RegionFactoryBeanTest extends AbstractRegionFactoryBeanTests {
@Override
public void verify() {
assertNotNull(this.exception);
assertEquals("Data Policy 'PERSISTENT_REPLICATE' is invalid when persistent is false.",
assertEquals("Data Policy [PERSISTENT_REPLICATE] is invalid when persistent is false.",
exception.getMessage());
}
};
@@ -191,7 +191,7 @@ public class RegionFactoryBeanTest extends AbstractRegionFactoryBeanTests {
factoryBean.assertDataPolicyAndPersistentAttributesAreCompatible(DataPolicy.REPLICATE);
}
catch (IllegalArgumentException expected) {
assertEquals("Data Policy 'REPLICATE' is invalid when persistent is true.", expected.getMessage());
assertEquals("Data Policy [REPLICATE] is invalid when persistent is true.", expected.getMessage());
throw expected;
}
}
@@ -204,7 +204,7 @@ public class RegionFactoryBeanTest extends AbstractRegionFactoryBeanTests {
factoryBean.assertDataPolicyAndPersistentAttributesAreCompatible(DataPolicy.PERSISTENT_PARTITION);
}
catch (IllegalArgumentException expected) {
assertEquals("Data Policy 'PERSISTENT_PARTITION' is invalid when persistent is false.",
assertEquals("Data Policy [PERSISTENT_PARTITION] is invalid when persistent is false.",
expected.getMessage());
throw expected;
}
@@ -715,7 +715,7 @@ public class RegionFactoryBeanTest extends AbstractRegionFactoryBeanTests {
factoryBean.resolveDataPolicy(mockRegionFactory, true, " ");
}
catch (IllegalArgumentException expected) {
assertEquals("Data Policy ' ' is invalid.", expected.getMessage());
assertEquals("Data Policy [ ] is invalid.", expected.getMessage());
throw expected;
}
finally {
@@ -734,7 +734,7 @@ public class RegionFactoryBeanTest extends AbstractRegionFactoryBeanTests {
factoryBean.resolveDataPolicy(mockRegionFactory, true, "");
}
catch (IllegalArgumentException expected) {
assertEquals("Data Policy '' is invalid.", expected.getMessage());
assertEquals("Data Policy [] is invalid.", expected.getMessage());
throw expected;
}
finally {
@@ -753,7 +753,7 @@ public class RegionFactoryBeanTest extends AbstractRegionFactoryBeanTests {
factoryBean.resolveDataPolicy(mockRegionFactory, true, "CSV");
}
catch (IllegalArgumentException expected) {
assertEquals("Data Policy 'CSV' is invalid.", expected.getMessage());
assertEquals("Data Policy [CSV] is invalid.", expected.getMessage());
throw expected;
}
finally {
@@ -787,7 +787,7 @@ public class RegionFactoryBeanTest extends AbstractRegionFactoryBeanTests {
factoryBean.resolveDataPolicy(mockRegionFactory, true, "EMPTY");
}
catch (IllegalArgumentException expected) {
assertEquals("Data Policy 'EMPTY' is invalid when persistent is true.", expected.getMessage());
assertEquals("Data Policy [EMPTY] is invalid when persistent is true.", expected.getMessage());
throw expected;
}
finally {
@@ -821,7 +821,7 @@ public class RegionFactoryBeanTest extends AbstractRegionFactoryBeanTests {
factoryBean.resolveDataPolicy(mockRegionFactory, false, "PERSISTENT_PARTITION");
}
catch (IllegalArgumentException expected) {
assertEquals("Data Policy 'PERSISTENT_PARTITION' is invalid when persistent is false.", expected.getMessage());
assertEquals("Data Policy [PERSISTENT_PARTITION] is invalid when persistent is false.", expected.getMessage());
throw expected;
}
finally {
@@ -843,7 +843,7 @@ public class RegionFactoryBeanTest extends AbstractRegionFactoryBeanTests {
"Setting the 'persistent' attribute to TRUE and 'Data Policy' to PARTITION should have thrown an IllegalArgumentException!");
}
catch (IllegalArgumentException expected) {
assertEquals("Data Policy 'PARTITION' is invalid when persistent is true.", expected.getMessage());
assertEquals("Data Policy [PARTITION] is invalid when persistent is true.", expected.getMessage());
throw expected;
}
finally {
@@ -913,7 +913,7 @@ public class RegionFactoryBeanTest extends AbstractRegionFactoryBeanTests {
factoryBean.resolveDataPolicy(mockRegionFactory, false, (String) null);
}
catch (IllegalArgumentException expected) {
assertEquals("Data Policy 'PERSISTENT_PARTITION' is invalid when persistent is false.", expected.getMessage());
assertEquals("Data Policy [PERSISTENT_PARTITION] is invalid when persistent is false.", expected.getMessage());
throw expected;
}
finally {
@@ -934,7 +934,7 @@ public class RegionFactoryBeanTest extends AbstractRegionFactoryBeanTests {
factoryBean.resolveDataPolicy(mockRegionFactory, true, (String) null);
}
catch (IllegalArgumentException expected) {
assertEquals("Data Policy 'PARTITION' is invalid when persistent is true.", expected.getMessage());
assertEquals("Data Policy [PARTITION] is invalid when persistent is true.", expected.getMessage());
throw expected;
}
finally {
@@ -996,7 +996,7 @@ public class RegionFactoryBeanTest extends AbstractRegionFactoryBeanTests {
fail("Setting the 'persistent' attribute to FALSE and 'Data Policy' to PERSISTENT_REPLICATE should have thrown an IllegalArgumentException!");
}
catch (IllegalArgumentException expected) {
assertEquals("Data Policy 'PERSISTENT_REPLICATE' is invalid when persistent is false.", expected.getMessage());
assertEquals("Data Policy [PERSISTENT_REPLICATE] is invalid when persistent is false.", expected.getMessage());
throw expected;
}
finally {
@@ -1017,7 +1017,7 @@ public class RegionFactoryBeanTest extends AbstractRegionFactoryBeanTests {
fail("Setting the 'persistent' attribute to TRUE and 'Data Policy' to REPLICATE should have thrown an IllegalArgumentException!");
}
catch (IllegalArgumentException expected) {
assertEquals("Data Policy 'REPLICATE' is invalid when persistent is true.", expected.getMessage());
assertEquals("Data Policy [REPLICATE] is invalid when persistent is true.", expected.getMessage());
throw expected;
}
finally {

View File

@@ -168,7 +168,7 @@ public class ReplicatedRegionFactoryBeanTest {
factoryBean.resolveDataPolicy(mockRegionFactory, true, "empty");
}
catch (IllegalArgumentException e) {
assertEquals("Data Policy 'EMPTY' is invalid when persistent is true.", e.getMessage());
assertEquals("Data Policy [EMPTY] is invalid when persistent is true.", e.getMessage());
throw e;
}
finally {
@@ -202,7 +202,7 @@ public class ReplicatedRegionFactoryBeanTest {
factoryBean.resolveDataPolicy(mockRegionFactory, true, "REPLICATE");
}
catch (IllegalArgumentException e) {
assertEquals("Data Policy 'REPLICATE' is invalid when persistent is true.", e.getMessage());
assertEquals("Data Policy [REPLICATE] is invalid when persistent is true.", e.getMessage());
throw e;
}
finally {
@@ -228,7 +228,7 @@ public class ReplicatedRegionFactoryBeanTest {
factoryBean.resolveDataPolicy(mockRegionFactory, false, "PERSISTENT_REPLICATE");
}
catch (IllegalArgumentException e) {
assertEquals("Data Policy 'PERSISTENT_REPLICATE' is invalid when persistent is false.", e.getMessage());
assertEquals("Data Policy [PERSISTENT_REPLICATE] is invalid when persistent is false.", e.getMessage());
throw e;
}
finally {
@@ -245,5 +245,4 @@ public class ReplicatedRegionFactoryBeanTest {
factoryBean.resolveDataPolicy(mockRegionFactory, true, "PERSISTENT_REPLICATE");
verify(mockRegionFactory).setDataPolicy(eq(DataPolicy.PERSISTENT_REPLICATE));
}
}

View File

@@ -16,7 +16,6 @@
package org.springframework.data.gemfire.client;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.instanceOf;
import static org.hamcrest.CoreMatchers.is;
@@ -42,6 +41,7 @@ import java.net.InetSocketAddress;
import java.util.Arrays;
import java.util.Collections;
import java.util.Map;
import java.util.Optional;
import java.util.Properties;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -65,15 +65,21 @@ import org.springframework.data.gemfire.util.ArrayUtils;
import org.springframework.data.gemfire.util.DistributedSystemUtils;
/**
* The ClientCacheFactoryBeanTest class is a test suite of test cases testing the contract and functionality
* of the SDG ClientCacheFactoryBean class.
* Unit tests for {@link ClientCacheFactoryBean}
*
* @author John Blum
* @see org.mockito.Mockito
* @see java.net.InetSocketAddress
* @see org.junit.Rule
* @see org.junit.Test
* @see org.springframework.data.gemfire.client.ClientCacheFactoryBean
* @see org.mockito.Mockito
* @see org.apache.geode.cache.GemFireCache
* @see org.apache.geode.cache.client.ClientCache
* @see org.apache.geode.cache.client.ClientCacheFactory
* @see org.apache.geode.cache.client.Pool
* @see org.apache.geode.distributed.DistributedSystem
* @see org.apache.geode.pdx.PdxSerializer
* @see org.springframework.beans.factory.BeanFactory
* @see org.springframework.data.gemfire.client.ClientCacheFactoryBean
* @since 1.7.0
*/
public class ClientCacheFactoryBeanTest {
@@ -81,24 +87,25 @@ public class ClientCacheFactoryBeanTest {
@Rule
public ExpectedException exception = ExpectedException.none();
protected Properties createProperties(String key, String value) {
private Properties createProperties(String key, String value) {
return addProperty(null, key, value);
}
protected Properties addProperty(Properties properties, String key, String value) {
properties = (properties != null ? properties : new Properties());
@SuppressWarnings("all")
private Properties addProperty(Properties properties, String key, String value) {
properties = Optional.ofNullable(properties).orElseGet(Properties::new);
properties.setProperty(key, value);
return properties;
}
protected ConnectionEndpoint newConnectionEndpoint(String host, int port) {
private ConnectionEndpoint newConnectionEndpoint(String host, int port) {
return new ConnectionEndpoint(host, port);
}
@Test
@SuppressWarnings("unchecked")
public void getObjectType() {
assertThat((Class<ClientCache>) new ClientCacheFactoryBean().getObjectType(), is(equalTo(ClientCache.class)));
assertThat(new ClientCacheFactoryBean().getObjectType(), is(equalTo(ClientCache.class)));
}
@Test
@@ -252,18 +259,21 @@ public class ClientCacheFactoryBeanTest {
ClientCacheFactory mockClientCacheFactory = mock(ClientCacheFactory.class);
ClientCacheFactoryBean clientCacheFactoryBean = new ClientCacheFactoryBean() {
@Override ClientCacheFactory initializePdx(final ClientCacheFactory clientCacheFactory) {
@Override
ClientCacheFactory initializePdx(ClientCacheFactory clientCacheFactory) {
initializePdxCalled.set(true);
return clientCacheFactory;
}
@Override ClientCacheFactory initializePool(final ClientCacheFactory clientCacheFactory) {
@Override
ClientCacheFactory initializePool(final ClientCacheFactory clientCacheFactory) {
initializePoolCalled.set(true);
return clientCacheFactory;
}
};
assertThat((ClientCacheFactory) clientCacheFactoryBean.prepareFactory(mockClientCacheFactory),
assertThat(clientCacheFactoryBean.prepareFactory(mockClientCacheFactory),
is(sameInstance(mockClientCacheFactory)));
assertThat(initializePdxCalled.get(), is(true));
assertThat(initializePoolCalled.get(), is(true));
@@ -285,7 +295,7 @@ public class ClientCacheFactoryBeanTest {
assertThat(clientCacheFactoryBean.getPdxIgnoreUnreadFields(), is(false));
assertThat(clientCacheFactoryBean.getPdxPersistent(), is(true));
assertThat(clientCacheFactoryBean.getPdxReadSerialized(), is(false));
assertThat((PdxSerializer) clientCacheFactoryBean.getPdxSerializer(), is(sameInstance(mockPdxSerializer)));
assertThat(clientCacheFactoryBean.getPdxSerializer(), is(sameInstance(mockPdxSerializer)));
ClientCacheFactory mockClientCacheFactory = mock(ClientCacheFactory.class);
@@ -342,51 +352,19 @@ public class ClientCacheFactoryBeanTest {
verifyZeroInteractions(mockClientCacheFactory);
}
@Test
public void initializePdxUsingIllegalTypeForPdxSerializer() {
ClientCacheFactory mockClientCacheFactory = mock(ClientCacheFactory.class);
try {
ClientCacheFactoryBean clientCacheFactoryBean = new ClientCacheFactoryBean();
Object pdxSerializer = new Object();
clientCacheFactoryBean.setPdxSerializer(pdxSerializer);
clientCacheFactoryBean.setPdxReadSerialized(false);
clientCacheFactoryBean.setPdxPersistent(true);
clientCacheFactoryBean.setPdxIgnoreUnreadFields(false);
clientCacheFactoryBean.setPdxDiskStoreName("test");
exception.expect(IllegalArgumentException.class);
exception.expectCause(is(nullValue(Throwable.class)));
exception.expectMessage(containsString(String.format(
"[%1$s] of type [java.lang.Object] is not a PdxSerializer", pdxSerializer)));
assertThat(clientCacheFactoryBean.initializePdx(mockClientCacheFactory),
is(sameInstance(mockClientCacheFactory)));
}
finally {
verify(mockClientCacheFactory, never()).setPdxSerializer(any(PdxSerializer.class));
verify(mockClientCacheFactory, never()).setPdxDiskStore(any(String.class));
verify(mockClientCacheFactory, never()).setPdxIgnoreUnreadFields(any(Boolean.class));
verify(mockClientCacheFactory, never()).setPdxPersistent(any(Boolean.class));
verify(mockClientCacheFactory, never()).setPdxReadSerialized(any(Boolean.class));
}
}
@Test
public void initializePoolWithPool() {
Pool mockPool = mock(Pool.class);
when(mockPool.getFreeConnectionTimeout()).thenReturn(10000);
when(mockPool.getIdleTimeout()).thenReturn(120000l);
when(mockPool.getIdleTimeout()).thenReturn(120000L);
when(mockPool.getLoadConditioningInterval()).thenReturn(30000);
when(mockPool.getLocators()).thenReturn(Collections.<InetSocketAddress>emptyList());
when(mockPool.getLocators()).thenReturn(Collections.emptyList());
when(mockPool.getMaxConnections()).thenReturn(100);
when(mockPool.getMinConnections()).thenReturn(10);
when(mockPool.getMultiuserAuthentication()).thenReturn(true);
when(mockPool.getPRSingleHopEnabled()).thenReturn(true);
when(mockPool.getPingInterval()).thenReturn(15000l);
when(mockPool.getPingInterval()).thenReturn(15000L);
when(mockPool.getReadTimeout()).thenReturn(20000);
when(mockPool.getRetryAttempts()).thenReturn(1);
when(mockPool.getServerGroup()).thenReturn("TestGroup");
@@ -453,13 +431,13 @@ public class ClientCacheFactoryBeanTest {
verify(mockPool, times(1)).getSubscriptionRedundancy();
verify(mockPool, times(1)).getThreadLocalConnections();
verify(mockClientCacheFactory, times(1)).setPoolFreeConnectionTimeout(eq(10000));
verify(mockClientCacheFactory, times(1)).setPoolIdleTimeout(eq(120000l));
verify(mockClientCacheFactory, times(1)).setPoolIdleTimeout(eq(120000L));
verify(mockClientCacheFactory, times(1)).setPoolLoadConditioningInterval(eq(30000));
verify(mockClientCacheFactory, times(1)).setPoolMaxConnections(eq(100));
verify(mockClientCacheFactory, times(1)).setPoolMinConnections(eq(10));
verify(mockClientCacheFactory, times(1)).setPoolMultiuserAuthentication(eq(true));
verify(mockClientCacheFactory, times(1)).setPoolPRSingleHopEnabled(eq(true));
verify(mockClientCacheFactory, times(1)).setPoolPingInterval(eq(15000l));
verify(mockClientCacheFactory, times(1)).setPoolPingInterval(eq(15000L));
verify(mockClientCacheFactory, times(1)).setPoolReadTimeout(eq(20000));
verify(mockClientCacheFactory, times(1)).setPoolRetryAttempts(eq(1));
verify(mockClientCacheFactory, times(1)).setPoolServerGroup(eq("TestGroup"));
@@ -482,12 +460,12 @@ public class ClientCacheFactoryBeanTest {
ClientCacheFactoryBean clientCacheFactoryBean = new ClientCacheFactoryBean();
clientCacheFactoryBean.setFreeConnectionTimeout(5000);
clientCacheFactoryBean.setIdleTimeout(300000l);
clientCacheFactoryBean.setIdleTimeout(300000L);
clientCacheFactoryBean.setLoadConditioningInterval(120000);
clientCacheFactoryBean.setMaxConnections(99);
clientCacheFactoryBean.setMinConnections(9);
clientCacheFactoryBean.setMultiUserAuthentication(true);
clientCacheFactoryBean.setPingInterval(15000l);
clientCacheFactoryBean.setPingInterval(15000L);
clientCacheFactoryBean.setPool(mockPool);
clientCacheFactoryBean.setPrSingleHopEnabled(true);
clientCacheFactoryBean.setReadTimeout(20000);
@@ -504,13 +482,13 @@ public class ClientCacheFactoryBeanTest {
newConnectionEndpoint("skullbox", 10334));
assertThat(clientCacheFactoryBean.getFreeConnectionTimeout(), is(equalTo(5000)));
assertThat(clientCacheFactoryBean.getIdleTimeout(), is(equalTo(300000l)));
assertThat(clientCacheFactoryBean.getIdleTimeout(), is(equalTo(300000L)));
assertThat(clientCacheFactoryBean.getLoadConditioningInterval(), is(equalTo(120000)));
assertThat(clientCacheFactoryBean.getLocators().size(), is(equalTo(2)));
assertThat(clientCacheFactoryBean.getMaxConnections(), is(equalTo(99)));
assertThat(clientCacheFactoryBean.getMinConnections(), is(equalTo(9)));
assertThat(clientCacheFactoryBean.getMultiUserAuthentication(), is(equalTo(true)));
assertThat(clientCacheFactoryBean.getPingInterval(), is(equalTo(15000l)));
assertThat(clientCacheFactoryBean.getPingInterval(), is(equalTo(15000L)));
assertThat(clientCacheFactoryBean.getPool(), is(sameInstance(mockPool)));
assertThat(clientCacheFactoryBean.getPoolName(), is(nullValue()));
assertThat(clientCacheFactoryBean.getPrSingleHopEnabled(), is(equalTo(true)));
@@ -533,12 +511,12 @@ public class ClientCacheFactoryBeanTest {
verifyZeroInteractions(mockPool);
verify(mockClientCacheFactory, times(1)).setPoolFreeConnectionTimeout(eq(5000));
verify(mockClientCacheFactory, times(1)).setPoolIdleTimeout(eq(300000l));
verify(mockClientCacheFactory, times(1)).setPoolIdleTimeout(eq(300000L));
verify(mockClientCacheFactory, times(1)).setPoolLoadConditioningInterval(eq(120000));
verify(mockClientCacheFactory, times(1)).setPoolMaxConnections(eq(99));
verify(mockClientCacheFactory, times(1)).setPoolMinConnections(eq(9));
verify(mockClientCacheFactory, times(1)).setPoolMultiuserAuthentication(eq(true));
verify(mockClientCacheFactory, times(1)).setPoolPingInterval(eq(15000l));
verify(mockClientCacheFactory, times(1)).setPoolPingInterval(eq(15000L));
verify(mockClientCacheFactory, times(1)).setPoolPRSingleHopEnabled(eq(true));
verify(mockClientCacheFactory, times(1)).setPoolReadTimeout(eq(20000));
verify(mockClientCacheFactory, times(1)).setPoolRetryAttempts(eq(2));
@@ -560,13 +538,13 @@ public class ClientCacheFactoryBeanTest {
Pool mockPool = mock(Pool.class);
when(mockPool.getFreeConnectionTimeout()).thenReturn(5000);
when(mockPool.getIdleTimeout()).thenReturn(120000l);
when(mockPool.getIdleTimeout()).thenReturn(120000L);
when(mockPool.getLoadConditioningInterval()).thenReturn(300000);
when(mockPool.getLocators()).thenReturn(Collections.<InetSocketAddress>emptyList());
when(mockPool.getLocators()).thenReturn(Collections.emptyList());
when(mockPool.getMaxConnections()).thenReturn(200);
when(mockPool.getMinConnections()).thenReturn(10);
when(mockPool.getMultiuserAuthentication()).thenReturn(false);
when(mockPool.getPingInterval()).thenReturn(15000l);
when(mockPool.getPingInterval()).thenReturn(15000L);
when(mockPool.getPRSingleHopEnabled()).thenReturn(false);
when(mockPool.getReadTimeout()).thenReturn(30000);
when(mockPool.getRetryAttempts()).thenReturn(1);
@@ -582,7 +560,7 @@ public class ClientCacheFactoryBeanTest {
ClientCacheFactoryBean clientCacheFactoryBean = new ClientCacheFactoryBean();
clientCacheFactoryBean.setIdleTimeout(180000l);
clientCacheFactoryBean.setIdleTimeout(180000L);
clientCacheFactoryBean.setMaxConnections(500);
clientCacheFactoryBean.setMinConnections(50);
clientCacheFactoryBean.setMultiUserAuthentication(true);
@@ -598,7 +576,7 @@ public class ClientCacheFactoryBeanTest {
clientCacheFactoryBean.addLocators(newConnectionEndpoint("localhost", 11235));
assertThat(clientCacheFactoryBean.getFreeConnectionTimeout(), is(nullValue()));
assertThat(clientCacheFactoryBean.getIdleTimeout(), is(equalTo(180000l)));
assertThat(clientCacheFactoryBean.getIdleTimeout(), is(equalTo(180000L)));
assertThat(clientCacheFactoryBean.getLoadConditioningInterval(), is(nullValue()));
assertThat(clientCacheFactoryBean.getLocators().size(), is(equalTo(1)));
assertThat(clientCacheFactoryBean.getMaxConnections(), is(equalTo(500)));
@@ -646,12 +624,12 @@ public class ClientCacheFactoryBeanTest {
verify(mockPool, never()).getSubscriptionRedundancy();
verify(mockPool, never()).getThreadLocalConnections();
verify(mockClientCacheFactory, times(1)).setPoolFreeConnectionTimeout(eq(5000));
verify(mockClientCacheFactory, times(1)).setPoolIdleTimeout(eq(180000l));
verify(mockClientCacheFactory, times(1)).setPoolIdleTimeout(eq(180000L));
verify(mockClientCacheFactory, times(1)).setPoolLoadConditioningInterval(eq(300000));
verify(mockClientCacheFactory, times(1)).setPoolMaxConnections(eq(500));
verify(mockClientCacheFactory, times(1)).setPoolMinConnections(eq(50));
verify(mockClientCacheFactory, times(1)).setPoolMultiuserAuthentication(eq(true));
verify(mockClientCacheFactory, times(1)).setPoolPingInterval(eq(15000l));
verify(mockClientCacheFactory, times(1)).setPoolPingInterval(eq(15000L));
verify(mockClientCacheFactory, times(1)).setPoolPRSingleHopEnabled(eq(true));
verify(mockClientCacheFactory, times(1)).setPoolReadTimeout(eq(30000));
verify(mockClientCacheFactory, times(1)).setPoolRetryAttempts(eq(1));
@@ -724,7 +702,7 @@ public class ClientCacheFactoryBeanTest {
public void initializePoolWithPoolServer() {
Pool mockPool = mock(Pool.class);
when(mockPool.getLocators()).thenReturn(Collections.<InetSocketAddress>emptyList());
when(mockPool.getLocators()).thenReturn(Collections.emptyList());
when(mockPool.getServers()).thenReturn(Collections.singletonList(new InetSocketAddress("boombox", 41414)));
ClientCacheFactoryBean clientCacheFactoryBean = new ClientCacheFactoryBean();
@@ -751,7 +729,7 @@ public class ClientCacheFactoryBeanTest {
Pool mockPool = mock(Pool.class);
when(mockPool.getLocators()).thenReturn(Collections.singletonList(new InetSocketAddress("skullbox", 21668)));
when(mockPool.getServers()).thenReturn(Collections.<InetSocketAddress>emptyList());
when(mockPool.getServers()).thenReturn(Collections.emptyList());
ClientCacheFactoryBean clientCacheFactoryBean = new ClientCacheFactoryBean();
@@ -803,8 +781,7 @@ public class ClientCacheFactoryBeanTest {
ClientCacheFactoryBean clientCacheFactoryBean = new ClientCacheFactoryBean();
assertThat((ClientCache) clientCacheFactoryBean.createCache(mockClientCacheFactory),
is(sameInstance(mockClientCache)));
assertThat(clientCacheFactoryBean.createCache(mockClientCacheFactory), is(sameInstance(mockClientCache)));
verify(mockClientCacheFactory, times(1)).create();
verifyZeroInteractions(mockClientCache);
@@ -878,7 +855,7 @@ public class ClientCacheFactoryBeanTest {
clientCacheFactoryBean.setBeanFactory(mockBeanFactory);
clientCacheFactoryBean.setPoolName("TestPool");
assertThat((ListableBeanFactory) clientCacheFactoryBean.getBeanFactory(), is(equalTo(mockBeanFactory)));
assertThat(clientCacheFactoryBean.getBeanFactory(), is(equalTo(mockBeanFactory)));
assertThat(clientCacheFactoryBean.getPool(), is(nullValue()));
assertThat(clientCacheFactoryBean.getPoolName(), is(equalTo("TestPool")));
assertThat(clientCacheFactoryBean.resolvePool(), is(equalTo(mockPool)));
@@ -903,7 +880,7 @@ public class ClientCacheFactoryBeanTest {
clientCacheFactoryBean.setBeanFactory(mockBeanFactory);
assertThat((ListableBeanFactory) clientCacheFactoryBean.getBeanFactory(), is(equalTo(mockBeanFactory)));
assertThat(clientCacheFactoryBean.getBeanFactory(), is(equalTo(mockBeanFactory)));
assertThat(clientCacheFactoryBean.getPool(), is(nullValue()));
assertThat(clientCacheFactoryBean.getPoolName(), is(nullValue()));
assertThat(clientCacheFactoryBean.resolvePool(), is(equalTo(mockPool)));
@@ -925,7 +902,7 @@ public class ClientCacheFactoryBeanTest {
clientCacheFactoryBean.setBeanFactory(mockBeanFactory);
assertThat((ListableBeanFactory) clientCacheFactoryBean.getBeanFactory(), is(equalTo(mockBeanFactory)));
assertThat(clientCacheFactoryBean.getBeanFactory(), is(equalTo(mockBeanFactory)));
assertThat(clientCacheFactoryBean.getPool(), is(nullValue()));
assertThat(clientCacheFactoryBean.getPoolName(), is(nullValue()));
assertThat(clientCacheFactoryBean.resolvePool(), is(nullValue()));
@@ -949,7 +926,7 @@ public class ClientCacheFactoryBeanTest {
clientCacheFactoryBean.setBeanFactory(mockBeanFactory);
clientCacheFactoryBean.setPoolName("TestPool");
assertThat((ListableBeanFactory) clientCacheFactoryBean.getBeanFactory(), is(equalTo(mockBeanFactory)));
assertThat(clientCacheFactoryBean.getBeanFactory(), is(equalTo(mockBeanFactory)));
assertThat(clientCacheFactoryBean.getPool(), is(nullValue()));
assertThat(clientCacheFactoryBean.getPoolName(), is(equalTo("TestPool")));
assertThat(clientCacheFactoryBean.resolvePool(), is(nullValue()));
@@ -1176,12 +1153,12 @@ public class ClientCacheFactoryBeanTest {
assertThat(clientCacheFactoryBean.getThreadLocalConnections(), is(nullValue()));
clientCacheFactoryBean.setFreeConnectionTimeout(5000);
clientCacheFactoryBean.setIdleTimeout(120000l);
clientCacheFactoryBean.setIdleTimeout(120000L);
clientCacheFactoryBean.setLoadConditioningInterval(300000);
clientCacheFactoryBean.setMaxConnections(500);
clientCacheFactoryBean.setMinConnections(50);
clientCacheFactoryBean.setMultiUserAuthentication(true);
clientCacheFactoryBean.setPingInterval(15000l);
clientCacheFactoryBean.setPingInterval(15000L);
clientCacheFactoryBean.setPrSingleHopEnabled(true);
clientCacheFactoryBean.setReadTimeout(30000);
clientCacheFactoryBean.setRetryAttempts(1);
@@ -1195,12 +1172,12 @@ public class ClientCacheFactoryBeanTest {
clientCacheFactoryBean.setThreadLocalConnections(false);
assertThat(clientCacheFactoryBean.getFreeConnectionTimeout(), is(equalTo(5000)));
assertThat(clientCacheFactoryBean.getIdleTimeout(), is(equalTo(120000l)));
assertThat(clientCacheFactoryBean.getIdleTimeout(), is(equalTo(120000L)));
assertThat(clientCacheFactoryBean.getLoadConditioningInterval(), is(equalTo(300000)));
assertThat(clientCacheFactoryBean.getMaxConnections(), is(equalTo(500)));
assertThat(clientCacheFactoryBean.getMinConnections(), is(equalTo(50)));
assertThat(clientCacheFactoryBean.getMultiUserAuthentication(), is(equalTo(true)));
assertThat(clientCacheFactoryBean.getPingInterval(), is(equalTo(15000l)));
assertThat(clientCacheFactoryBean.getPingInterval(), is(equalTo(15000L)));
assertThat(clientCacheFactoryBean.getPrSingleHopEnabled(), is(equalTo(true)));
assertThat(clientCacheFactoryBean.getReadTimeout(), is(equalTo(30000)));
assertThat(clientCacheFactoryBean.getRetryAttempts(), is(equalTo(1)));
@@ -1233,7 +1210,7 @@ public class ClientCacheFactoryBeanTest {
assertThat(clientCacheFactoryBean.getReadyForEvents(), is(false));
}
protected ClientCache mockClientCache(String durableClientId) {
private ClientCache mockClientCache(String durableClientId) {
ClientCache mockClientCache = mock(ClientCache.class);
DistributedSystem mockDistributedSystem = mock(DistributedSystem.class);
@@ -1363,7 +1340,7 @@ public class ClientCacheFactoryBeanTest {
assertThat(clientCacheFactoryBean.getLocators().size(), is(equalTo(1)));
assertThat(clientCacheFactoryBean.getLocators().findOne("localhost"), is(equalTo(localhost)));
clientCacheFactoryBean.setLocators(Collections.<ConnectionEndpoint>emptyList());
clientCacheFactoryBean.setLocators(Collections.emptyList());
assertThat(clientCacheFactoryBean.getLocators(), is(notNullValue()));
assertThat(clientCacheFactoryBean.getLocators().isEmpty(), is(true));
@@ -1398,7 +1375,7 @@ public class ClientCacheFactoryBeanTest {
assertThat(clientCacheFactoryBean.getServers().size(), is(equalTo(1)));
assertThat(clientCacheFactoryBean.getServers().findOne("localhost"), is(equalTo(localhost)));
clientCacheFactoryBean.setServers(Collections.<ConnectionEndpoint>emptyList());
clientCacheFactoryBean.setServers(Collections.emptyList());
assertThat(clientCacheFactoryBean.getServers(), is(notNullValue()));
assertThat(clientCacheFactoryBean.getServers().isEmpty(), is(true));

View File

@@ -130,7 +130,7 @@ public class ClientRegionFactoryBeanTest {
factoryBean.setSnapshot(mockSnapshot);
factoryBean.setShortcut(null);
Region actualRegion = factoryBean.lookupRegion(mockClientCache, testRegionName);
Region actualRegion = factoryBean.createRegion(mockClientCache, testRegionName);
assertSame(mockRegion, actualRegion);
@@ -180,7 +180,7 @@ public class ClientRegionFactoryBeanTest {
factoryBean.setPoolName("TestPool");
factoryBean.setShortcut(null);
Region<Object, Object> actualRegion = factoryBean.lookupRegion(mockClientCache, "TestRegion");
Region<Object, Object> actualRegion = factoryBean.createRegion(mockClientCache, "TestRegion");
assertSame(mockRegion, actualRegion);
@@ -208,7 +208,7 @@ public class ClientRegionFactoryBeanTest {
factoryBean.setBeanFactory(mockBeanFactory);
factoryBean.setShortcut(ClientRegionShortcut.CACHING_PROXY);
Region<Object, Object> actualRegion = factoryBean.lookupRegion(mockClientCache, "TestRegion");
Region<Object, Object> actualRegion = factoryBean.createRegion(mockClientCache, "TestRegion");
assertSame(mockRegion, actualRegion);
@@ -235,7 +235,7 @@ public class ClientRegionFactoryBeanTest {
factoryBean.setParent(mockRegion);
factoryBean.setShortcut(ClientRegionShortcut.PROXY);
Region<Object, Object> actualRegion = factoryBean.lookupRegion(mockClientCache, "TestSubRegion");
Region<Object, Object> actualRegion = factoryBean.createRegion(mockClientCache, "TestSubRegion");
assertSame(mockSubRegion, actualRegion);
@@ -260,7 +260,7 @@ public class ClientRegionFactoryBeanTest {
factoryBean.setBeanFactory(mockBeanFactory);
factoryBean.setShortcut(ClientRegionShortcut.LOCAL_HEAP_LRU);
Region<Object, Object> actualRegion = factoryBean.lookupRegion(mockClientCache, "TestRegion");
Region<Object, Object> actualRegion = factoryBean.createRegion(mockClientCache, "TestRegion");
assertSame(mockRegion, actualRegion);
@@ -284,7 +284,7 @@ public class ClientRegionFactoryBeanTest {
factoryBean.setDataPolicyName("INVALID");
}
catch (IllegalArgumentException expected) {
assertEquals("Data Policy 'INVALID' is invalid.", expected.getMessage());
assertEquals("Data Policy [INVALID] is not valid", expected.getMessage());
throw expected;
}
finally {
@@ -429,7 +429,7 @@ public class ClientRegionFactoryBeanTest {
factoryBean.resolveClientRegionShortcut();
}
catch (IllegalArgumentException expected) {
assertEquals("Client Region Shortcut 'CACHING_PROXY' is invalid when persistent is true",
assertEquals("Client Region Shortcut [CACHING_PROXY] is not valid when persistent is true",
expected.getMessage());
throw expected;
}
@@ -456,7 +456,7 @@ public class ClientRegionFactoryBeanTest {
factoryBean.resolveClientRegionShortcut();
}
catch (IllegalArgumentException expected) {
assertEquals("Client Region Shortcut 'LOCAL_PERSISTENT' is invalid when persistent is false",
assertEquals("Client Region Shortcut [LOCAL_PERSISTENT] is not valid when persistent is false",
expected.getMessage());
throw expected;
}
@@ -503,7 +503,7 @@ public class ClientRegionFactoryBeanTest {
factoryBean.resolveClientRegionShortcut();
}
catch (IllegalArgumentException expected) {
assertEquals("Data Policy 'NORMAL' is invalid when persistent is true", expected.getMessage());
assertEquals("Data Policy [NORMAL] is not valid when persistent is true", expected.getMessage());
throw expected;
}
}
@@ -529,7 +529,7 @@ public class ClientRegionFactoryBeanTest {
factoryBean.resolveClientRegionShortcut();
}
catch (IllegalArgumentException expected) {
assertEquals("Data Policy 'PERSISTENT_REPLICATE' is invalid when persistent is false", expected.getMessage());
assertEquals("Data Policy [PERSISTENT_REPLICATE] is not valid when persistent is false", expected.getMessage());
throw expected;
}
}

View File

@@ -52,19 +52,15 @@ import org.springframework.data.gemfire.util.ArrayUtils;
import org.springframework.data.util.ReflectionUtils;
/**
* The PoolFactoryBeanTest class is a test suite of test cases testing the contract and functionality
* of the PoolFactoryBean class.
* Unit tests for {@link PoolFactoryBean}.
*
* @author John Blum
* @see org.junit.Rule
* @see org.junit.Test
* @see org.junit.rules.ExpectedException
* @see org.mockito.Mockito
* @see org.springframework.data.gemfire.client.PoolFactoryBean
* @see org.springframework.data.gemfire.support.ConnectionEndpoint
* @see org.apache.geode.cache.GemFireCache
* @see org.apache.geode.cache.client.Pool
* @see org.apache.geode.cache.client.PoolFactory
* @see org.springframework.data.gemfire.client.PoolFactoryBean
* @since 1.7.0
*/
public class PoolFactoryBeanTest {
@@ -164,7 +160,7 @@ public class PoolFactoryBeanTest {
exception.expect(IllegalArgumentException.class);
exception.expectCause(is(nullValue(Throwable.class)));
exception.expectMessage("Pool 'name' is required");
exception.expectMessage("Pool name is required");
poolFactoryBean.afterPropertiesSet();
}

View File

@@ -18,6 +18,7 @@
package org.springframework.data.gemfire.config.annotation;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.doReturn;
@@ -53,9 +54,11 @@ import org.springframework.util.MethodInvoker;
*
* @author John Blum
* @see org.junit.Test
* @see org.junit.runner.RunWith
* @see org.mockito.Mock
* @see org.mockito.Mockito
* @see org.mockito.runners.MockitoJUnitRunner
* @see org.mockito.Spy
* @see org.mockito.junit.MockitoJUnitRunner
* @see org.springframework.data.gemfire.config.annotation.AbstractCacheConfiguration
* @since 1.9.0
*/
@@ -174,7 +177,7 @@ public class AbstractCacheConfigurationUnitTests {
MappingPdxSerializer mockPdxSerializer = mock(MappingPdxSerializer.class);
when(mockBeanFactory.containsBean(anyString())).thenReturn(false);
doReturn(mockPdxSerializer).when(cacheConfigurationSpy).newPdxSerializer();
doReturn(mockPdxSerializer).when(cacheConfigurationSpy).newPdxSerializer(any(BeanFactory.class));
cacheConfigurationSpy.setBeanFactory(mockBeanFactory);
@@ -184,7 +187,7 @@ public class AbstractCacheConfigurationUnitTests {
verify(mockBeanFactory, times(1)).containsBean(eq("TestPdxSerializer"));
verify(mockBeanFactory, never()).getBean(anyString(), eq(PdxSerializer.class));
verify(cacheConfigurationSpy, times(1)).newPdxSerializer();
verify(cacheConfigurationSpy, times(1)).newPdxSerializer(eq(mockBeanFactory));
}
@Test

View File

@@ -0,0 +1,130 @@
/*
* Copyright 2017 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.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
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.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.gemfire.server.CacheServerFactoryBean;
import org.springframework.data.gemfire.test.GemfireTestBeanPostProcessor;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner;
/**
* Integration tests for {@link CacheServerConfigurer}.
*
* @author John Blum
* @see org.junit.Test
* @see org.mockito.Mockito
* @see org.apache.geode.cache.server.CacheServer
* @see org.springframework.context.annotation.Configuration
* @see org.springframework.data.gemfire.config.annotation.CacheServerConfigurer
* @see org.springframework.data.gemfire.config.annotation.EnableCacheServer
* @see org.springframework.data.gemfire.config.annotation.EnableCacheServers
* @see org.springframework.data.gemfire.server.CacheServerFactoryBean
* @see org.springframework.test.context.ContextConfiguration
* @see org.springframework.test.context.junit4.SpringRunner
* @since 1.1.0
*/
@RunWith(SpringRunner.class)
@ContextConfiguration
@SuppressWarnings("unused")
public class CacheServerConfigurerIntegrationTests {
@Autowired
@Qualifier("configurerOne")
private TestCacheServerConfigurer configurerOne;
@Autowired
@Qualifier("configurerTwo")
private TestCacheServerConfigurer configurerTwo;
private void assertCacheServerConfigurerCalled(TestCacheServerConfigurer configurer,
String... cacheServerBeanNames) {
assertThat(configurer).isNotNull();
assertThat(configurer).hasSize(cacheServerBeanNames.length);
assertThat(configurer).contains(cacheServerBeanNames);
}
@Test
public void cacheServerConfigurerOneCalledSuccessfully() {
assertCacheServerConfigurerCalled(this.configurerOne,
"gemfireCacheServer", "marsServer", "saturnServer", "venusServer");
}
@Test
public void cacheServerConfigurerTwoCalledSuccessfully() {
assertCacheServerConfigurerCalled(this.configurerTwo,
"gemfireCacheServer", "marsServer", "saturnServer", "venusServer");
}
@Configuration
@CacheServerApplication
@EnableCacheServers(servers = {
@EnableCacheServer(name = "marsServer"),
@EnableCacheServer(name = "saturnServer"),
@EnableCacheServer(name = "venusServer"),
})
static class TestConfiguration {
@Bean
GemfireTestBeanPostProcessor testBeanPostProcessor() {
return new GemfireTestBeanPostProcessor();
}
@Bean
TestCacheServerConfigurer configurerOne() {
return new TestCacheServerConfigurer();
}
@Bean
TestCacheServerConfigurer configurerTwo() {
return new TestCacheServerConfigurer();
}
@Bean
Object nonRelevantBean() {
return "test";
}
}
static class TestCacheServerConfigurer implements CacheServerConfigurer, Iterable<String> {
private final Set<String> beanNames = new HashSet<>();
@Override
public void configure(String beanName, CacheServerFactoryBean bean) {
this.beanNames.add(beanName);
}
@Override
public Iterator<String> iterator() {
return Collections.unmodifiableSet(this.beanNames).iterator();
}
}
}

View File

@@ -0,0 +1,127 @@
/*
* Copyright 2017 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.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import org.apache.geode.cache.client.ClientCache;
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.context.annotation.Bean;
import org.springframework.data.gemfire.client.ClientCacheFactoryBean;
import org.springframework.data.gemfire.test.GemfireTestBeanPostProcessor;
import org.springframework.test.context.junit4.SpringRunner;
/**
* Integration tests for {@link ClientCacheConfigurer}.
*
* @author John Blum
* @see org.junit.Test
* @see org.junit.runner.RunWith
* @see org.apache.geode.cache.client.ClientCache
* @see org.springframework.data.gemfire.client.ClientCacheFactoryBean
* @see org.springframework.data.gemfire.config.annotation.ClientCacheApplication
* @see org.springframework.data.gemfire.config.annotation.ClientCacheConfigurer
* @see org.springframework.data.gemfire.test.GemfireTestBeanPostProcessor
* @see org.springframework.test.context.junit4.SpringRunner
* @since 1.1.0
*/
@RunWith(SpringRunner.class)
@SuppressWarnings("unused")
public class ClientCacheConfigurerIntegrationTests {
@Autowired
private ClientCache clientCache;
@Autowired
@Qualifier("testClientCacheConfigurerOne")
private TestClientCacheConfigurer configurerOne;
@Autowired
@Qualifier("testClientCacheConfigurerTwo")
private TestClientCacheConfigurer configurerTwo;
@Before
public void setup() {
assertThat(this.clientCache).isNotNull();
}
private void assertClientCacheConfigurerInvokedSuccessfully(TestClientCacheConfigurer clientCacheConfigurer,
String... beanNames) {
assertThat(clientCacheConfigurer).isNotNull();
assertThat(clientCacheConfigurer).hasSize(beanNames.length);
assertThat(clientCacheConfigurer).contains(beanNames);
}
@Test
public void clientCacheConfigurerOneCalledSuccessfully() {
assertClientCacheConfigurerInvokedSuccessfully(this.configurerOne, "gemfireCache");
}
@Test
public void clientCacheConfigurerTwoCalledSuccessfully() {
assertClientCacheConfigurerInvokedSuccessfully(this.configurerTwo, "gemfireCache");
}
@ClientCacheApplication
static class TestConfiguration {
@Bean
GemfireTestBeanPostProcessor testBeanPostProcessor() {
return new GemfireTestBeanPostProcessor();
}
@Bean
TestClientCacheConfigurer testClientCacheConfigurerOne() {
return new TestClientCacheConfigurer();
}
@Bean
TestClientCacheConfigurer testClientCacheConfigurerTwo() {
return new TestClientCacheConfigurer();
}
@Bean
String nonRelevantBean() {
return "test";
}
}
static final class TestClientCacheConfigurer implements ClientCacheConfigurer, Iterable<String> {
private Set<String> beanNames = new HashSet<>();
@Override
public void configure(String beanName, ClientCacheFactoryBean bean) {
this.beanNames.add(beanName);
}
@Override
public Iterator<String> iterator() {
return Collections.unmodifiableSet(this.beanNames).iterator();
}
}
}

View File

@@ -0,0 +1,127 @@
/*
* Copyright 2017 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.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
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.context.annotation.Bean;
import org.springframework.data.gemfire.DiskStoreFactoryBean;
import org.springframework.data.gemfire.test.GemfireTestBeanPostProcessor;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner;
/**
* Integration tests for {@link DiskStoreConfigurer}.
*
* @author John Blum
* @see org.junit.Test
* @see org.mockito.Mockito
* @see org.apache.geode.cache.DiskStore
* @see org.apache.geode.cache.DiskStoreFactory
* @see org.apache.geode.cache.GemFireCache
* @see org.springframework.context.annotation.Configuration
* @see org.springframework.data.gemfire.DiskStoreFactoryBean
* @see org.springframework.data.gemfire.config.annotation.DiskStoreConfiguration
* @see org.springframework.data.gemfire.config.annotation.DiskStoreConfigurer
* @see org.springframework.data.gemfire.config.annotation.EnableDiskStore
* @see org.springframework.data.gemfire.config.annotation.EnableDiskStores
* @see org.springframework.test.context.ContextConfiguration
* @see org.springframework.test.context.junit4.SpringRunner
* @since 1.1.0
*/
@RunWith(SpringRunner.class)
@ContextConfiguration
@SuppressWarnings("unused")
public class DiskStoreConfigurerIntegrationTests {
@Autowired
@Qualifier("configurerOne")
private TestDiskStoreConfigurer configurerOne;
@Autowired
@Qualifier("configurerTwo")
private TestDiskStoreConfigurer configurerTwo;
private void assertDiskStoreConfigurerCalled(TestDiskStoreConfigurer configurer, String... beanNames) {
assertThat(configurer).isNotNull();
assertThat(configurer).hasSize(beanNames.length);
assertThat(configurer).contains(beanNames);
}
@Test
public void diskStoreConfigurerOneCalledSuccessfully() {
assertDiskStoreConfigurerCalled(this.configurerOne, "cd", "floppy", "tape");
}
@Test
public void diskStoreConfigurerTwoCalledSuccessfully() {
assertDiskStoreConfigurerCalled(this.configurerTwo, "cd", "floppy", "tape");
}
@PeerCacheApplication
@EnableDiskStores(diskStores = {
@EnableDiskStore(name = "cd"),
@EnableDiskStore(name = "floppy"),
@EnableDiskStore(name = "tape"),
})
static class TestConfiguration {
@Bean
GemfireTestBeanPostProcessor testBeanPostProcessor() {
return new GemfireTestBeanPostProcessor();
}
@Bean
TestDiskStoreConfigurer configurerOne() {
return new TestDiskStoreConfigurer();
}
@Bean
TestDiskStoreConfigurer configurerTwo() {
return new TestDiskStoreConfigurer();
}
@Bean
Object nonRelevantBean() {
return "test";
}
}
static class TestDiskStoreConfigurer implements DiskStoreConfigurer, Iterable<String> {
private final Set<String> beanNames = new HashSet<>();
@Override
public void configure(String beanName, DiskStoreFactoryBean bean) {
this.beanNames.add(beanName);
}
@Override
public Iterator<String> iterator() {
return Collections.unmodifiableSet(this.beanNames).iterator();
}
}
}

View File

@@ -0,0 +1,211 @@
/*
* Copyright 2017 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 static org.mockito.Mockito.mock;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Optional;
import java.util.Set;
import org.apache.geode.cache.GemFireCache;
import org.apache.geode.cache.lucene.LuceneIndex;
import org.apache.geode.cache.lucene.LuceneService;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.FilterType;
import org.springframework.data.gemfire.IndexFactoryBean;
import org.springframework.data.gemfire.config.annotation.test.entities.CollocatedPartitionRegionEntity;
import org.springframework.data.gemfire.config.annotation.test.entities.NonEntity;
import org.springframework.data.gemfire.mapping.annotation.ClientRegion;
import org.springframework.data.gemfire.mapping.annotation.LocalRegion;
import org.springframework.data.gemfire.mapping.annotation.ReplicateRegion;
import org.springframework.data.gemfire.search.lucene.LuceneIndexFactoryBean;
import org.springframework.data.gemfire.test.GemfireTestBeanPostProcessor;
/**
* Integration tests for {@link IndexConfigurer}.
*
* @author John Blum
* @see org.junit.Test
* @see org.apache.geode.cache.GemFireCache
* @see org.apache.geode.cache.lucene.LuceneIndex
* @see org.apache.geode.cache.query.Index
* @see org.springframework.data.gemfire.IndexFactoryBean
* @see org.springframework.data.gemfire.config.annotation.IndexConfigurer
* @see org.springframework.data.gemfire.search.lucene.LuceneIndexFactoryBean
* @since 1.0.0
*/
public class IndexConfigurerIntegrationTests {
private static ConfigurableApplicationContext applicationContext;
@BeforeClass
public static void setup() {
applicationContext = newApplicationContext(TestConfiguration.class);
assertThat(applicationContext).isNotNull();
assertThat(applicationContext.containsBean("CustomersFirstNameFunctionalIdx")).isTrue();
assertThat(applicationContext.containsBean("CustomersIdKeyIdx")).isTrue();
assertThat(applicationContext.containsBean("GenericRegionEntityIdKeyIdx")).isTrue();
assertThat(applicationContext.containsBean("LastNameIdx")).isTrue();
assertThat(applicationContext.containsBean("luceneIndex")).isTrue();
assertThat(applicationContext.containsBean("oqlIndex")).isTrue();
assertThat(applicationContext.containsBean("TitleLuceneIdx")).isTrue();
}
@AfterClass
public static void tearDown() {
Optional.ofNullable(applicationContext).ifPresent(ConfigurableApplicationContext::close);
}
/* (non-Javadoc) */
private static ConfigurableApplicationContext newApplicationContext(Class<?>... annotatedClasses) {
ConfigurableApplicationContext applicationContext = new AnnotationConfigApplicationContext(annotatedClasses);
applicationContext.registerShutdownHook();
return applicationContext;
}
/* (non-Javadoc) */
private void assertIndexConfigurerInvocations(TestIndexConfigurer indexConfigurer, String... indexBeanNames) {
assertThat(indexConfigurer).isNotNull();
assertThat(indexConfigurer).contains(indexBeanNames);
assertThat(indexConfigurer).hasSize(indexBeanNames.length);
}
@Test
public void indexConfigurerOneCalledSuccessfully() {
assertIndexConfigurerInvocations(
applicationContext.getBean("testIndexConfigurerOne", TestIndexConfigurer.class),
"CustomersFirstNameFunctionalIdx", "CustomersIdKeyIdx", "GenericRegionEntityIdKeyIdx",
"LastNameIdx", "TitleLuceneIdx");
}
@Test
public void indexConfigurerTwoCalledSuccessfully() {
assertIndexConfigurerInvocations(
applicationContext.getBean("testIndexConfigurerTwo", TestIndexConfigurer.class),
"CustomersFirstNameFunctionalIdx", "CustomersIdKeyIdx", "GenericRegionEntityIdKeyIdx",
"LastNameIdx", "TitleLuceneIdx");
}
@PeerCacheApplication
@EnableIndexing
@SuppressWarnings("unused")
@EnableEntityDefinedRegions(basePackageClasses = NonEntity.class,
excludeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION,
classes = { ClientRegion.class, LocalRegion.class, ReplicateRegion.class }),
@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,
classes = CollocatedPartitionRegionEntity.class)
}
)
static class TestConfiguration {
@Bean
GemfireTestBeanPostProcessor testBeanPostProcessor() {
return new GemfireTestBeanPostProcessor();
}
@Bean
BeanPostProcessor indexFactoryBeanReplacingBeanPostProcessor() {
return new BeanPostProcessor() {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof LuceneIndexFactoryBean) {
LuceneIndexFactoryBean luceneIndexFactoryBean = (LuceneIndexFactoryBean) bean;
LuceneService mockLuceneService = mock(LuceneService.class);
LuceneIndex mockLuceneIndex = mock(LuceneIndex.class);
luceneIndexFactoryBean.setLuceneIndex(mockLuceneIndex);
luceneIndexFactoryBean.setLuceneService(mockLuceneService);
luceneIndexFactoryBean.setRegionPath("/Test");
}
return bean;
}
};
}
@Bean
LuceneIndexFactoryBean luceneIndex() {
return new LuceneIndexFactoryBean();
}
@Bean
IndexFactoryBean oqlIndex(GemFireCache cache) {
IndexFactoryBean indexFactory = new IndexFactoryBean();
indexFactory.setCache(cache);
indexFactory.setExpression("*");
indexFactory.setFrom("/Test");
return indexFactory;
}
@Bean
TestIndexConfigurer testIndexConfigurerOne() {
return new TestIndexConfigurer();
}
@Bean
TestIndexConfigurer testIndexConfigurerTwo() {
return new TestIndexConfigurer();
}
@Bean
String nonRelevantBean() {
return "test";
}
}
private static class TestIndexConfigurer implements IndexConfigurer, Iterable<String> {
private final Set<String> beanNames = new HashSet<>();
@Override
public void configure(String beanName, IndexFactoryBean bean) {
this.beanNames.add(beanName);
}
@Override
public void configure(String beanName, LuceneIndexFactoryBean bean) {
this.beanNames.add(beanName);
}
@Override
public Iterator<String> iterator() {
return Collections.unmodifiableSet(this.beanNames).iterator();
}
}
}

View File

@@ -0,0 +1,127 @@
/*
* Copyright 2017 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.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import org.apache.geode.cache.Cache;
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.context.annotation.Bean;
import org.springframework.data.gemfire.CacheFactoryBean;
import org.springframework.data.gemfire.test.GemfireTestBeanPostProcessor;
import org.springframework.test.context.junit4.SpringRunner;
/**
* Integration tests for {@link PeerCacheConfigurer}.
*
* @author John Blum
* @see org.junit.Test
* @see org.junit.runner.RunWith
* @see org.apache.geode.cache.Cache
* @see org.springframework.data.gemfire.CacheFactoryBean
* @see org.springframework.data.gemfire.config.annotation.PeerCacheApplication
* @see org.springframework.data.gemfire.config.annotation.PeerCacheConfigurer
* @see org.springframework.data.gemfire.test.GemfireTestBeanPostProcessor
* @see org.springframework.test.context.junit4.SpringRunner
* @since 1.0.0
*/
@RunWith(SpringRunner.class)
@SuppressWarnings("unused")
public class PeerCacheConfigurerIntegrationTests {
@Autowired
private Cache peerCache;
@Autowired
@Qualifier("testPeerCacheConfigurerOne")
private TestPeerCacheConfigurer configurerOne;
@Autowired
@Qualifier("testPeerCacheConfigurerTwo")
private TestPeerCacheConfigurer configurerTwo;
@Before
public void setup() {
assertThat(this.peerCache).isNotNull();
}
private void assertTestPeerCacheConfigurerCalledSuccessully(TestPeerCacheConfigurer peerCacheConfigurer,
String... beanNames) {
assertThat(peerCacheConfigurer).isNotNull();
assertThat(peerCacheConfigurer).hasSize(beanNames.length);
assertThat(peerCacheConfigurer).contains(beanNames);
}
@Test
public void peerCacheConfigurerOneCalledSuccessfully() {
assertTestPeerCacheConfigurerCalledSuccessully(this.configurerOne, "gemfireCache");
}
@Test
public void peerCacheConfigurerTwoCalledSuccessfully() {
assertTestPeerCacheConfigurerCalledSuccessully(this.configurerTwo, "gemfireCache");
}
@PeerCacheApplication
static class TestConfiguration {
@Bean
GemfireTestBeanPostProcessor testBeanPostProcessor() {
return new GemfireTestBeanPostProcessor();
}
@Bean
TestPeerCacheConfigurer testPeerCacheConfigurerOne() {
return new TestPeerCacheConfigurer();
}
@Bean
TestPeerCacheConfigurer testPeerCacheConfigurerTwo() {
return new TestPeerCacheConfigurer();
}
@Bean
String nonRelevantBean() {
return "test";
}
}
static class TestPeerCacheConfigurer implements Iterable<String>, PeerCacheConfigurer {
private Set<String> beanNames = new HashSet<>();
@Override
public void configure(String beanName, CacheFactoryBean bean) {
this.beanNames.add(beanName);
}
@Override
public Iterator<String> iterator() {
return Collections.unmodifiableSet(this.beanNames).iterator();
}
}
}

View File

@@ -0,0 +1,120 @@
/*
* Copyright 2017 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.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
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.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.gemfire.client.PoolFactoryBean;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner;
/**
* Integration tests for {@link PoolConfigurer}.
*
* @author John Blum
* @see org.junit.Test
* @see org.apache.geode.cache.client.Pool
* @see org.springframework.context.annotation.Configuration
* @see org.springframework.data.gemfire.client.PoolFactoryBean
* @see org.springframework.data.gemfire.config.annotation.AddPoolConfiguration
* @see org.springframework.data.gemfire.config.annotation.AddPoolsConfiguration
* @see org.springframework.data.gemfire.config.annotation.PoolConfigurer
* @see org.springframework.data.gemfire.config.annotation.EnablePool
* @see org.springframework.data.gemfire.config.annotation.EnablePools
* @see org.springframework.test.context.ContextConfiguration
* @see org.springframework.test.context.junit4.SpringRunner
* @since 1.1.0
*/
@RunWith(SpringRunner.class)
@ContextConfiguration
@SuppressWarnings("unused")
public class PoolConfigurerIntegrationTests {
@Autowired
@Qualifier("configurerOne")
private TestPoolConfigurer configurerOne;
@Autowired
@Qualifier("configurerTwo")
private TestPoolConfigurer configurerTwo;
protected void assertPoolConfigurerCalled(TestPoolConfigurer configurer, String... beanNames) {
assertThat(configurer).isNotNull();
assertThat(configurer).hasSize(beanNames.length);
assertThat(configurer).contains(beanNames);
}
@Test
public void poolConfigurerOneCalledSuccessfully() {
assertPoolConfigurerCalled(this.configurerOne, "poolOne", "poolTwo", "poolThree");
}
@Test
public void poolConfigurerTwoCalledSuccessfully() {
assertPoolConfigurerCalled(this.configurerTwo, "poolOne", "poolTwo", "poolThree");
}
@Configuration
@EnablePools(pools = {
@EnablePool(name = "poolOne"),
@EnablePool(name = "poolTwo"),
@EnablePool(name = "poolThree"),
})
static class TestConfiguration {
@Bean
TestPoolConfigurer configurerOne() {
return new TestPoolConfigurer();
}
@Bean
TestPoolConfigurer configurerTwo() {
return new TestPoolConfigurer();
}
@Bean
Object nonRelevantBean() {
return "test";
}
}
static class TestPoolConfigurer implements Iterable<String>, PoolConfigurer {
private final Set<String> beanNames = new HashSet<>();
@Override
public void configure(String beanName, PoolFactoryBean bean) {
this.beanNames.add(beanName);
}
@Override
public Iterator<String> iterator() {
return Collections.unmodifiableSet(this.beanNames).iterator();
}
}
}

View File

@@ -0,0 +1,204 @@
/*
* Copyright 2017 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.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Optional;
import java.util.Set;
import org.apache.geode.cache.GemFireCache;
import org.junit.After;
import org.junit.Test;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.FilterType;
import org.springframework.data.gemfire.PartitionedRegionFactoryBean;
import org.springframework.data.gemfire.RegionFactoryBean;
import org.springframework.data.gemfire.client.ClientRegionFactoryBean;
import org.springframework.data.gemfire.config.annotation.test.entities.CollocatedPartitionRegionEntity;
import org.springframework.data.gemfire.config.annotation.test.entities.NonEntity;
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.test.GemfireTestBeanPostProcessor;
/**
* Integration tests for {@link RegionConfigurer}.
*
* @author John Blum
* @see org.junit.Test
* @see org.apache.geode.cache.GemFireCache
* @see org.apache.geode.cache.Region
* @see org.springframework.context.ConfigurableApplicationContext
* @see org.springframework.context.annotation.AnnotationConfigApplicationContext
* @see org.springframework.data.gemfire.RegionFactoryBean
* @see org.springframework.data.gemfire.client.ClientRegionFactoryBean
* @see org.springframework.data.gemfire.config.annotation.RegionConfigurer
* @see org.springframework.data.gemfire.test.GemfireTestBeanPostProcessor
* @since 1.1.0
*/
public class RegionConfigurerIntegrationTests {
private ConfigurableApplicationContext applicationContext;
@After
public void tearDown() {
Optional.ofNullable(this.applicationContext).ifPresent(ConfigurableApplicationContext::close);
}
/* (non-Javadoc) */
private void assertRegionConfigurerInvocations(TestRegionConfigurer regionConfigurer, String... regionBeanNames) {
assertThat(regionConfigurer).isNotNull();
assertThat(regionConfigurer).contains(regionBeanNames);
assertThat(regionConfigurer).hasSize(regionBeanNames.length);
}
/* (non-Javadoc) */
private ConfigurableApplicationContext newApplicationContext(Class<?>... annotatedClasses) {
ConfigurableApplicationContext applicationContext = new AnnotationConfigApplicationContext(annotatedClasses);
applicationContext.registerShutdownHook();
return applicationContext;
}
@Test
public void clientRegionConfigurersCalledSuccessfully() {
this.applicationContext = newApplicationContext(ClientTestConfiguration.class);
assertThat(this.applicationContext).isNotNull();
assertThat(this.applicationContext.containsBean("Sessions")).isTrue();
assertThat(this.applicationContext.containsBean("GenericRegionEntity")).isTrue();
assertThat(this.applicationContext.containsBean("Test")).isTrue();
assertThat(this.applicationContext.containsBean("testRegionConfigurerOne")).isTrue();
assertThat(this.applicationContext.containsBean("testRegionConfigurerTwo")).isTrue();
assertRegionConfigurerInvocations(
this.applicationContext.getBean("testRegionConfigurerOne", TestRegionConfigurer.class),
"GenericRegionEntity", "Sessions");
assertRegionConfigurerInvocations(
this.applicationContext.getBean("testRegionConfigurerTwo", TestRegionConfigurer.class),
"GenericRegionEntity", "Sessions");
}
@Test
public void peerRegionConfigurersCalledSuccessfully() {
this.applicationContext = newApplicationContext(PeerTestConfiguration.class);
assertThat(this.applicationContext).isNotNull();
assertThat(this.applicationContext.containsBean("Customers")).isTrue();
assertThat(this.applicationContext.containsBean("GenericRegionEntity")).isTrue();
assertThat(this.applicationContext.containsBean("Test")).isTrue();
assertThat(this.applicationContext.containsBean("testRegionConfigurerOne")).isTrue();
assertThat(this.applicationContext.containsBean("testRegionConfigurerTwo")).isTrue();
assertRegionConfigurerInvocations(
this.applicationContext.getBean("testRegionConfigurerOne", TestRegionConfigurer.class),
"Customers", "GenericRegionEntity");
assertRegionConfigurerInvocations(
this.applicationContext.getBean("testRegionConfigurerTwo", TestRegionConfigurer.class),
"Customers", "GenericRegionEntity");
}
@SuppressWarnings("unused")
static class AbstractTestConfiguration {
@Bean
GemfireTestBeanPostProcessor testBeanPostProcessor() {
return new GemfireTestBeanPostProcessor();
}
@Bean
TestRegionConfigurer testRegionConfigurerOne() {
return new TestRegionConfigurer();
}
@Bean
TestRegionConfigurer testRegionConfigurerTwo() {
return new TestRegionConfigurer();
}
@Bean
String nonRelevantBean() {
return "test";
}
}
@ClientCacheApplication
@EnableEntityDefinedRegions(basePackageClasses = NonEntity.class,
excludeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION,
classes = { LocalRegion.class, PartitionRegion.class, ReplicateRegion.class }))
@SuppressWarnings("unused")
static class ClientTestConfiguration extends AbstractTestConfiguration {
@Bean(name = "Test")
ClientRegionFactoryBean<Object, Object> testRegion(GemFireCache gemfireCache) {
ClientRegionFactoryBean<Object, Object> testRegionFactory = new ClientRegionFactoryBean<>();
testRegionFactory.setCache(gemfireCache);
return testRegionFactory;
}
}
@PeerCacheApplication
@EnableEntityDefinedRegions(basePackageClasses = NonEntity.class,
excludeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION,
classes = { ClientRegion.class, LocalRegion.class, ReplicateRegion.class }),
@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,
classes = CollocatedPartitionRegionEntity.class)
}
)
@SuppressWarnings("unused")
static class PeerTestConfiguration extends AbstractTestConfiguration {
@Bean(name = "Test")
PartitionedRegionFactoryBean<Object, Object> testRegion(GemFireCache gemfireCache) {
PartitionedRegionFactoryBean<Object, Object> testRegionFactory = new PartitionedRegionFactoryBean<>();
testRegionFactory.setCache(gemfireCache);
return testRegionFactory;
}
}
private static class TestRegionConfigurer implements Iterable<String>, RegionConfigurer {
private final Set<String> beanNames = new HashSet<>();
@Override
public void configure(String beanName, RegionFactoryBean<?, ?> bean) {
this.beanNames.add(beanName);
}
@Override
public void configure(String beanName, ClientRegionFactoryBean<?, ?> bean) {
this.beanNames.add(beanName);
}
@Override
public Iterator<String> iterator() {
return Collections.unmodifiableSet(this.beanNames).iterator();
}
}
}

View File

@@ -16,21 +16,23 @@
package org.springframework.data.gemfire.config.xml;
import static java.util.Arrays.stream;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
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.nullSafeArray;
import java.io.File;
import java.io.FilenameFilter;
import java.util.concurrent.atomic.AtomicReference;
import org.apache.geode.cache.CacheListener;
@@ -46,6 +48,7 @@ import org.apache.geode.cache.LoaderHelper;
import org.apache.geode.cache.Region;
import org.apache.geode.cache.RegionAttributes;
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.util.CacheWriterAdapter;
import org.apache.geode.compression.Compressor;
@@ -66,12 +69,13 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.util.ObjectUtils;
/**
* The ClientRegionNamespaceTest class is a test suite of test cases testing the contract and functionality
* of GemFire Client Region namespace support in SDG.
* Unit tests for Spring Data GemFire's XML namespace support for client {@link Region Regions}.
*
* @author Costin Leau
* @author David Turanski
* @author John Blum
* @see org.apache.geode.cache.Region
* @see org.apache.geode.cache.client.ClientCache
* @see org.springframework.data.gemfire.client.ClientRegionFactoryBean
* @see org.springframework.data.gemfire.config.xml.ClientRegionParser
*/
@@ -81,35 +85,29 @@ import org.springframework.util.ObjectUtils;
public class ClientRegionNamespaceTest {
@Autowired
private ApplicationContext context;
private ApplicationContext applicationContext;
@AfterClass
public static void tearDown() {
for (String name : new File(".").list(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
return name.startsWith("BACKUP");
}
})) {
new File(name).delete();
}
stream(nullSafeArray(new File(".").list((dir, name) -> name.startsWith("BACKUP")), String.class))
.forEach(fileName -> new File(fileName).delete());
}
@Test
public void testBeanNames() throws Exception {
assertTrue(context.containsBean("SimpleRegion"));
assertTrue(context.containsBean("Publisher"));
assertTrue(context.containsBean("ComplexRegion"));
assertTrue(context.containsBean("PersistentRegion"));
assertTrue(context.containsBean("OverflowRegion"));
assertTrue(context.containsBean("Compressed"));
assertTrue(applicationContext.containsBean("SimpleRegion"));
assertTrue(applicationContext.containsBean("Publisher"));
assertTrue(applicationContext.containsBean("ComplexRegion"));
assertTrue(applicationContext.containsBean("PersistentRegion"));
assertTrue(applicationContext.containsBean("OverflowRegion"));
assertTrue(applicationContext.containsBean("Compressed"));
}
@Test
public void testSimpleClientRegion() throws Exception {
assertTrue(context.containsBean("simple"));
assertTrue(applicationContext.containsBean("simple"));
Region<?, ?> simple = context.getBean("simple", Region.class);
Region<?, ?> simple = applicationContext.getBean("simple", Region.class);
assertNotNull("The 'SimpleRegion' Client Region was not properly configured and initialized!", simple);
assertEquals("SimpleRegion", simple.getName());
@@ -121,9 +119,10 @@ public class ClientRegionNamespaceTest {
@Test
@SuppressWarnings("rawtypes")
public void testPublishingClientRegion() throws Exception {
assertTrue(context.containsBean("empty"));
assertTrue(applicationContext.containsBean("empty"));
ClientRegionFactoryBean emptyClientRegionFactoryBean = context.getBean("&empty", ClientRegionFactoryBean.class);
ClientRegionFactoryBean emptyClientRegionFactoryBean = applicationContext
.getBean("&empty", ClientRegionFactoryBean.class);
assertNotNull(emptyClientRegionFactoryBean);
assertEquals(DataPolicy.EMPTY, TestUtils.readField("dataPolicy", emptyClientRegionFactoryBean));
@@ -135,9 +134,10 @@ public class ClientRegionNamespaceTest {
@Test
@SuppressWarnings("rawtypes")
public void testComplexClientRegion() throws Exception {
assertTrue(context.containsBean("complex"));
assertTrue(applicationContext.containsBean("complex"));
ClientRegionFactoryBean complexClientRegionFactoryBean = context.getBean("&complex", ClientRegionFactoryBean.class);
ClientRegionFactoryBean complexClientRegionFactoryBean = applicationContext
.getBean("&complex", ClientRegionFactoryBean.class);
assertNotNull(complexClientRegionFactoryBean);
@@ -145,7 +145,7 @@ public class ClientRegionNamespaceTest {
assertFalse(ObjectUtils.isEmpty(cacheListeners));
assertEquals(2, cacheListeners.length);
assertSame(cacheListeners[0], context.getBean("c-listener"));
assertSame(cacheListeners[0], applicationContext.getBean("c-listener"));
assertTrue(cacheListeners[1] instanceof SimpleCacheListener);
assertNotSame(cacheListeners[0], cacheListeners[1]);
@@ -161,9 +161,9 @@ public class ClientRegionNamespaceTest {
@Test
@SuppressWarnings({ "deprecation", "rawtypes" })
public void testPersistentClientRegion() throws Exception {
assertTrue(context.containsBean("persistent"));
assertTrue(applicationContext.containsBean("persistent"));
Region persistent = context.getBean("persistent", Region.class);
Region persistent = applicationContext.getBean("persistent", Region.class);
assertNotNull("The 'PersistentRegion' Region was not properly configured and initialized!", persistent);
assertEquals("PersistentRegion", persistent.getName());
@@ -179,9 +179,10 @@ public class ClientRegionNamespaceTest {
@Test
@SuppressWarnings("rawtypes")
public void testOverflowClientRegion() throws Exception {
assertTrue(context.containsBean("overflow"));
assertTrue(applicationContext.containsBean("overflow"));
ClientRegionFactoryBean overflowClientRegionFactoryBean = context.getBean("&overflow", ClientRegionFactoryBean.class);
ClientRegionFactoryBean overflowClientRegionFactoryBean = applicationContext
.getBean("&overflow", ClientRegionFactoryBean.class);
assertNotNull(overflowClientRegionFactoryBean);
assertEquals("diskStore", TestUtils.readField("diskStoreName", overflowClientRegionFactoryBean));
@@ -203,9 +204,9 @@ public class ClientRegionNamespaceTest {
@Test
public void testClientRegionWithCacheLoaderAndCacheWriter() throws Exception {
assertTrue(context.containsBean("loadWithWrite"));
assertTrue(applicationContext.containsBean("loadWithWrite"));
ClientRegionFactoryBean factory = context.getBean("&loadWithWrite", ClientRegionFactoryBean.class);
ClientRegionFactoryBean factory = applicationContext.getBean("&loadWithWrite", ClientRegionFactoryBean.class);
assertNotNull(factory);
assertEquals("LoadedFullOfWrites", TestUtils.readField("name", factory));
@@ -216,9 +217,9 @@ public class ClientRegionNamespaceTest {
@Test
public void testCompressedReplicateRegion() {
assertTrue(context.containsBean("Compressed"));
assertTrue(applicationContext.containsBean("Compressed"));
Region<?, ?> compressed = context.getBean("Compressed", Region.class);
Region<?, ?> compressed = applicationContext.getBean("Compressed", Region.class);
assertNotNull("The 'Compressed' Client Region was not properly configured and initialized!", compressed);
assertEquals("Compressed", compressed.getName());
@@ -235,9 +236,9 @@ public class ClientRegionNamespaceTest {
@Test
@SuppressWarnings("unchecked")
public void testClientRegionWithAttributes() {
assertTrue(context.containsBean("client-with-attributes"));
assertTrue(applicationContext.containsBean("client-with-attributes"));
Region<Long, String> clientRegion = context.getBean("client-with-attributes", Region.class);
Region<Long, String> clientRegion = applicationContext.getBean("client-with-attributes", Region.class);
assertNotNull("The 'client-with-attributes' Client Region was not properly configured and initialized!", clientRegion);
assertEquals("client-with-attributes", clientRegion.getName());
@@ -258,9 +259,11 @@ public class ClientRegionNamespaceTest {
@Test
@SuppressWarnings("unchecked")
public void testClientRegionWithRegisteredInterests() throws Exception {
assertTrue(context.containsBean("client-with-interests"));
ClientRegionFactoryBean factoryBean = context.getBean("&client-with-interests", ClientRegionFactoryBean.class);
assertTrue(applicationContext.containsBean("client-with-interests"));
ClientRegionFactoryBean factoryBean =
applicationContext.getBean("&client-with-interests", ClientRegionFactoryBean.class);
assertNotNull(factoryBean);
@@ -276,10 +279,11 @@ public class ClientRegionNamespaceTest {
assertNotNull(mockClientRegion);
verify(mockClientRegion, times(1)).registerInterest(eq(".*"), eq(InterestResultPolicy.KEYS),
eq(true), eq(false));
verify(mockClientRegion, times(1)).registerInterestRegex(eq("keyPrefix.*"), eq(InterestResultPolicy.KEYS_VALUES),
eq(true), eq(false));
verify(mockClientRegion, times(1)).registerInterest(eq(".*"),
eq(InterestResultPolicy.KEYS), eq(true), eq(false));
verify(mockClientRegion, times(1)).registerInterestRegex(eq("keyPrefix.*"),
eq(InterestResultPolicy.KEYS_VALUES), eq(true), eq(false));
}
protected void assertInterest(final boolean expectedDurable, final boolean expectedReceiveValues,
@@ -300,38 +304,41 @@ public class ClientRegionNamespaceTest {
return null;
}
public static final class MockCacheFactoryBean implements FactoryBean<ClientCache>, InitializingBean {
static final class MockCacheFactoryBean implements FactoryBean<ClientCache>, InitializingBean {
protected static final AtomicReference<Region> MOCK_REGION_REF = new AtomicReference<Region>(null);
static final AtomicReference<Region> MOCK_REGION_REF = new AtomicReference<Region>(null);
private ClientCache mockClientCache;
@Override
@SuppressWarnings("unchecked")
public void afterPropertiesSet() throws Exception {
mockClientCache = mock(ClientCache.class, ClientRegionNamespaceTest.class.getSimpleName()
.concat(".MockClientCache"));
this.mockClientCache = mock(ClientCache.class,
ClientRegionNamespaceTest.class.getSimpleName().concat(".MockClientCache"));
MOCK_REGION_REF.compareAndSet(null, mock(Region.class, ClientRegionNamespaceTest.class.getSimpleName()
.concat(".MockClientRegion")));
ClientRegionFactory mockClientRegionFactory = mock(ClientRegionFactory.class,
ClientRegionNamespaceTest.class.getSimpleName().concat("MockClientRegionFactory"));
when(mockClientCache.getRegion(anyString())).thenReturn(MOCK_REGION_REF.get());
when(this.mockClientCache.createClientRegionFactory(any(ClientRegionShortcut.class)))
.thenReturn(mockClientRegionFactory);
Region mockRegion = mock(Region.class,
ClientRegionNamespaceTest.class.getSimpleName().concat(".MockClientRegion"));
when(mockClientRegionFactory.create(anyString())).thenReturn(mockRegion);
MOCK_REGION_REF.compareAndSet(null, mockRegion);
}
@Override
public ClientCache getObject() throws Exception {
return mockClientCache;
return this.mockClientCache;
}
@Override
public Class<?> getObjectType() {
return ClientCache.class;
}
@Override
public boolean isSingleton() {
return true;
}
}
public static final class TestCacheLoader implements CacheLoader<Object, Object> {
@@ -371,6 +378,5 @@ public class ClientRegionNamespaceTest {
public String toString() {
return this.name;
}
}
}

View File

@@ -37,15 +37,18 @@ import org.springframework.data.gemfire.RegionFactoryBean;
*/
public class InvalidRegionDefinitionUsingBeansNamespaceTest {
private static final String CONFIG_LOCATION =
"org/springframework/data/gemfire/config/xml/InvalidDataPolicyPersistentAttributeSettingsBeansNamespaceTest.xml";
@Test(expected = IllegalArgumentException.class)
public void testInvalidDataPolicyPersistentAttributeSettings() {
try {
new ClassPathXmlApplicationContext(
"org/springframework/data/gemfire/config/xml/InvalidDataPolicyPersistentAttributeSettingsBeansNamespaceTest.xml");
new ClassPathXmlApplicationContext(CONFIG_LOCATION);
}
catch (BeanCreationException expected) {
assertTrue(expected.getCause() instanceof IllegalArgumentException);
assertEquals("Data Policy 'REPLICATE' is invalid when persistent is true.", expected.getCause().getMessage());
assertEquals("Data Policy [REPLICATE] is invalid when persistent is true.", expected.getCause().getMessage());
throw (IllegalArgumentException) expected.getCause();
}
}
@@ -53,5 +56,4 @@ public class InvalidRegionDefinitionUsingBeansNamespaceTest {
@SuppressWarnings("unused")
public static final class TestRegionFactoryBean<K, V> extends RegionFactoryBean<K, V> {
}
}

View File

@@ -44,9 +44,9 @@ public class SubRegionWithInvalidDataPolicyTest {
"/org/springframework/data/gemfire/config/xml/subregion-with-invalid-datapolicy.xml");
}
catch (XmlBeanDefinitionStoreException expected) {
//expected.printStackTrace(System.err);
assertTrue(expected.getCause() instanceof SAXParseException);
assertTrue(expected.getCause().getMessage().contains("PERSISTENT_PARTITION"));
throw expected;
}
}
@@ -58,13 +58,12 @@ public class SubRegionWithInvalidDataPolicyTest {
"/org/springframework/data/gemfire/config/xml/subregion-with-inconsistent-datapolicy-persistent-settings.xml");
}
catch (BeanCreationException expected) {
//expected.printStackTrace(System.err);
assertTrue(expected.getMessage().contains("Error creating bean with name '/Parent/Child'"));
assertTrue(expected.getCause() instanceof IllegalArgumentException);
assertEquals("Data Policy 'REPLICATE' is invalid when persistent is true.",
assertEquals("Data Policy [REPLICATE] is invalid when persistent is true.",
expected.getCause().getMessage());
throw expected;
}
}
}

View File

@@ -84,6 +84,7 @@ public class ClientCacheFunctionExecutionWithPdxIntegrationTest extends ClientSe
@BeforeClass
public static void startGemFireServer() throws Exception {
int availablePort = findAvailablePort();
gemfireServer = run(ServerProcess.class,
@@ -101,8 +102,10 @@ public class ClientCacheFunctionExecutionWithPdxIntegrationTest extends ClientSe
stop(gemfireServer);
}
protected PdxInstance toPdxInstance(final Map<String, Object> pdxData) {
PdxInstanceFactory pdxInstanceFactory = gemfireClientCache.createPdxInstanceFactory(pdxData.get("@type").toString());
private PdxInstance toPdxInstance(Map<String, Object> pdxData) {
PdxInstanceFactory pdxInstanceFactory =
gemfireClientCache.createPdxInstanceFactory(pdxData.get("@type").toString());
for (Map.Entry<String, Object> entry : pdxData.entrySet()) {
pdxInstanceFactory.writeObject(entry.getKey(), entry.getValue());
@@ -112,9 +115,10 @@ public class ClientCacheFunctionExecutionWithPdxIntegrationTest extends ClientSe
}
@Test
public void testConvertedFunctionArgumentTypes() {
Class[] argumentTypes = functionExecutions.captureConvertedArgumentTypes("test", 1, Boolean.TRUE,
new Person("Jon", "Doe"), Gender.MALE);
public void convertedFunctionArgumentTypes() {
Class[] argumentTypes = functionExecutions.captureConvertedArgumentTypes("test", 1,
Boolean.TRUE, new Person("Jon", "Doe"), Gender.MALE);
assertNotNull(argumentTypes);
assertEquals(5, argumentTypes.length);
@@ -126,9 +130,10 @@ public class ClientCacheFunctionExecutionWithPdxIntegrationTest extends ClientSe
}
@Test
public void testUnconvertedFunctionArgumentTypes() {
Class[] argumentTypes = functionExecutions.captureUnconvertedArgumentTypes("test", 2, Boolean.FALSE,
new Person("Jane", "Doe"), Gender.FEMALE);
public void unconvertedFunctionArgumentTypes() {
Class[] argumentTypes = functionExecutions.captureUnconvertedArgumentTypes("test", 2,
Boolean.FALSE, new Person("Jane", "Doe"), Gender.FEMALE);
assertNotNull(argumentTypes);
assertEquals(5, argumentTypes.length);
@@ -140,13 +145,14 @@ public class ClientCacheFunctionExecutionWithPdxIntegrationTest extends ClientSe
}
@Test
public void testGetAddressFieldValue() {
public void getAddressFieldValue() {
assertEquals("Portland", functionExecutions.getAddressField(new Address(
"100 Main St.", "Portland", "OR", "97205"), "city"));
}
@Test
public void testPdxDataFieldValue() {
public void pdxDataFieldValue() {
Map<String, Object> pdxData = new HashMap<String, Object>(3);
pdxData.put("@type", "x.y.z.domain.MyApplicationDomainType");
@@ -162,6 +168,7 @@ public class ClientCacheFunctionExecutionWithPdxIntegrationTest extends ClientSe
public static class ApplicationDomainFunctions {
private Class[] getArgumentTypes(final Object... arguments) {
Class[] argumentTypes = new Class[arguments.length];
int index = 0;
@@ -174,25 +181,27 @@ public class ClientCacheFunctionExecutionWithPdxIntegrationTest extends ClientSe
}
@GemfireFunction
public Class[] captureConvertedArgumentTypes(final String stringValue, final Integer integerValue,
final Boolean booleanValue, final Person person, final Gender gender) {
public Class[] captureConvertedArgumentTypes(String stringValue, Integer integerValue, Boolean booleanValue,
Person person, Gender gender) {
return getArgumentTypes(stringValue, integerValue, booleanValue, person, gender);
}
@GemfireFunction
public Class[] captureUnconvertedArgumentTypes(final String stringValue, final Integer integerValue,
final Boolean booleanValue, final Object domainObject, final Object enumValue) {
public Class[] captureUnconvertedArgumentTypes(String stringValue, Integer integerValue, Boolean booleanValue,
Object domainObject, Object enumValue) {
return getArgumentTypes(stringValue, integerValue, booleanValue, domainObject, enumValue);
}
@GemfireFunction
public String getAddressField(final PdxInstance address, final String fieldName) {
Assert.isTrue(Address.class.getName().equals(address.getClassName()));
public String getAddressField(PdxInstance address, String fieldName) {
Assert.isTrue(Address.class.getName().equals(address.getClassName()), "Address is not the correct type");
return String.valueOf(address.getField(fieldName));
}
@GemfireFunction
public Object getDataField(final PdxInstance data, final String fieldName) {
public Object getDataField(PdxInstance data, String fieldName) {
return data.getField(fieldName);
}
}
@@ -204,11 +213,12 @@ public class ClientCacheFunctionExecutionWithPdxIntegrationTest extends ClientSe
private final String state; // refactor; use Enum!
private final String zipCode;
public Address(final String street, final String city, final String state, final String zipCode) {
public Address(String street, String city, String state, String zipCode) {
Assert.hasText("The Address 'street' must be specified", street);
Assert.hasText("The Address 'city' must be specified", city);
Assert.hasText("The Address 'state' must be specified", state);
Assert.hasText("The Address 'zipCode' must be specified", zipCode);
this.street = street;
this.city = city;
this.state = state;
@@ -233,6 +243,7 @@ public class ClientCacheFunctionExecutionWithPdxIntegrationTest extends ClientSe
@Override
public boolean equals(final Object obj) {
if (obj == this) {
return true;
}
@@ -251,11 +262,14 @@ public class ClientCacheFunctionExecutionWithPdxIntegrationTest extends ClientSe
@Override
public int hashCode() {
int hashValue = 17;
hashValue = 37 * hashValue + ObjectUtils.nullSafeHashCode(getStreet());
hashValue = 37 * hashValue + ObjectUtils.nullSafeHashCode(getCity());
hashValue = 37 * hashValue + ObjectUtils.nullSafeHashCode(getState());
hashValue = 37 * hashValue + ObjectUtils.nullSafeHashCode(getZipCode());
return hashValue;
}
@@ -275,9 +289,10 @@ public class ClientCacheFunctionExecutionWithPdxIntegrationTest extends ClientSe
private final String firstName;
private final String lastName;
public Person(final String firstName, final String lastName) {
public Person(String firstName, String lastName) {
Assert.hasText(firstName, "The person's first name must be specified!");
Assert.hasText(lastName, "The person's last name must be specified!");
this.firstName = firstName;
this.lastName = lastName;
}
@@ -292,6 +307,7 @@ public class ClientCacheFunctionExecutionWithPdxIntegrationTest extends ClientSe
@Override
public boolean equals(final Object obj) {
if (obj == this) {
return true;
}
@@ -308,9 +324,12 @@ public class ClientCacheFunctionExecutionWithPdxIntegrationTest extends ClientSe
@Override
public int hashCode() {
int hashValue = 17;
hashValue = 37 * hashValue + ObjectUtils.nullSafeHashCode(getFirstName());
hashValue = 37 * hashValue + ObjectUtils.nullSafeHashCode(getLastName());
return hashValue;
}
@@ -324,18 +343,18 @@ public class ClientCacheFunctionExecutionWithPdxIntegrationTest extends ClientSe
private final PdxSerializer[] pdxSerializers;
private ComposablePdxSerializer(final PdxSerializer[] pdxSerializers) {
private ComposablePdxSerializer(PdxSerializer[] pdxSerializers) {
this.pdxSerializers = pdxSerializers;
}
public static PdxSerializer compose(final PdxSerializer... pdxSerializers) {
public static PdxSerializer compose(PdxSerializer... pdxSerializers) {
return (pdxSerializers == null ? null : (pdxSerializers.length == 1 ? pdxSerializers[0]
: new ComposablePdxSerializer(pdxSerializers)));
}
@Override
public boolean toData(final Object obj, final PdxWriter out) {
for (PdxSerializer pdxSerializer : pdxSerializers) {
public boolean toData(Object obj, PdxWriter out) {
for (PdxSerializer pdxSerializer : this.pdxSerializers) {
if (pdxSerializer.toData(obj, out)) {
return true;
}
@@ -345,8 +364,8 @@ public class ClientCacheFunctionExecutionWithPdxIntegrationTest extends ClientSe
}
@Override
public Object fromData(final Class<?> type, final PdxReader in) {
for (PdxSerializer pdxSerializer : pdxSerializers) {
public Object fromData(Class<?> type, final PdxReader in) {
for (PdxSerializer pdxSerializer : this.pdxSerializers) {
Object obj = pdxSerializer.fromData(type, in);
if (obj != null) {
@@ -393,7 +412,8 @@ public class ClientCacheFunctionExecutionWithPdxIntegrationTest extends ClientSe
public static class AddressPdxSerializer implements PdxSerializer {
@Override
public boolean toData(final Object obj, final PdxWriter out) {
public boolean toData(Object obj, PdxWriter out) {
if (obj instanceof Address) {
Address address = (Address) obj;
out.writeString("street", address.getStreet());
@@ -407,7 +427,8 @@ public class ClientCacheFunctionExecutionWithPdxIntegrationTest extends ClientSe
}
@Override
public Object fromData(final Class<?> type, final PdxReader in) {
public Object fromData(Class<?> type, PdxReader in) {
if (Address.class.isAssignableFrom(type)) {
return new Address(in.readString("street"), in.readString("city"), in.readString("state"),
in.readString("zipCode"));
@@ -419,7 +440,8 @@ public class ClientCacheFunctionExecutionWithPdxIntegrationTest extends ClientSe
public static class PersonPdxSerializer implements PdxSerializer {
@Override
public boolean toData(final Object obj, final PdxWriter out) {
public boolean toData(Object obj, PdxWriter out) {
if (obj instanceof Person) {
Person person = (Person) obj;
out.writeString("firstName", person.getFirstName());
@@ -431,7 +453,7 @@ public class ClientCacheFunctionExecutionWithPdxIntegrationTest extends ClientSe
}
@Override
public Object fromData(final Class<?> type, final PdxReader in) {
public Object fromData(Class<?> type, PdxReader in) {
if (Person.class.isAssignableFrom(type)) {
return new Person(in.readString("firstName"), in.readString("lastName"));
}

View File

@@ -32,44 +32,45 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;
import org.springframework.data.gemfire.function.execution.GemfireOnServerFunctionTemplate;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.junit4.SpringRunner;
/**
* @author David Turanski
*
*/
@RunWith(SpringJUnit4ClassRunner.class)
@RunWith(SpringRunner.class)
@ContextConfiguration(classes = { TestClientCacheConfig.class })
public class FunctionExecutionClientCacheTests {
@Autowired
ApplicationContext context;
ApplicationContext applicationContext;
@Test
public void contextCreated() throws Exception {
ClientCache cache = context.getBean("gemfireCache", ClientCache.class);
Pool pool = context.getBean("gemfirePool", Pool.class);
ClientCache cache = applicationContext.getBean("gemfireCache", ClientCache.class);
Pool pool = applicationContext.getBean("gemfirePool", Pool.class);
assertEquals("gemfirePool", pool.getName());
assertTrue(cache.getDefaultPool().getLocators().isEmpty());
assertEquals(1, cache.getDefaultPool().getServers().size());
assertEquals(pool.getServers().get(0), cache.getDefaultPool().getServers().get(0));
Region region = context.getBean("r1", Region.class);
Region region = applicationContext.getBean("r1", Region.class);
assertEquals("gemfirePool", region.getAttributes().getPoolName());
GemfireOnServerFunctionTemplate template = context.getBean(GemfireOnServerFunctionTemplate.class);
GemfireOnServerFunctionTemplate template = applicationContext.getBean(GemfireOnServerFunctionTemplate.class);
assertTrue(template.getResultCollector() instanceof MyResultCollector);
}
}
@Configuration
@ImportResource("/org/springframework/data/gemfire/function/config/FunctionExecutionCacheClientTests-context.xml")
@EnableGemfireFunctionExecutions(basePackages = "org.springframework.data.gemfire.function.config.three")
class TestClientCacheConfig {
@Bean
MyResultCollector myResultCollector() {
return new MyResultCollector();
@@ -115,5 +116,4 @@ class MyResultCollector implements ResultCollector {
public Object getResult(long arg0, TimeUnit arg1) throws FunctionException, InterruptedException {
return null;
}
}

View File

@@ -23,14 +23,12 @@ import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.data.gemfire.CacheFactoryBean;
import org.springframework.data.gemfire.LocalRegionFactoryBean;
import org.springframework.data.gemfire.config.annotation.PeerCacheApplication;
import org.springframework.data.gemfire.repository.sample.Person;
import org.springframework.data.gemfire.repository.sample.PersonRepository;
import org.springframework.data.gemfire.test.GemfireTestApplicationContextInitializer;
import org.springframework.data.gemfire.test.MockCacheFactoryBean;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@@ -39,29 +37,24 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
* repository configuration).
*
* @author Oliver Gierke
* @author John Blum
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(initializers=GemfireTestApplicationContextInitializer.class)
public class GemfireRepositoriesRegistrarIntegrationTest {
@Configuration
@PeerCacheApplication
@EnableGemfireRepositories(value = "org.springframework.data.gemfire.repository.sample",
includeFilters = @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,
value = org.springframework.data.gemfire.repository.sample.PersonRepository.class))
static class Config {
@Bean
public GemFireCache cache() throws Exception {
public Region<Long, Person> simple(GemFireCache gemfireCache) throws Exception {
CacheFactoryBean factory = new MockCacheFactoryBean();
return factory.getObject();
}
LocalRegionFactoryBean<Long, Person> factory = new LocalRegionFactoryBean<>();
@Bean
public Region<Long, Person> simple() throws Exception {
LocalRegionFactoryBean<Long, Person> factory = new LocalRegionFactoryBean<Long, Person>();
factory.setCache(cache());
factory.setCache(gemfireCache);
factory.setName("simple");
factory.afterPropertiesSet();
@@ -75,5 +68,4 @@ public class GemfireRepositoriesRegistrarIntegrationTest {
@Test
public void bootstrapsRepositoriesCorrectly() {
}
}

View File

@@ -102,7 +102,7 @@ public class LuceneIndexFactoryBeanUnitTests {
doReturn(mockCache).when(factoryBean).resolveCache();
doReturn(mockLuceneService).when(factoryBean).resolveLuceneService();
doReturn("/Example").when(factoryBean).resolveRegionPath();
doReturn(mockLuceneIndex).when(factoryBean).createIndex(eq("ExampleIndex"), eq("/Example"));
doReturn(mockLuceneIndex).when(factoryBean).createLuceneIndex(eq("ExampleIndex"), eq("/Example"));
factoryBean.setIndexName("ExampleIndex");
@@ -113,10 +113,10 @@ public class LuceneIndexFactoryBeanUnitTests {
assertThat(factoryBean.getObject()).isEqualTo(mockLuceneIndex);
verify(factoryBean, times(1)).resolveCache();
verify(factoryBean, times(1)).resolveLuceneService();
verify(factoryBean, times(2)).resolveLuceneService();
verify(factoryBean, times(1)).resolveRegionPath();
verify(factoryBean, times(1))
.createIndex(eq("ExampleIndex"), eq("/Example"));
.createLuceneIndex(eq("ExampleIndex"), eq("/Example"));
}
@Test
@@ -129,7 +129,7 @@ public class LuceneIndexFactoryBeanUnitTests {
}
@Test
public void createIndexWithAllFields() {
public void createLuceneIndexWithAllFields() {
factoryBean.setLuceneService(mockLuceneService);
when(mockLuceneService.getIndex(eq("ExampleIndex"), eq("/Example"))).thenReturn(mockLuceneIndex);
@@ -137,7 +137,7 @@ public class LuceneIndexFactoryBeanUnitTests {
assertThat(factoryBean.getFieldAnalyzers()).isEmpty();
assertThat(factoryBean.getFields()).isEmpty();
assertThat(factoryBean.getLuceneService()).isSameAs(mockLuceneService);
assertThat(factoryBean.createIndex("ExampleIndex", "/Example")).isEqualTo(mockLuceneIndex);
assertThat(factoryBean.createLuceneIndex("ExampleIndex", "/Example")).isEqualTo(mockLuceneIndex);
verify(mockLuceneService, times(1))
.createIndex(eq("ExampleIndex"), eq("/Example"), eq(LuceneService.REGION_VALUE_FIELD));
@@ -146,7 +146,7 @@ public class LuceneIndexFactoryBeanUnitTests {
}
@Test
public void createIndexWithFieldAnalyzers() {
public void createLuceneIndexWithFieldAnalyzers() {
Map<String, Analyzer> fieldAnalyzers = Collections.singletonMap("fieldOne", mockAnalyzer);
factoryBean.setFieldAnalyzers(fieldAnalyzers);
@@ -157,7 +157,7 @@ public class LuceneIndexFactoryBeanUnitTests {
assertThat(factoryBean.getFieldAnalyzers()).isEqualTo(fieldAnalyzers);
assertThat(factoryBean.getFields()).isEmpty();
assertThat(factoryBean.getLuceneService()).isSameAs(mockLuceneService);
assertThat(factoryBean.createIndex("ExampleIndex", "/Example")).isEqualTo(mockLuceneIndex);
assertThat(factoryBean.createLuceneIndex("ExampleIndex", "/Example")).isEqualTo(mockLuceneIndex);
verify(mockLuceneService, times(1))
.createIndex(eq("ExampleIndex"), eq("/Example"), eq(fieldAnalyzers));
@@ -166,7 +166,7 @@ public class LuceneIndexFactoryBeanUnitTests {
}
@Test
public void createIndexWithTargetedFields() {
public void createLuceneIndexWithTargetedFields() {
factoryBean.setFields("fieldOne", "fieldTwo");
factoryBean.setLuceneService(mockLuceneService);
@@ -175,7 +175,7 @@ public class LuceneIndexFactoryBeanUnitTests {
assertThat(factoryBean.getFieldAnalyzers()).isEmpty();
assertThat(factoryBean.getFields()).containsAll(Arrays.asList("fieldOne", "fieldTwo"));
assertThat(factoryBean.getLuceneService()).isSameAs(mockLuceneService);
assertThat(factoryBean.createIndex("ExampleIndex", "/Example")).isEqualTo(mockLuceneIndex);
assertThat(factoryBean.createLuceneIndex("ExampleIndex", "/Example")).isEqualTo(mockLuceneIndex);
verify(mockLuceneService, times(1))
.createIndex(eq("ExampleIndex"), eq("/Example"), eq("fieldOne"), eq("fieldTwo"));

View File

@@ -44,11 +44,12 @@ import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
/**
* The CacheServerFactoryBeanTest class is a test suite of test cases testing the contract and functionality
* of the CacheServerFactoryBean class.
* Unit tests for {@link CacheServerFactoryBean}.
*
* @author John Blum
* @see org.junit.Test
* @see org.apache.geode.cache.Cache
* @see org.apache.geode.cache.server.CacheServer
* @see org.springframework.data.gemfire.server.CacheServerFactoryBean
* @since 1.6.0
*/
@@ -146,7 +147,7 @@ public class CacheServerFactoryBeanTest {
new CacheServerFactoryBean().afterPropertiesSet();
}
catch (IllegalArgumentException expected) {
assertEquals("A GemFire Cache is required.", expected.getMessage());
assertEquals("Cache is required", expected.getMessage());
throw expected;
}
}
@@ -228,5 +229,4 @@ public class CacheServerFactoryBeanTest {
assertFalse(factoryBean.isRunning());
assertTrue(called.get());
}
}

View File

@@ -0,0 +1,168 @@
/*
* Copyright 2017 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.support;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import org.apache.commons.logging.Log;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Spy;
import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.beans.factory.BeanFactory;
/**
* Unit tests for {@link AbstractFactoryBeanSupport}.
*
* @author John Blum
* @see org.junit.Test
* @see org.mockito.Mock
* @see org.mockito.Mockito
* @see org.mockito.Spy
* @see org.springframework.data.gemfire.support.AbstractFactoryBeanSupport
* @since 1.0.0
*/
@RunWith(MockitoJUnitRunner.class)
public class AbstractFactoryBeanSupportUnitTests {
@Mock
private Log mockLog;
@Spy
private TestFactoryBeanSupport<?> factoryBeanSupport;
@Before
public void setup() {
when(factoryBeanSupport.getLog()).thenReturn(mockLog);
}
@Test
public void setAndGetBeanClassLoader() {
assertThat(factoryBeanSupport.getBeanClassLoader()).isNull();
ClassLoader mockClassLoader = mock(ClassLoader.class);
factoryBeanSupport.setBeanClassLoader(mockClassLoader);
assertThat(factoryBeanSupport.getBeanClassLoader()).isSameAs(mockClassLoader);
ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
factoryBeanSupport.setBeanClassLoader(systemClassLoader);
assertThat(factoryBeanSupport.getBeanClassLoader()).isSameAs(systemClassLoader);
factoryBeanSupport.setBeanClassLoader(null);
assertThat(factoryBeanSupport.getBeanClassLoader()).isNull();
}
@Test
public void setAndGetBeanFactory() {
assertThat(factoryBeanSupport.getBeanFactory()).isNull();
BeanFactory mockBeanFactory = mock(BeanFactory.class);
factoryBeanSupport.setBeanFactory(mockBeanFactory);
assertThat(factoryBeanSupport.getBeanFactory()).isSameAs(mockBeanFactory);
factoryBeanSupport.setBeanFactory(null);
assertThat(factoryBeanSupport.getBeanFactory()).isNull();
}
@Test
public void setAndGetBeanName() {
assertThat(factoryBeanSupport.getBeanName()).isNullOrEmpty();
factoryBeanSupport.setBeanName("test");
assertThat(factoryBeanSupport.getBeanName()).isEqualTo("test");
factoryBeanSupport.setBeanName(null);
assertThat(factoryBeanSupport.getBeanName()).isNullOrEmpty();
}
@Test
public void isSingletonDefaultsToTrue() {
assertThat(factoryBeanSupport.isSingleton()).isTrue();
}
@Test
public void logsDebugWhenDebugIsEnabled() {
when(mockLog.isDebugEnabled()).thenReturn(true);
factoryBeanSupport.logDebug("%s log test", "debug");
verify(mockLog, times(1)).isDebugEnabled();
verify(mockLog, times(1)).debug(eq("debug log test"));
}
@Test
public void logsInfoWhenInfoIsEnabled() {
when(mockLog.isInfoEnabled()).thenReturn(true);
factoryBeanSupport.logInfo("%s log test", "info");
verify(mockLog, times(1)).isInfoEnabled();
verify(mockLog, times(1)).info(eq("info log test"));
}
@Test
public void suppressesDebugLoggingWhenDebugIsDisabled() {
when(mockLog.isDebugEnabled()).thenReturn(false);
factoryBeanSupport.logDebug(() -> "test");
verify(mockLog, times(1)).isDebugEnabled();
verify(mockLog, never()).debug(any());
}
@Test
public void suppressesInfoLoggingWhenInfoIsDisabled() {
when(mockLog.isInfoEnabled()).thenReturn(false);
factoryBeanSupport.logInfo(() -> "test");
verify(mockLog, times(1)).isInfoEnabled();
verify(mockLog, never()).info(any());
}
private static class TestFactoryBeanSupport<T> extends AbstractFactoryBeanSupport<T> {
@Override
public T getObject() throws Exception {
return null;
}
@Override
public Class<?> getObjectType() {
return Object.class;
}
}
}

View File

@@ -13,6 +13,8 @@
package org.springframework.data.gemfire.test;
import java.util.Optional;
import org.apache.geode.cache.GemFireCache;
import org.springframework.data.gemfire.CacheFactoryBean;
@@ -27,36 +29,39 @@ public class MockCacheFactoryBean extends CacheFactoryBean {
}
public MockCacheFactoryBean(CacheFactoryBean cacheFactoryBean) {
setUseBeanFactoryLocator(false);
if (cacheFactoryBean != null) {
setBeanClassLoader(cacheFactoryBean.getBeanClassLoader());
setBeanFactory(cacheFactoryBean.getBeanFactory());
setBeanName(cacheFactoryBean.getBeanName());
setCacheXml(cacheFactoryBean.getCacheXml());
setPhase(cacheFactoryBean.getPhase());
setProperties(cacheFactoryBean.getProperties());
setClose(cacheFactoryBean.getClose());
setCopyOnRead(cacheFactoryBean.getCopyOnRead());
setCriticalHeapPercentage(cacheFactoryBean.getCriticalHeapPercentage());
setDynamicRegionSupport(cacheFactoryBean.getDynamicRegionSupport());
setEnableAutoReconnect(cacheFactoryBean.getEnableAutoReconnect());
setEvictionHeapPercentage(cacheFactoryBean.getEvictionHeapPercentage());
setGatewayConflictResolver(cacheFactoryBean.getGatewayConflictResolver());
setJndiDataSources(cacheFactoryBean.getJndiDataSources());
setLockLease(cacheFactoryBean.getLockLease());
setLockTimeout(cacheFactoryBean.getLockTimeout());
setMessageSyncInterval(cacheFactoryBean.getMessageSyncInterval());
setPdxDiskStoreName(cacheFactoryBean.getPdxDiskStoreName());
setPdxIgnoreUnreadFields(cacheFactoryBean.getPdxIgnoreUnreadFields());
setPdxPersistent(cacheFactoryBean.getPdxPersistent());
setPdxReadSerialized(cacheFactoryBean.getPdxReadSerialized());
setPdxSerializer(cacheFactoryBean.getPdxSerializer());
setSearchTimeout(cacheFactoryBean.getSearchTimeout());
setTransactionListeners(cacheFactoryBean.getTransactionListeners());
setTransactionWriter(cacheFactoryBean.getTransactionWriter());
setUseBeanFactoryLocator(cacheFactoryBean.isUseBeanFactoryLocator());
}
Optional.ofNullable(cacheFactoryBean).ifPresent(it -> {
setBeanClassLoader(it.getBeanClassLoader());
setBeanFactory(it.getBeanFactory());
setBeanName(it.getBeanName());
setCacheXml(it.getCacheXml());
setPhase(it.getPhase());
setProperties(it.getProperties());
setClose(it.isClose());
setCopyOnRead(it.getCopyOnRead());
setCriticalHeapPercentage(it.getCriticalHeapPercentage());
setDynamicRegionSupport(it.getDynamicRegionSupport());
setEnableAutoReconnect(it.getEnableAutoReconnect());
setEvictionHeapPercentage(it.getEvictionHeapPercentage());
setGatewayConflictResolver(it.getGatewayConflictResolver());
setJndiDataSources(it.getJndiDataSources());
setLockLease(it.getLockLease());
setLockTimeout(it.getLockTimeout());
setMessageSyncInterval(it.getMessageSyncInterval());
setPdxDiskStoreName(it.getPdxDiskStoreName());
setPdxIgnoreUnreadFields(it.getPdxIgnoreUnreadFields());
setPdxPersistent(it.getPdxPersistent());
setPdxReadSerialized(it.getPdxReadSerialized());
setPdxSerializer(it.getPdxSerializer());
setSearchTimeout(it.getSearchTimeout());
setTransactionListeners(it.getTransactionListeners());
setTransactionWriter(it.getTransactionWriter());
setUseBeanFactoryLocator(it.isUseBeanFactoryLocator());
});
applyPeerCacheConfigurers(cacheFactoryBean.getCompositePeerCacheConfigurer());
}
@Override
@@ -66,5 +71,4 @@ public class MockCacheFactoryBean extends CacheFactoryBean {
stubCache.setProperties(getProperties());
return (T) stubCache;
}
}

View File

@@ -12,6 +12,8 @@
*/
package org.springframework.data.gemfire.test;
import java.util.Optional;
import org.apache.geode.cache.GemFireCache;
import org.springframework.data.gemfire.client.ClientCacheFactoryBean;
@@ -22,38 +24,41 @@ import org.springframework.data.gemfire.client.ClientCacheFactoryBean;
public class MockClientCacheFactoryBean extends ClientCacheFactoryBean {
public MockClientCacheFactoryBean(ClientCacheFactoryBean clientCacheFactoryBean) {
setUseBeanFactoryLocator(false);
if (clientCacheFactoryBean != null) {
this.beanFactoryLocator = clientCacheFactoryBean.getBeanFactoryLocator();
setBeanClassLoader(clientCacheFactoryBean.getBeanClassLoader());
setBeanFactory(clientCacheFactoryBean.getBeanFactory());
setBeanName(clientCacheFactoryBean.getBeanName());
setCacheXml(clientCacheFactoryBean.getCacheXml());
setCopyOnRead(clientCacheFactoryBean.getCopyOnRead());
setCriticalHeapPercentage(clientCacheFactoryBean.getCriticalHeapPercentage());
setDurableClientId(clientCacheFactoryBean.getDurableClientId());
setDurableClientTimeout(clientCacheFactoryBean.getDurableClientTimeout());
setDynamicRegionSupport(clientCacheFactoryBean.getDynamicRegionSupport());
setEvictionHeapPercentage(clientCacheFactoryBean.getEvictionHeapPercentage());
setGatewayConflictResolver(clientCacheFactoryBean.getGatewayConflictResolver());
setJndiDataSources(clientCacheFactoryBean.getJndiDataSources());
setKeepAlive(clientCacheFactoryBean.isKeepAlive());
setLockLease(clientCacheFactoryBean.getLockLease());
setLockTimeout(clientCacheFactoryBean.getLockTimeout());
setMessageSyncInterval(clientCacheFactoryBean.getMessageSyncInterval());
setPdxDiskStoreName(clientCacheFactoryBean.getPdxDiskStoreName());
setPdxIgnoreUnreadFields(clientCacheFactoryBean.getPdxIgnoreUnreadFields());
setPdxPersistent(clientCacheFactoryBean.getPdxPersistent());
setPdxReadSerialized(clientCacheFactoryBean.getPdxReadSerialized());
setPdxSerializer(clientCacheFactoryBean.getPdxSerializer());
setPoolName(clientCacheFactoryBean.getPoolName());
setProperties(clientCacheFactoryBean.getProperties());
setReadyForEvents(clientCacheFactoryBean.getReadyForEvents());
setSearchTimeout(clientCacheFactoryBean.getSearchTimeout());
setTransactionListeners(clientCacheFactoryBean.getTransactionListeners());
setTransactionWriter(clientCacheFactoryBean.getTransactionWriter());
}
Optional.ofNullable(clientCacheFactoryBean).ifPresent(it -> {
this.beanFactoryLocator = it.getBeanFactoryLocator();
setBeanClassLoader(it.getBeanClassLoader());
setBeanFactory(it.getBeanFactory());
setBeanName(it.getBeanName());
setCacheXml(it.getCacheXml());
setCopyOnRead(it.getCopyOnRead());
setCriticalHeapPercentage(it.getCriticalHeapPercentage());
setDurableClientId(it.getDurableClientId());
setDurableClientTimeout(it.getDurableClientTimeout());
setDynamicRegionSupport(it.getDynamicRegionSupport());
setEvictionHeapPercentage(it.getEvictionHeapPercentage());
setGatewayConflictResolver(it.getGatewayConflictResolver());
setJndiDataSources(it.getJndiDataSources());
setKeepAlive(it.isKeepAlive());
setLockLease(it.getLockLease());
setLockTimeout(it.getLockTimeout());
setMessageSyncInterval(it.getMessageSyncInterval());
setPdxDiskStoreName(it.getPdxDiskStoreName());
setPdxIgnoreUnreadFields(it.getPdxIgnoreUnreadFields());
setPdxPersistent(it.getPdxPersistent());
setPdxReadSerialized(it.getPdxReadSerialized());
setPdxSerializer(it.getPdxSerializer());
setPoolName(it.getPoolName());
setProperties(it.getProperties());
setReadyForEvents(it.getReadyForEvents());
setSearchTimeout(it.getSearchTimeout());
setTransactionListeners(it.getTransactionListeners());
setTransactionWriter(it.getTransactionWriter());
});
applyClientCacheConfigurers(clientCacheFactoryBean.getCompositeClientCacheConfigurer());
}
@SuppressWarnings("unchecked")
@@ -62,6 +67,4 @@ public class MockClientCacheFactoryBean extends ClientCacheFactoryBean {
stubCache.setProperties(getProperties());
return (T) stubCache;
}
}

View File

@@ -16,18 +16,17 @@
<context:property-placeholder/>
<util:properties id="gemfireProperties">
<prop key="log-level">warning</prop>
<prop key="log-level">config</prop>
</util:properties>
<gfe:pool id="serverConnectionPool">
<gfe:server host="localhost" port="${spring.data.gemfire.cache.server.port:40404}"/>
</gfe:pool>
<bean id="addressPdxSerializer"
class="org.springframework.data.gemfire.function.ClientCacheFunctionExecutionWithPdxIntegrationTest$AddressPdxSerializer"/>
<bean id="addressPdxSerializer" class="org.springframework.data.gemfire.function.ClientCacheFunctionExecutionWithPdxIntegrationTest$AddressPdxSerializer"/>
<bean id="personPdxSerializer"
class="org.springframework.data.gemfire.function.ClientCacheFunctionExecutionWithPdxIntegrationTest$PersonPdxSerializer"/>
<bean id="personPdxSerializer" class="org.springframework.data.gemfire.function.ClientCacheFunctionExecutionWithPdxIntegrationTest$PersonPdxSerializer"/>
<bean id="domainBasedPdxSerializer" class="org.springframework.data.gemfire.function.ClientCacheFunctionExecutionWithPdxIntegrationTest$ComposablePdxSerializerFactoryBean">
<bean id="domainBasedPdxSerializer"
class="org.springframework.data.gemfire.function.ClientCacheFunctionExecutionWithPdxIntegrationTest$ComposablePdxSerializerFactoryBean">
<property name="pdxSerializers">
<list>
<ref bean="addressPdxSerializer"/>
@@ -38,6 +37,10 @@
<gfe:client-cache properties-ref="gemfireProperties" pool-name="serverConnectionPool" pdx-serializer-ref="domainBasedPdxSerializer"/>
<gfe:pool id="serverConnectionPool">
<gfe:server host="localhost" port="${spring.data.gemfire.cache.server.port:40404}"/>
</gfe:pool>
<gfe-data:function-executions base-package="org.springframework.data.gemfire.function.sample">
<gfe-data:include-filter type="assignable" expression="org.springframework.data.gemfire.function.sample.ApplicationDomainFunctionExecutions"/>
</gfe-data:function-executions>

View File

@@ -15,14 +15,17 @@
<util:properties id="gemfireProperties">
<prop key="name">SpringGemFireServerFunctionCreationWithPdx</prop>
<prop key="mcast-port">0</prop>
<prop key="log-level">warning</prop>
<prop key="log-level">config</prop>
</util:properties>
<bean id="addressPdxSerializer" class="org.springframework.data.gemfire.function.ClientCacheFunctionExecutionWithPdxIntegrationTest$AddressPdxSerializer"/>
<bean id="addressPdxSerializer"
class="org.springframework.data.gemfire.function.ClientCacheFunctionExecutionWithPdxIntegrationTest$AddressPdxSerializer"/>
<bean id="personPdxSerializer" class="org.springframework.data.gemfire.function.ClientCacheFunctionExecutionWithPdxIntegrationTest$PersonPdxSerializer"/>
<bean id="personPdxSerializer"
class="org.springframework.data.gemfire.function.ClientCacheFunctionExecutionWithPdxIntegrationTest$PersonPdxSerializer"/>
<bean id="domainBasedPdxSerializer" class="org.springframework.data.gemfire.function.ClientCacheFunctionExecutionWithPdxIntegrationTest$ComposablePdxSerializerFactoryBean">
<bean id="domainBasedPdxSerializer"
class="org.springframework.data.gemfire.function.ClientCacheFunctionExecutionWithPdxIntegrationTest$ComposablePdxSerializerFactoryBean">
<property name="pdxSerializers">
<list>
<ref bean="addressPdxSerializer"/>