diff --git a/src/main/java/org/springframework/data/gemfire/CacheFactoryBean.java b/src/main/java/org/springframework/data/gemfire/CacheFactoryBean.java index dec12b04..b2f00184 100644 --- a/src/main/java/org/springframework/data/gemfire/CacheFactoryBean.java +++ b/src/main/java/org/springframework/data/gemfire/CacheFactoryBean.java @@ -104,7 +104,7 @@ import org.springframework.util.StringUtils; * @see org.springframework.data.gemfire.support.GemfireBeanFactoryLocator */ @SuppressWarnings("unused") -public class CacheFactoryBean extends AbstractFactoryBeanSupport +public class CacheFactoryBean extends AbstractFactoryBeanSupport implements DisposableBean, InitializingBean, PersistenceExceptionTranslator, Phased { private boolean close = true; @@ -119,7 +119,7 @@ public class CacheFactoryBean extends AbstractFactoryBeanSupport private Boolean pdxReadSerialized; private Boolean useClusterConfiguration; - private Cache cache; + private GemFireCache cache; private CacheFactoryInitializer cacheFactoryInitializer; @@ -247,10 +247,10 @@ public class CacheFactoryBean extends AbstractFactoryBeanSupport * @see org.apache.geode.cache.Cache * @see #resolveCache() * @see #postProcess(GemFireCache) - * @see #setCache(Cache) + * @see #setCache(GemFireCache) */ @SuppressWarnings("deprecation") - Cache init() { + GemFireCache init() { ClassLoader currentThreadContextClassLoader = Thread.currentThread().getContextClassLoader(); @@ -260,7 +260,7 @@ public class CacheFactoryBean extends AbstractFactoryBeanSupport setCache(postProcess(resolveCache())); - Optional.ofNullable(this.getCache()).ifPresent(cache -> { + Optional.ofNullable(this.getCache()).ifPresent(cache -> { Optional.ofNullable(cache.getDistributedSystem()).map(DistributedSystem::getDistributedMember) .ifPresent(member -> @@ -290,6 +290,7 @@ public class CacheFactoryBean extends AbstractFactoryBeanSupport * If an existing {@link Cache} could not be found, then this method proceeds in attempting to create * a new {@link Cache} instance. * + * @param parameterized {@link Class} type extension of {@link GemFireCache}. * @return the resolved {@link Cache} instance. * @see org.apache.geode.cache.Cache * @see #fetchCache() @@ -298,15 +299,16 @@ public class CacheFactoryBean extends AbstractFactoryBeanSupport * @see #prepareFactory(Object) * @see #createCache(Object) */ - protected Cache resolveCache() { + @SuppressWarnings("unchecked") + protected T resolveCache() { try { this.cacheResolutionMessagePrefix = "Found existing"; - return (Cache) fetchCache(); + return (T) fetchCache(); } catch (CacheClosedException ex) { this.cacheResolutionMessagePrefix = "Created new"; initDynamicRegionFactory(); - return (Cache) createCache(prepareFactory(initializeFactory(createFactory(resolveProperties())))); + return (T) createCache(prepareFactory(initializeFactory(createFactory(resolveProperties())))); } } @@ -443,6 +445,7 @@ public class CacheFactoryBean extends AbstractFactoryBeanSupport * @see #registerTransactionListeners(org.apache.geode.cache.GemFireCache) * @see #registerTransactionWriter(org.apache.geode.cache.GemFireCache) */ + @SuppressWarnings("all") protected T postProcess(T cache) { // load cache.xml Resource and initialize the cache @@ -457,11 +460,14 @@ public class CacheFactoryBean extends AbstractFactoryBeanSupport }); Optional.ofNullable(getCopyOnRead()).ifPresent(cache::setCopyOnRead); - Optional.ofNullable(getGatewayConflictResolver()).ifPresent(((Cache) cache)::setGatewayConflictResolver); - Optional.ofNullable(getLockLease()).ifPresent(((Cache) cache)::setLockLease); - Optional.ofNullable(getLockTimeout()).ifPresent(((Cache) cache)::setLockTimeout); - Optional.ofNullable(getMessageSyncInterval()).ifPresent(((Cache) cache)::setMessageSyncInterval); - Optional.ofNullable(getSearchTimeout()).ifPresent(((Cache) cache)::setSearchTimeout); + + if (cache instanceof Cache) { + Optional.ofNullable(getGatewayConflictResolver()).ifPresent(((Cache) cache)::setGatewayConflictResolver); + Optional.ofNullable(getLockLease()).ifPresent(((Cache) cache)::setLockLease); + Optional.ofNullable(getLockTimeout()).ifPresent(((Cache) cache)::setLockTimeout); + Optional.ofNullable(getMessageSyncInterval()).ifPresent(((Cache) cache)::setMessageSyncInterval); + Optional.ofNullable(getSearchTimeout()).ifPresent(((Cache) cache)::setSearchTimeout); + } configureHeapPercentages(cache); registerTransactionListeners(cache); @@ -577,6 +583,7 @@ public class CacheFactoryBean extends AbstractFactoryBeanSupport * @see org.springframework.dao.DataAccessException */ @Override + @SuppressWarnings("all") public DataAccessException translateExceptionIfPossible(RuntimeException exception) { if (exception instanceof IllegalArgumentException) { @@ -620,7 +627,7 @@ public class CacheFactoryBean extends AbstractFactoryBeanSupport * @param cache {@link Cache} created by this {@link CacheFactoryBean}. * @see org.apache.geode.cache.Cache */ - protected void setCache(Cache cache) { + protected void setCache(GemFireCache cache) { this.cache = cache; } @@ -701,8 +708,9 @@ public class CacheFactoryBean extends AbstractFactoryBeanSupport * @see #getCache() */ @Override - public Cache getObject() throws Exception { - return Optional.ofNullable(this.getCache()).orElseGet(this::init); + @SuppressWarnings("all") + public GemFireCache getObject() throws Exception { + return Optional.ofNullable(this.getCache()).orElseGet(this::init); } /** @@ -714,7 +722,7 @@ public class CacheFactoryBean extends AbstractFactoryBeanSupport @Override @SuppressWarnings("unchecked") public Class getObjectType() { - return Optional.ofNullable(getCache()).map(Object::getClass).orElse(Cache.class); + return Optional.ofNullable(this.getCache()).map(Object::getClass).orElse(Cache.class); } /** diff --git a/src/main/java/org/springframework/data/gemfire/DiskStoreFactoryBean.java b/src/main/java/org/springframework/data/gemfire/DiskStoreFactoryBean.java index b85f07f7..68947d19 100644 --- a/src/main/java/org/springframework/data/gemfire/DiskStoreFactoryBean.java +++ b/src/main/java/org/springframework/data/gemfire/DiskStoreFactoryBean.java @@ -63,14 +63,15 @@ public class DiskStoreFactoryBean extends AbstractFactoryBeanSupport private GemFireCache cache; private Integer compactionThreshold; - private Integer maxOplogSize; private Integer queueSize; - private Integer timeInterval; private Integer writeBufferSize; private Float diskUsageCriticalPercentage; private Float diskUsageWarningPercentage; + private Long maxOplogSize; + private Long timeInterval; + private List diskStoreConfigurers = Collections.emptyList(); private DiskStoreConfigurer compositeDiskStoreConfigurer = (beanName, bean) -> @@ -312,7 +313,7 @@ public class DiskStoreFactoryBean extends AbstractFactoryBeanSupport this.diskUsageWarningPercentage = diskUsageWarningPercentage; } - public void setMaxOplogSize(Integer maxOplogSize) { + public void setMaxOplogSize(Long maxOplogSize) { this.maxOplogSize = maxOplogSize; } @@ -320,7 +321,7 @@ public class DiskStoreFactoryBean extends AbstractFactoryBeanSupport this.queueSize = queueSize; } - public void setTimeInterval(Integer timeInterval) { + public void setTimeInterval(Long timeInterval) { this.timeInterval = timeInterval; } diff --git a/src/main/java/org/springframework/data/gemfire/client/ClientRegionFactoryBean.java b/src/main/java/org/springframework/data/gemfire/client/ClientRegionFactoryBean.java index db5c44eb..db7a42bc 100644 --- a/src/main/java/org/springframework/data/gemfire/client/ClientRegionFactoryBean.java +++ b/src/main/java/org/springframework/data/gemfire/client/ClientRegionFactoryBean.java @@ -130,7 +130,7 @@ public class ClientRegionFactoryBean extends RegionLookupFactoryBean ClientCache cache = resolveCache(gemfireCache); ClientRegionFactory clientRegionFactory = - configure(createClientRegionFactory(cache, resolveClientRegionShortcut())); + postProcess(configure(createClientRegionFactory(cache, resolveClientRegionShortcut()))); @SuppressWarnings("all") Region region = newRegion(clientRegionFactory, getParent(), regionName); @@ -251,6 +251,7 @@ public class ClientRegionFactoryBean extends RegionLookupFactoryBean * @see org.apache.geode.cache.DataPolicy */ ClientRegionShortcut resolveClientRegionShortcut() { + ClientRegionShortcut resolvedShortcut = this.shortcut; if (resolvedShortcut == null) { diff --git a/src/main/java/org/springframework/data/gemfire/config/annotation/AbstractCacheConfiguration.java b/src/main/java/org/springframework/data/gemfire/config/annotation/AbstractCacheConfiguration.java index 2498c20d..70192e2c 100644 --- a/src/main/java/org/springframework/data/gemfire/config/annotation/AbstractCacheConfiguration.java +++ b/src/main/java/org/springframework/data/gemfire/config/annotation/AbstractCacheConfiguration.java @@ -192,7 +192,6 @@ public abstract class AbstractCacheConfiguration extends AbstractAnnotationConfi */ @Override public void setImportMetadata(AnnotationMetadata importMetadata) { - configureInfrastructure(importMetadata); configureCache(importMetadata); configurePdx(importMetadata); @@ -208,7 +207,6 @@ public abstract class AbstractCacheConfiguration extends AbstractAnnotationConfi * @see org.springframework.core.type.AnnotationMetadata */ protected void configureInfrastructure(AnnotationMetadata importMetadata) { - registerCustomEditorBeanFactoryPostProcessor(importMetadata); registerDefinedIndexesApplicationListener(importMetadata); registerDiskStoreDirectoryBeanPostProcessor(importMetadata); @@ -254,19 +252,33 @@ public abstract class AbstractCacheConfiguration extends AbstractAnnotationConfi Map cacheMetadataAttributes = importMetadata.getAnnotationAttributes(getAnnotationTypeName()); - setCopyOnRead(Boolean.TRUE.equals(cacheMetadataAttributes.get("copyOnRead"))); + setCopyOnRead(resolveProperty(cacheProperty("copy-on-read"), + Boolean.TRUE.equals(cacheMetadataAttributes.get("copyOnRead")))); + + Optional.ofNullable(resolveProperty(cacheProperty("critical-heap-percentage"), (Float) null)) + .ifPresent(this::setCriticalHeapPercentage); Optional.ofNullable((Float) cacheMetadataAttributes.get("criticalHeapPercentage")) + .filter(it -> getCriticalHeapPercentage() == null) .filter(AbstractAnnotationConfigSupport::hasValue) .ifPresent(this::setCriticalHeapPercentage); + Optional.ofNullable(resolveProperty(cacheProperty("eviction-heap-percentage"), (Float) null)) + .ifPresent(this::setEvictionHeapPercentage); + Optional.ofNullable((Float) cacheMetadataAttributes.get("evictionHeapPercentage")) + .filter(it -> getEvictionHeapPercentage() == null) .filter(AbstractAnnotationConfigSupport::hasValue) .ifPresent(this::setEvictionHeapPercentage); - setLogLevel((String) cacheMetadataAttributes.get("logLevel")); - setName((String) cacheMetadataAttributes.get("name")); - setUseBeanFactoryLocator(Boolean.TRUE.equals(cacheMetadataAttributes.get("useBeanFactoryLocator"))); + setLogLevel(resolveProperty(cacheProperty("log-level"), + (String) cacheMetadataAttributes.get("logLevel"))); + + setName(resolveProperty(cacheProperty("name"), + (String) cacheMetadataAttributes.get("name"))); + + setUseBeanFactoryLocator(resolveProperty(propertyName("use-bean-factory-locator"), + Boolean.TRUE.equals(cacheMetadataAttributes.get("useBeanFactoryLocator")))); } } @@ -286,10 +298,18 @@ public abstract class AbstractCacheConfiguration extends AbstractAnnotationConfi Map enablePdxAttributes = importMetadata.getAnnotationAttributes(enablePdxTypeName); - setPdxDiskStoreName((String) enablePdxAttributes.get("diskStoreName")); - setPdxIgnoreUnreadFields(Boolean.TRUE.equals(enablePdxAttributes.get("ignoreUnreadFields"))); - setPdxPersistent(Boolean.TRUE.equals(enablePdxAttributes.get("persistent"))); - setPdxReadSerialized(Boolean.TRUE.equals(enablePdxAttributes.get("readSerialized"))); + setPdxDiskStoreName(resolveProperty(pdxProperty("disk-store-name"), + (String) enablePdxAttributes.get("diskStoreName"))); + + setPdxIgnoreUnreadFields(resolveProperty(pdxProperty("ignore-unread-fields"), + Boolean.TRUE.equals(enablePdxAttributes.get("ignoreUnreadFields")))); + + setPdxPersistent(resolveProperty(pdxProperty("persistent"), + Boolean.TRUE.equals(enablePdxAttributes.get("persistent")))); + + setPdxReadSerialized(resolveProperty(pdxProperty("read-serialized"), + Boolean.TRUE.equals(enablePdxAttributes.get("readSerialized")))); + setPdxSerializer(resolvePdxSerializer((String) enablePdxAttributes.get("serializerBeanName"))); registerPdxDiskStoreAwareBeanFactoryPostProcessor(importMetadata); @@ -313,7 +333,7 @@ public abstract class AbstractCacheConfiguration extends AbstractAnnotationConfi return Optional.ofNullable(pdxSerializerBeanName) .filter(beanFactory::containsBean) .map(beanName -> beanFactory.getBean(beanName, PdxSerializer.class)) - .orElseGet(() -> Optional.ofNullable(pdxSerializer()).orElseGet(() -> newPdxSerializer(beanFactory))); + .orElseGet(() -> Optional.ofNullable(getPdxSerializer()).orElseGet(() -> newPdxSerializer(beanFactory))); } /** @@ -353,7 +373,7 @@ public abstract class AbstractCacheConfiguration extends AbstractAnnotationConfi /* (non-Javadoc) */ private void registerPdxDiskStoreAwareBeanFactoryPostProcessor(AnnotationMetadata importMetadata) { - Optional.ofNullable(pdxDiskStoreName()) + Optional.ofNullable(getPdxDiskStoreName()) .filter(StringUtils::hasText) .ifPresent(pdxDiskStoreName -> { if (PDX_DISK_STORE_AWARE_BEAN_FACTORY_POST_PROCESSOR_REGISTERED.compareAndSet(false, true)) { @@ -425,22 +445,22 @@ public abstract class AbstractCacheConfiguration extends AbstractAnnotationConfi 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.setCacheXml(getCacheXml()); + gemfireCache.setClose(isClose()); + gemfireCache.setCopyOnRead(getCopyOnRead()); + gemfireCache.setCriticalHeapPercentage(getCriticalHeapPercentage()); + gemfireCache.setDynamicRegionSupport(getDynamicRegionSupport()); + gemfireCache.setEvictionHeapPercentage(getEvictionHeapPercentage()); + gemfireCache.setGatewayConflictResolver(getGatewayConflictResolver()); + gemfireCache.setJndiDataSources(getJndiDataSources()); gemfireCache.setProperties(gemfireProperties()); - gemfireCache.setPdxDiskStoreName(pdxDiskStoreName()); - gemfireCache.setPdxIgnoreUnreadFields(pdxIgnoreUnreadFields()); - gemfireCache.setPdxPersistent(pdxPersistent()); - gemfireCache.setPdxReadSerialized(pdxReadSerialized()); - gemfireCache.setPdxSerializer(pdxSerializer()); - gemfireCache.setTransactionListeners(transactionListeners()); - gemfireCache.setTransactionWriter(transactionWriter()); + gemfireCache.setPdxDiskStoreName(getPdxDiskStoreName()); + gemfireCache.setPdxIgnoreUnreadFields(getPdxIgnoreUnreadFields()); + gemfireCache.setPdxPersistent(getPdxPersistent()); + gemfireCache.setPdxReadSerialized(getPdxReadSerialized()); + gemfireCache.setPdxSerializer(getPdxSerializer()); + gemfireCache.setTransactionListeners(getTransactionListeners()); + gemfireCache.setTransactionWriter(getTransactionWriter()); return gemfireCache; } @@ -588,7 +608,7 @@ public abstract class AbstractCacheConfiguration extends AbstractAnnotationConfi this.cacheXml = cacheXml; } - protected Resource cacheXml() { + protected Resource getCacheXml() { return this.cacheXml; } @@ -597,7 +617,7 @@ public abstract class AbstractCacheConfiguration extends AbstractAnnotationConfi this.close = close; } - protected boolean close() { + protected boolean isClose() { return this.close; } @@ -606,7 +626,7 @@ public abstract class AbstractCacheConfiguration extends AbstractAnnotationConfi this.copyOnRead = copyOnRead; } - protected boolean copyOnRead() { + protected boolean getCopyOnRead() { return this.copyOnRead; } @@ -615,7 +635,7 @@ public abstract class AbstractCacheConfiguration extends AbstractAnnotationConfi this.criticalHeapPercentage = criticalHeapPercentage; } - protected Float criticalHeapPercentage() { + protected Float getCriticalHeapPercentage() { return this.criticalHeapPercentage; } @@ -624,7 +644,7 @@ public abstract class AbstractCacheConfiguration extends AbstractAnnotationConfi this.dynamicRegionSupport = dynamicRegionSupport; } - protected DynamicRegionSupport dynamicRegionSupport() { + protected DynamicRegionSupport getDynamicRegionSupport() { return this.dynamicRegionSupport; } @@ -633,7 +653,7 @@ public abstract class AbstractCacheConfiguration extends AbstractAnnotationConfi this.evictionHeapPercentage = evictionHeapPercentage; } - protected Float evictionHeapPercentage() { + protected Float getEvictionHeapPercentage() { return this.evictionHeapPercentage; } @@ -642,7 +662,7 @@ public abstract class AbstractCacheConfiguration extends AbstractAnnotationConfi this.gatewayConflictResolver = gatewayConflictResolver; } - protected GatewayConflictResolver gatewayConflictResolver() { + protected GatewayConflictResolver getGatewayConflictResolver() { return this.gatewayConflictResolver; } @@ -651,7 +671,7 @@ public abstract class AbstractCacheConfiguration extends AbstractAnnotationConfi this.jndiDataSources = jndiDataSources; } - protected List jndiDataSources() { + protected List getJndiDataSources() { return nullSafeList(this.jndiDataSources); } @@ -706,7 +726,7 @@ public abstract class AbstractCacheConfiguration extends AbstractAnnotationConfi this.pdxDiskStoreName = pdxDiskStoreName; } - protected String pdxDiskStoreName() { + protected String getPdxDiskStoreName() { return this.pdxDiskStoreName; } @@ -715,7 +735,7 @@ public abstract class AbstractCacheConfiguration extends AbstractAnnotationConfi this.pdxIgnoreUnreadFields = pdxIgnoreUnreadFields; } - protected Boolean pdxIgnoreUnreadFields() { + protected Boolean getPdxIgnoreUnreadFields() { return this.pdxIgnoreUnreadFields; } @@ -724,7 +744,7 @@ public abstract class AbstractCacheConfiguration extends AbstractAnnotationConfi this.pdxPersistent = pdxPersistent; } - protected Boolean pdxPersistent() { + protected Boolean getPdxPersistent() { return this.pdxPersistent; } @@ -733,7 +753,7 @@ public abstract class AbstractCacheConfiguration extends AbstractAnnotationConfi this.pdxReadSerialized = pdxReadSerialized; } - protected Boolean pdxReadSerialized() { + protected Boolean getPdxReadSerialized() { return this.pdxReadSerialized; } @@ -742,7 +762,7 @@ public abstract class AbstractCacheConfiguration extends AbstractAnnotationConfi this.pdxSerializer = pdxSerializer; } - protected PdxSerializer pdxSerializer() { + protected PdxSerializer getPdxSerializer() { return this.pdxSerializer; } @@ -760,7 +780,7 @@ public abstract class AbstractCacheConfiguration extends AbstractAnnotationConfi this.transactionListeners = transactionListeners; } - protected List transactionListeners() { + protected List getTransactionListeners() { return nullSafeList(this.transactionListeners); } @@ -769,7 +789,7 @@ public abstract class AbstractCacheConfiguration extends AbstractAnnotationConfi this.transactionWriter = transactionWriter; } - protected TransactionWriter transactionWriter() { + protected TransactionWriter getTransactionWriter() { return this.transactionWriter; } diff --git a/src/main/java/org/springframework/data/gemfire/config/annotation/AddCacheServerConfiguration.java b/src/main/java/org/springframework/data/gemfire/config/annotation/AddCacheServerConfiguration.java index a1738804..caea56e1 100644 --- a/src/main/java/org/springframework/data/gemfire/config/annotation/AddCacheServerConfiguration.java +++ b/src/main/java/org/springframework/data/gemfire/config/annotation/AddCacheServerConfiguration.java @@ -25,9 +25,6 @@ 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; @@ -38,8 +35,10 @@ import org.springframework.beans.factory.support.BeanDefinitionReaderUtils; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.context.annotation.ImportBeanDefinitionRegistrar; import org.springframework.core.type.AnnotationMetadata; +import org.springframework.data.gemfire.config.annotation.support.AbstractAnnotationConfigSupport; import org.springframework.data.gemfire.config.xml.GemfireConstants; import org.springframework.data.gemfire.server.CacheServerFactoryBean; +import org.springframework.data.gemfire.server.SubscriptionEvictionPolicy; import org.springframework.util.StringUtils; /** @@ -50,9 +49,7 @@ import org.springframework.util.StringUtils; * @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 @@ -63,12 +60,12 @@ import org.springframework.util.StringUtils; * @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.config.annotation.support.AbstractAnnotationConfigSupport * @see org.springframework.data.gemfire.server.CacheServerFactoryBean * @since 1.9.0 */ -public class AddCacheServerConfiguration implements BeanFactoryAware, ImportBeanDefinitionRegistrar { - - private BeanFactory beanFactory; +public class AddCacheServerConfiguration extends AbstractAnnotationConfigSupport + implements ImportBeanDefinitionRegistrar { @Autowired(required = false) private List cacheServerConfigurers = Collections.emptyList(); @@ -104,25 +101,86 @@ public class AddCacheServerConfiguration implements BeanFactoryAware, ImportBean BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(CacheServerFactoryBean.class); + String beanName = registerCacheServerFactoryBeanDefinition(builder.getBeanDefinition(), + (String) enableCacheServerAttributes.get("name"), registry); + 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")); - builder.addPropertyValue("loadPollInterval", enableCacheServerAttributes.get("loadPollInterval")); - builder.addPropertyValue("maxConnections", enableCacheServerAttributes.get("maxConnections")); - builder.addPropertyValue("maxMessageCount", enableCacheServerAttributes.get("maxMessageCount")); - builder.addPropertyValue("maxThreads", enableCacheServerAttributes.get("maxThreads")); - builder.addPropertyValue("maxTimeBetweenPings", enableCacheServerAttributes.get("maxTimeBetweenPings")); - builder.addPropertyValue("messageTimeToLive", enableCacheServerAttributes.get("messageTimeToLive")); - builder.addPropertyValue("port", enableCacheServerAttributes.get("port")); - builder.addPropertyValue("socketBufferSize", enableCacheServerAttributes.get("socketBufferSize")); - builder.addPropertyValue("subscriptionCapacity", enableCacheServerAttributes.get("subscriptionCapacity")); - builder.addPropertyValue("subscriptionDiskStore", enableCacheServerAttributes.get("subscriptionDiskStoreName")); - builder.addPropertyValue("subscriptionEvictionPolicy", enableCacheServerAttributes.get("subscriptionEvictionPolicy")); - registerCacheServerFactoryBeanDefinition(builder.getBeanDefinition(), - (String) enableCacheServerAttributes.get("name"), registry); + builder.addPropertyValue("autoStartup", + resolveProperty(namedCacheServerProperty(beanName, "auto-startup"), + resolveProperty(cacheServerProperty("auto-startup"), + (Boolean) enableCacheServerAttributes.get("autoStartup")))); + + builder.addPropertyValue("bindAddress", + resolveProperty(namedCacheServerProperty(beanName, "bind-address"), + resolveProperty(cacheServerProperty("bind-address"), + (String) enableCacheServerAttributes.get("bindAddress")))); + + builder.addPropertyValue("hostNameForClients", + resolveProperty(namedCacheServerProperty(beanName, "hostname-for-clients"), + resolveProperty(cacheServerProperty("hostname-for-clients"), + (String) enableCacheServerAttributes.get("hostnameForClients")))); + + builder.addPropertyValue("loadPollInterval", + resolveProperty(namedCacheServerProperty(beanName, "load-poll-interval"), + resolveProperty(cacheServerProperty("load-poll-interval"), + (Long) enableCacheServerAttributes.get("loadPollInterval")))); + + builder.addPropertyValue("maxConnections", + resolveProperty(namedCacheServerProperty(beanName, "max-connections"), + resolveProperty(cacheServerProperty("max-connections"), + (Integer) enableCacheServerAttributes.get("maxConnections")))); + + builder.addPropertyValue("maxMessageCount", + resolveProperty(namedCacheServerProperty(beanName, "max-message-count"), + resolveProperty(cacheServerProperty("max-message-count"), + (Integer) enableCacheServerAttributes.get("maxMessageCount")))); + + builder.addPropertyValue("maxThreads", + resolveProperty(namedCacheServerProperty(beanName, "max-threads"), + resolveProperty(cacheServerProperty("max-threads"), + (Integer) enableCacheServerAttributes.get("maxThreads")))); + + builder.addPropertyValue("maxTimeBetweenPings", + resolveProperty(namedCacheServerProperty(beanName, "max-time-between-pings"), + resolveProperty(cacheServerProperty("max-time-between-pings"), + (Integer) enableCacheServerAttributes.get("maxTimeBetweenPings")))); + + builder.addPropertyValue("messageTimeToLive", + resolveProperty(namedCacheServerProperty(beanName, "message-time-to-live"), + resolveProperty(cacheServerProperty("message-time-to-live"), + (Integer) enableCacheServerAttributes.get("messageTimeToLive")))); + + builder.addPropertyValue("port", + resolveProperty(namedCacheServerProperty(beanName, "port"), + resolveProperty(cacheServerProperty("port"), + (Integer) enableCacheServerAttributes.get("port")))); + + builder.addPropertyValue("socketBufferSize", + resolveProperty(namedCacheServerProperty(beanName, "socket-buffer-size"), + resolveProperty(cacheServerProperty("socket-buffer-size"), + (Integer) enableCacheServerAttributes.get("socketBufferSize")))); + + builder.addPropertyValue("subscriptionCapacity", + resolveProperty(namedCacheServerProperty(beanName, "subscription-capacity"), + resolveProperty(cacheServerProperty("subscription-capacity"), + (Integer) enableCacheServerAttributes.get("subscriptionCapacity")))); + + builder.addPropertyValue("subscriptionDiskStore", + resolveProperty(namedCacheServerProperty(beanName, "subscription-disk-store-name"), + resolveProperty(cacheServerProperty("subscription-disk-store-name"), + (String) enableCacheServerAttributes.get("subscriptionDiskStoreName")))); + + builder.addPropertyValue("subscriptionEvictionPolicy", + resolveProperty(namedCacheServerProperty(beanName, "subscription-eviction-policy"), + SubscriptionEvictionPolicy.class, resolveProperty(cacheServerProperty("subscription-eviction-policy"), + SubscriptionEvictionPolicy.class, (SubscriptionEvictionPolicy) enableCacheServerAttributes.get("subscriptionEvictionPolicy")))); + + builder.addPropertyValue("tcpNoDelay", + resolveProperty(namedCacheServerProperty(beanName, "tcp-no-delay"), + resolveProperty(cacheServerProperty("tcp-no-delay"), + (Boolean) enableCacheServerAttributes.get("tcpNoDelay")))); } /* (non-Javadoc) */ @@ -131,7 +189,7 @@ public class AddCacheServerConfiguration implements BeanFactoryAware, ImportBean return Optional.ofNullable(this.cacheServerConfigurers) .filter(cacheServerConfigurers -> !cacheServerConfigurers.isEmpty()) .orElseGet(() -> - Optional.of(this.beanFactory) + Optional.of(this.beanFactory()) .filter(beanFactory -> beanFactory instanceof ListableBeanFactory) .map(beanFactory -> { Map beansOfType = ((ListableBeanFactory) beanFactory) @@ -143,16 +201,19 @@ public class AddCacheServerConfiguration implements BeanFactoryAware, ImportBean ); } + /* (non-Javadoc) */ - protected void registerCacheServerFactoryBeanDefinition(AbstractBeanDefinition beanDefinition, String beanName, + protected String registerCacheServerFactoryBeanDefinition(AbstractBeanDefinition beanDefinition, String beanName, BeanDefinitionRegistry registry) { if (StringUtils.hasText(beanName)) { BeanDefinitionReaderUtils.registerBeanDefinition( newBeanDefinitionHolder(beanDefinition, beanName), registry); + + return beanName; } else { - BeanDefinitionReaderUtils.registerWithGeneratedName(beanDefinition, registry); + return BeanDefinitionReaderUtils.registerWithGeneratedName(beanDefinition, registry); } } @@ -163,7 +224,7 @@ public class AddCacheServerConfiguration implements BeanFactoryAware, ImportBean /* (non-Javadoc) */ @Override - public void setBeanFactory(BeanFactory beanFactory) throws BeansException { - this.beanFactory = beanFactory; + protected Class getAnnotationType() { + return EnableCacheServer.class; } } diff --git a/src/main/java/org/springframework/data/gemfire/config/annotation/AddPoolConfiguration.java b/src/main/java/org/springframework/data/gemfire/config/annotation/AddPoolConfiguration.java index a672d2cf..41644a3b 100644 --- a/src/main/java/org/springframework/data/gemfire/config/annotation/AddPoolConfiguration.java +++ b/src/main/java/org/springframework/data/gemfire/config/annotation/AddPoolConfiguration.java @@ -17,7 +17,10 @@ package org.springframework.data.gemfire.config.annotation; +import static java.util.Arrays.stream; +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 java.util.Collections; import java.util.List; @@ -25,9 +28,6 @@ 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; @@ -37,9 +37,9 @@ import org.springframework.core.annotation.AnnotationAttributes; import org.springframework.core.type.AnnotationMetadata; import org.springframework.data.gemfire.GemfireUtils; import org.springframework.data.gemfire.client.PoolFactoryBean; +import org.springframework.data.gemfire.config.annotation.support.AbstractAnnotationConfigSupport; import org.springframework.data.gemfire.support.ConnectionEndpoint; import org.springframework.data.gemfire.support.ConnectionEndpointList; -import org.springframework.util.Assert; import org.springframework.util.StringUtils; /** @@ -50,7 +50,6 @@ import org.springframework.util.StringUtils; * @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 @@ -60,11 +59,11 @@ import org.springframework.util.StringUtils; * @see org.springframework.data.gemfire.config.annotation.PoolConfigurer * @see org.springframework.data.gemfire.config.annotation.EnablePools * @see org.springframework.data.gemfire.config.annotation.EnablePool + * @see org.springframework.data.gemfire.config.annotation.support.AbstractAnnotationConfigSupport * @since 1.9.0 */ -public class AddPoolConfiguration implements BeanFactoryAware, ImportBeanDefinitionRegistrar { - - private BeanFactory beanFactory; +public class AddPoolConfiguration extends AbstractAnnotationConfigSupport + implements ImportBeanDefinitionRegistrar { @Autowired(required = false) private List poolConfigurers = Collections.emptyList(); @@ -102,27 +101,99 @@ public class AddPoolConfiguration implements BeanFactoryAware, ImportBeanDefinit BeanDefinitionBuilder poolFactoryBean = BeanDefinitionBuilder.genericBeanDefinition(PoolFactoryBean.class); - poolFactoryBean.addPropertyValue("freeConnectionTimeout", enablePoolAttributes.get("freeConnectionTimeout")); - poolFactoryBean.addPropertyValue("idleTimeout", enablePoolAttributes.get("idleTimeout")); - poolFactoryBean.addPropertyValue("loadConditioningInterval", enablePoolAttributes.get("loadConditioningInterval")); - poolFactoryBean.addPropertyValue("maxConnections", enablePoolAttributes.get("maxConnections")); - 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")); - poolFactoryBean.addPropertyValue("serverGroup", enablePoolAttributes.get("serverGroup")); - poolFactoryBean.addPropertyValue("socketBufferSize", enablePoolAttributes.get("socketBufferSize")); - poolFactoryBean.addPropertyValue("statisticInterval", enablePoolAttributes.get("statisticInterval")); - poolFactoryBean.addPropertyValue("subscriptionAckInterval", enablePoolAttributes.get("subscriptionAckInterval")); - poolFactoryBean.addPropertyValue("subscriptionEnabled", enablePoolAttributes.get("subscriptionEnabled")); - poolFactoryBean.addPropertyValue("subscriptionMessageTrackingTimeout", enablePoolAttributes.get("subscriptionMessageTrackingTimeout")); - poolFactoryBean.addPropertyValue("subscriptionRedundancy", enablePoolAttributes.get("subscriptionRedundancy")); - poolFactoryBean.addPropertyValue("threadLocalConnections", enablePoolAttributes.get("threadLocalConnections")); + poolFactoryBean.addPropertyValue("freeConnectionTimeout", + resolveProperty(namedPoolProperty(poolName, "free-connection-timeout"), + resolveProperty(poolProperty("free-connection-timeout"), + (Integer) enablePoolAttributes.get("freeConnectionTimeout")))); - configurePoolConnections(enablePoolAttributes, poolFactoryBean); + poolFactoryBean.addPropertyValue("idleTimeout", + resolveProperty(namedPoolProperty(poolName, "idle-timeout"), + resolveProperty(poolProperty("idle-timeout"), + (Long) enablePoolAttributes.get("idleTimeout")))); + + poolFactoryBean.addPropertyValue("loadConditioningInterval", + resolveProperty(namedPoolProperty(poolName, "load-conditioning-interval"), + resolveProperty(poolProperty("load-conditioning-interval"), + (Integer) enablePoolAttributes.get("loadConditioningInterval")))); + + poolFactoryBean.addPropertyValue("maxConnections", + resolveProperty(namedPoolProperty(poolName, "max-connections"), + resolveProperty(poolProperty("max-connections"), + (Integer) enablePoolAttributes.get("maxConnections")))); + + poolFactoryBean.addPropertyValue("minConnections", + resolveProperty(namedPoolProperty(poolName, "min-connections"), + resolveProperty(poolProperty("min-connections"), + (Integer) enablePoolAttributes.get("minConnections")))); + + poolFactoryBean.addPropertyValue("multiUserAuthentication", + resolveProperty(namedPoolProperty(poolName, "multi-user-authentication"), + resolveProperty(poolProperty("multi-user-authentication"), + (Boolean) enablePoolAttributes.get("multiUserAuthentication")))); + + poolFactoryBean.addPropertyValue("pingInterval", + resolveProperty(namedPoolProperty(poolName, "ping-interval"), + resolveProperty(poolProperty("ping-interval"), + (Long) enablePoolAttributes.get("pingInterval")))); + + poolFactoryBean.addPropertyValue("poolConfigurers", resolvePoolConfigurers()); + + poolFactoryBean.addPropertyValue("prSingleHopEnabled", + resolveProperty(namedPoolProperty(poolName, "pr-single-hop-enabled"), + resolveProperty(poolProperty("pr-single-hop-enabled"), + (Boolean) enablePoolAttributes.get("prSingleHopEnabled")))); + + poolFactoryBean.addPropertyValue("readTimeout", + resolveProperty(namedPoolProperty(poolName, "read-timeout"), + resolveProperty(poolProperty("read-timeout"), + (Integer) enablePoolAttributes.get("readTimeout")))); + + poolFactoryBean.addPropertyValue("retryAttempts", + resolveProperty(namedPoolProperty(poolName, "retry-attempts"), + resolveProperty(poolProperty("retry-attempts"), + (Integer) enablePoolAttributes.get("retryAttempts")))); + + poolFactoryBean.addPropertyValue("serverGroup", + resolveProperty(namedPoolProperty(poolName, "server-group"), + resolveProperty(poolProperty("server-group"), + (String) enablePoolAttributes.get("serverGroup")))); + + poolFactoryBean.addPropertyValue("socketBufferSize", + resolveProperty(namedPoolProperty(poolName, "socket-buffer-size"), + resolveProperty(poolProperty("socket-buffer-size"), + (Integer) enablePoolAttributes.get("socketBufferSize")))); + + poolFactoryBean.addPropertyValue("statisticInterval", + resolveProperty(namedPoolProperty(poolName, "statistic-interval"), + resolveProperty(poolProperty("statistic-interval"), + (Integer) enablePoolAttributes.get("statisticInterval")))); + + poolFactoryBean.addPropertyValue("subscriptionAckInterval", + resolveProperty(namedPoolProperty(poolName, "subscription-ack-interval"), + resolveProperty(poolProperty("subscription-ack-interval"), + (Integer) enablePoolAttributes.get("subscriptionAckInterval")))); + + poolFactoryBean.addPropertyValue("subscriptionEnabled", + resolveProperty(namedPoolProperty(poolName, "subscription-enabled"), + resolveProperty(poolProperty("subscription-enabled"), + (Boolean) enablePoolAttributes.get("subscriptionEnabled")))); + + poolFactoryBean.addPropertyValue("subscriptionMessageTrackingTimeout", + resolveProperty(namedPoolProperty(poolName, "subscription-message-tracking-timeout"), + resolveProperty(poolProperty("subscription-message-tracking-timeout"), + (Integer) enablePoolAttributes.get("subscriptionMessageTrackingTimeout")))); + + poolFactoryBean.addPropertyValue("subscriptionRedundancy", + resolveProperty(namedPoolProperty(poolName, "subscription-redundancy"), + resolveProperty(poolProperty("subscription-redundancy"), + (Integer) enablePoolAttributes.get("subscriptionRedundancy")))); + + poolFactoryBean.addPropertyValue("threadLocalConnections", + resolveProperty(namedPoolProperty(poolName, "thread-local-connections"), + resolveProperty(poolProperty("thread-local-connections"), + (Boolean) enablePoolAttributes.get("threadLocalConnections")))); + + configurePoolConnections(poolName, enablePoolAttributes, poolFactoryBean); registry.registerBeanDefinition(poolName, poolFactoryBean.getBeanDefinition()); } @@ -133,7 +204,7 @@ public class AddPoolConfiguration implements BeanFactoryAware, ImportBeanDefinit return Optional.ofNullable(this.poolConfigurers) .filter(poolConfigurers -> !poolConfigurers.isEmpty()) .orElseGet(() -> - Optional.of(this.beanFactory) + Optional.of(this.beanFactory()) .filter(beanFactory -> beanFactory instanceof ListableBeanFactory) .map(beanFactory -> { Map beansOfType = ((ListableBeanFactory) beanFactory) @@ -145,10 +216,12 @@ public class AddPoolConfiguration implements BeanFactoryAware, ImportBeanDefinit ); } + /* (non-Javadoc) */ protected String getAndValidatePoolName(Map enablePoolAttributes) { - String poolName = (String) enablePoolAttributes.get("name"); - Assert.hasText(poolName, "Pool name is required"); - return poolName; + + return Optional.ofNullable((String) enablePoolAttributes.get("name")) + .filter(StringUtils::hasText) + .orElseThrow(() -> newIllegalArgumentException("Pool name is required")); } /** @@ -161,61 +234,81 @@ public class AddPoolConfiguration implements BeanFactoryAware, ImportBeanDefinit * @see org.springframework.data.gemfire.config.annotation.ClientCacheApplication * @see java.util.Map */ - protected BeanDefinitionBuilder configurePoolConnections(Map enablePoolAttributes, + protected BeanDefinitionBuilder configurePoolConnections(String poolName, Map enablePoolAttributes, BeanDefinitionBuilder poolFactoryBean) { - configureLocators(enablePoolAttributes, poolFactoryBean); - configureServers(enablePoolAttributes, poolFactoryBean); + configurePoolLocators(poolName, enablePoolAttributes, poolFactoryBean); + configurePoolServers(poolName, enablePoolAttributes, poolFactoryBean); return poolFactoryBean; } - protected BeanDefinitionBuilder configureLocators(Map enablePoolAttributes, + /* (non-Javadoc) */ + protected BeanDefinitionBuilder configurePoolLocators(String poolName, Map enablePoolAttributes, BeanDefinitionBuilder poolFactoryBean) { - poolFactoryBean.addPropertyValue("locators", parseConnectionEndpoints(enablePoolAttributes, - "locators", "locatorsString", GemfireUtils.DEFAULT_LOCATOR_PORT)); + String locatorsFromProperty = resolveProperty(namedPoolProperty(poolName, "locators"), + resolveProperty(poolProperty("locators"), (String) null)); + + ConnectionEndpointList locators = Optional.ofNullable(locatorsFromProperty) + .filter(StringUtils::hasText) + .map(it -> ConnectionEndpointList.parse(GemfireUtils.DEFAULT_LOCATOR_PORT, it.split(","))) + .orElseGet(() -> parseConnectionEndpoints(enablePoolAttributes,"locators", + "locatorsString", GemfireUtils.DEFAULT_LOCATOR_PORT)); + + poolFactoryBean.addPropertyValue("locators", locators); return poolFactoryBean; } - protected BeanDefinitionBuilder configureServers(Map enablePoolAttributes, + /* (non-Javadoc) */ + protected BeanDefinitionBuilder configurePoolServers(String poolName, Map enablePoolAttributes, BeanDefinitionBuilder poolFactoryBean) { - poolFactoryBean.addPropertyValue("servers", parseConnectionEndpoints(enablePoolAttributes, - "servers", "serversString", GemfireUtils.DEFAULT_CACHE_SERVER_PORT)); + String serversFromProperty = resolveProperty(namedPoolProperty(poolName, "servers"), + resolveProperty("servers", (String) null)); + + ConnectionEndpointList servers = Optional.ofNullable(serversFromProperty) + .filter(StringUtils::hasText) + .map(it -> ConnectionEndpointList.parse(GemfireUtils.DEFAULT_CACHE_SERVER_PORT, it.split(","))) + .orElseGet(() -> parseConnectionEndpoints(enablePoolAttributes, "servers", + "serversString", GemfireUtils.DEFAULT_CACHE_SERVER_PORT)); + + poolFactoryBean.addPropertyValue("servers", servers); return poolFactoryBean; } + /* (non-Javadoc) */ protected ConnectionEndpointList parseConnectionEndpoints(Map enablePoolAttributes, String arrayAttributeName, String stringAttributeName, int defaultPort) { - ConnectionEndpointList connectionEndpoints = new ConnectionEndpointList(); - AnnotationAttributes[] connectionEndpointsMetaData = (AnnotationAttributes[]) enablePoolAttributes.get(arrayAttributeName); - for (AnnotationAttributes annotationAttributes : connectionEndpointsMetaData) { - connectionEndpoints.add(newConnectionEndpoint((String) annotationAttributes.get("host"), - (Integer) annotationAttributes.get("port"))); - } + ConnectionEndpointList connectionEndpoints = new ConnectionEndpointList(); - String hostsPorts = (String) enablePoolAttributes.get(stringAttributeName); + stream(nullSafeArray(connectionEndpointsMetaData, AnnotationAttributes.class)) + .forEach(annotationAttributes -> + connectionEndpoints.add(newConnectionEndpoint((String) annotationAttributes.get("host"), + (Integer) annotationAttributes.get("port")))); - if (StringUtils.hasText(hostsPorts)) { - connectionEndpoints.add(ConnectionEndpointList.parse(defaultPort, hostsPorts.split(","))); - } + Optional.ofNullable((String) enablePoolAttributes.get(stringAttributeName)) + .filter(StringUtils::hasText) + .ifPresent(hostsPorts -> + connectionEndpoints.add(ConnectionEndpointList.parse(defaultPort, hostsPorts.split(",")))); return connectionEndpoints; } + /* (non-Javadoc) */ protected ConnectionEndpoint newConnectionEndpoint(String host, Integer port) { return new ConnectionEndpoint(host, port); } + /* (non-Javadoc) */ @Override - public void setBeanFactory(BeanFactory beanFactory) throws BeansException { - this.beanFactory = beanFactory; + protected Class getAnnotationType() { + return EnablePool.class; } } diff --git a/src/main/java/org/springframework/data/gemfire/config/annotation/ApacheShiroSecurityConfiguration.java b/src/main/java/org/springframework/data/gemfire/config/annotation/ApacheShiroSecurityConfiguration.java index c74156eb..395cf123 100644 --- a/src/main/java/org/springframework/data/gemfire/config/annotation/ApacheShiroSecurityConfiguration.java +++ b/src/main/java/org/springframework/data/gemfire/config/annotation/ApacheShiroSecurityConfiguration.java @@ -17,11 +17,15 @@ package org.springframework.data.gemfire.config.annotation; +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.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.Optional; import org.apache.geode.cache.GemFireCache; import org.apache.geode.internal.security.SecurityService; @@ -31,7 +35,6 @@ import org.apache.shiro.realm.Realm; import org.apache.shiro.spring.LifecycleBeanPostProcessor; 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.config.BeanPostProcessor; import org.springframework.context.annotation.Bean; @@ -41,9 +44,12 @@ import org.springframework.context.annotation.Conditional; import org.springframework.context.annotation.Configuration; import org.springframework.core.OrderComparator; import org.springframework.core.type.AnnotatedTypeMetadata; +import org.springframework.data.gemfire.GemfireUtils; +import org.springframework.data.gemfire.config.annotation.support.AbstractAnnotationConfigSupport; import org.springframework.data.gemfire.util.CollectionUtils; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; +import org.springframework.util.ObjectUtils; import org.springframework.util.ReflectionUtils; /** @@ -57,41 +63,60 @@ import org.springframework.util.ReflectionUtils; * @see org.apache.shiro.mgt.DefaultSecurityManager * @see org.apache.shiro.realm.Realm * @see org.apache.shiro.spring.LifecycleBeanPostProcessor - * @see org.springframework.beans.factory.BeanFactoryAware + * @see org.springframework.beans.factory.BeanFactory * @see org.springframework.beans.factory.ListableBeanFactory * @see org.springframework.context.annotation.Bean * @see org.springframework.context.annotation.Condition * @see org.springframework.context.annotation.Conditional * @see org.springframework.context.annotation.Configuration + * @see org.springframework.core.type.AnnotationMetadata * @see org.springframework.data.gemfire.config.annotation.ApacheShiroSecurityConfiguration.ApacheShiroPresentCondition + * @see org.springframework.data.gemfire.config.annotation.support.AbstractAnnotationConfigSupport * @since 1.9.0 */ @Configuration @Conditional(ApacheShiroSecurityConfiguration.ApacheShiroPresentCondition.class) @SuppressWarnings("unused") -public class ApacheShiroSecurityConfiguration implements BeanFactoryAware { - - private ListableBeanFactory beanFactory; +public class ApacheShiroSecurityConfiguration extends AbstractAnnotationConfigSupport { /** - * @inheritDoc + * Returns the {@link EnableSecurity} {@link java.lang.annotation.Annotation} {@link Class} type. + * + * @return the {@link EnableSecurity} {@link java.lang.annotation.Annotation} {@link Class} type. + * @see org.springframework.data.gemfire.config.annotation.EnableSecurity + */ + @Override + protected Class getAnnotationType() { + return EnableSecurity.class; + } + + /** + * Sets a reference to the Spring {@link BeanFactory}. + * + * @param beanFactory reference to the Spring {@link BeanFactory}. + * @throws IllegalArgumentException if the Spring {@link BeanFactory} is not + * an instance of {@link ListableBeanFactory}. + * @see org.springframework.beans.factory.BeanFactory */ @Override public void setBeanFactory(BeanFactory beanFactory) throws BeansException { - Assert.isInstanceOf(ListableBeanFactory.class, beanFactory); - this.beanFactory = (ListableBeanFactory) beanFactory; + + super.setBeanFactory(Optional.ofNullable(beanFactory) + .filter(it -> it instanceof ListableBeanFactory) + .orElseThrow(() -> newIllegalArgumentException( + "BeanFactory [%s] must be an instance of ListableBeanFactory", + ObjectUtils.nullSafeClassName(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. + * @throws IllegalStateException if the Spring {@link BeanFactory} was not set. * @see org.springframework.beans.factory.BeanFactory */ - protected ListableBeanFactory getBeanFactory() { - org.apache.shiro.util.Assert.state(this.beanFactory != null, "BeanFactory was not properly initialized"); - return this.beanFactory; + protected ListableBeanFactory getListableBeanFactory() { + return (ListableBeanFactory) beanFactory(); } /** @@ -138,15 +163,18 @@ public class ApacheShiroSecurityConfiguration implements BeanFactoryAware { */ @Bean public org.apache.shiro.mgt.SecurityManager shiroSecurityManager(GemFireCache gemfireCache) { + org.apache.shiro.mgt.SecurityManager shiroSecurityManager = null; List realms = resolveRealms(); if (!realms.isEmpty()) { + shiroSecurityManager = registerSecurityManager(new DefaultSecurityManager(realms)); if (!enableApacheGeodeSecurity()) { - throw new IllegalStateException("Failed to enable security services in Apache Geode"); + throw newIllegalStateException("Failed to enable security services in %s", + GemfireUtils.apacheGeodeProductName()); } } @@ -167,8 +195,10 @@ public class ApacheShiroSecurityConfiguration implements BeanFactoryAware { * @see org.apache.shiro.realm.Realm */ protected List resolveRealms() { + try { - Map realmBeans = getBeanFactory().getBeansOfType(Realm.class, false, true); + Map realmBeans = getListableBeanFactory() + .getBeansOfType(Realm.class, false, true); List realms = new ArrayList<>(CollectionUtils.nullSafeMap(realmBeans).values()); Collections.sort(realms, OrderComparator.INSTANCE); return realms; @@ -207,18 +237,21 @@ public class ApacheShiroSecurityConfiguration implements BeanFactoryAware { * @see org.apache.geode.internal.security.SecurityService#getSecurityService() */ protected boolean enableApacheGeodeSecurity() { + SecurityService securityService = SecurityService.getSecurityService(); if (securityService != null) { + String isIntegratedSecurityFieldName = "isIntegratedSecurity"; Field isIntegratedSecurity = ReflectionUtils.findField(securityService.getClass(), isIntegratedSecurityFieldName, Boolean.class); - isIntegratedSecurity = (isIntegratedSecurity != null ? isIntegratedSecurity - : ReflectionUtils.findField(securityService.getClass(), isIntegratedSecurityFieldName, Boolean.TYPE)); + isIntegratedSecurity = Optional.ofNullable(isIntegratedSecurity).orElseGet(() -> + ReflectionUtils.findField(securityService.getClass(), isIntegratedSecurityFieldName, Boolean.TYPE)); if (isIntegratedSecurity != null) { + ReflectionUtils.makeAccessible(isIntegratedSecurity); ReflectionUtils.setField(isIntegratedSecurity, securityService, Boolean.TRUE); diff --git a/src/main/java/org/springframework/data/gemfire/config/annotation/AuthConfiguration.java b/src/main/java/org/springframework/data/gemfire/config/annotation/AuthConfiguration.java index 8984b717..09539780 100644 --- a/src/main/java/org/springframework/data/gemfire/config/annotation/AuthConfiguration.java +++ b/src/main/java/org/springframework/data/gemfire/config/annotation/AuthConfiguration.java @@ -20,15 +20,17 @@ package org.springframework.data.gemfire.config.annotation; import java.util.Map; import java.util.Properties; +import org.springframework.context.annotation.ImportBeanDefinitionRegistrar; import org.springframework.data.gemfire.config.annotation.support.EmbeddedServiceConfigurationSupport; import org.springframework.data.gemfire.util.PropertiesBuilder; /** - * The AuthConfiguration class is a Spring {@link org.springframework.context.annotation.ImportBeanDefinitionRegistrar} - * that applies additional GemFire/Geode configuration by way of GemFire/Geode System properties to configure - * GemFire/Geode Authentication and Authorization framework services. + * The {@link AuthConfiguration} class is a Spring {@link ImportBeanDefinitionRegistrar} that applies + * additional configuration using Pivotal GemFire/Apache Geode {@link Properties} to configure + * Pivotal GemFire/Apache Geode Authentication and Authorization framework and services. * * @author John Blum + * @see org.springframework.context.annotation.ImportBeanDefinitionRegistrar * @see org.springframework.data.gemfire.config.annotation.EnableAuth * @see org.springframework.data.gemfire.config.annotation.support.EmbeddedServiceConfigurationSupport * @see http://gemfire.docs.pivotal.io/docs-gemfire/managing/security/chapter_overview.html @@ -53,47 +55,65 @@ public class AuthConfiguration extends EmbeddedServiceConfigurationSupport { protected static final String SECURITY_PEER_VERIFY_MEMBER_TIMEOUT = "security-peer-verifymember-timeout"; /** - * @inheritDoc + * Returns the {@link EnableAuth} {@link java.lang.annotation.Annotation} {@link Class} type. + * + * @return the {@link EnableAuth} {@link java.lang.annotation.Annotation} {@link Class} type. + * @see org.springframework.data.gemfire.config.annotation.EnableAuth */ @Override protected Class getAnnotationType() { return EnableAuth.class; } - /** - * @inheritDoc - */ + /* (non-Javadoc) */ @Override protected Properties toGemFireProperties(Map annotationAttributes) { + PropertiesBuilder gemfireProperties = PropertiesBuilder.create(); - gemfireProperties.setProperty(GEMFIRE_SECURITY_PROPERTY_FILE, annotationAttributes.get("securityPropertiesFile")); + gemfireProperties.setProperty(GEMFIRE_SECURITY_PROPERTY_FILE, + resolveProperty(securityProperty("properties-file"), + (String) annotationAttributes.get("securityPropertiesFile"))); - gemfireProperties.setProperty(SECURITY_CLIENT_ACCESSOR, annotationAttributes.get("clientAccessor")); + gemfireProperties.setProperty(SECURITY_CLIENT_ACCESSOR, + resolveProperty(securityProperty("client.accessor"), + (String) annotationAttributes.get("clientAccessor"))); gemfireProperties.setProperty(SECURITY_CLIENT_ACCESSOR_POST_PROCESSOR, - annotationAttributes.get("clientAccessPostOperation")); + resolveProperty(securityProperty("client.accessor-post-processor"), + (String) annotationAttributes.get("clientAccessorPostProcessor"))); gemfireProperties.setProperty(SECURITY_CLIENT_AUTH_INIT, - annotationAttributes.get("clientAuthenticationInitializer")); + resolveProperty(securityProperty("client.authentication-initializer"), + (String) annotationAttributes.get("clientAuthenticationInitializer"))); - gemfireProperties.setProperty(SECURITY_CLIENT_AUTHENTICATOR, annotationAttributes.get("clientAuthenticator")); + gemfireProperties.setProperty(SECURITY_CLIENT_AUTHENTICATOR, + resolveProperty(securityProperty("client.authenticator"), + (String) annotationAttributes.get("clientAuthenticator"))); gemfireProperties.setProperty(SECURITY_CLIENT_DIFFIE_HELLMAN_ALGORITHM, - annotationAttributes.get("clientDiffieHellmanAlgorithm")); + resolveProperty(securityProperty("client.diffie-hellman-algorithm"), + (String) annotationAttributes.get("clientDiffieHellmanAlgorithm"))); gemfireProperties.setProperty(SECURITY_PEER_AUTH_INIT, - annotationAttributes.get("peerAuthenticationInitializer")); + resolveProperty(securityProperty("peer.authentication-initializer"), + (String) annotationAttributes.get("peerAuthenticationInitializer"))); - gemfireProperties.setProperty(SECURITY_PEER_AUTHENTICATOR, annotationAttributes.get("peerAuthenticator")); + gemfireProperties.setProperty(SECURITY_PEER_AUTHENTICATOR, + resolveProperty(securityProperty("peer.authenticator"), + (String) annotationAttributes.get("peerAuthenticator"))); gemfireProperties.setPropertyIfNotDefault(SECURITY_PEER_VERIFY_MEMBER_TIMEOUT, - annotationAttributes.get("peerVerifyMemberTimeout"), DEFAULT_PEER_VERIFY_MEMBER_TIMEOUT); + resolveProperty(securityProperty("peer.verify-member-timeout"), + (Long) annotationAttributes.get("peerVerifyMemberTimeout")), DEFAULT_PEER_VERIFY_MEMBER_TIMEOUT); - gemfireProperties.setProperty(SECURITY_LOG_FILE, annotationAttributes.get("securityLogFile")); + gemfireProperties.setProperty(SECURITY_LOG_FILE, + resolveProperty(securityProperty("log.file"), + (String) annotationAttributes.get("securityLogFile"))); gemfireProperties.setPropertyIfNotDefault(SECURITY_LOG_LEVEL, - annotationAttributes.get("securityLogLevel"), DEFAULT_SECURITY_LOG_LEVEL); + resolveProperty(securityProperty("log.level"), + (String) annotationAttributes.get("securityLogLevel")), DEFAULT_SECURITY_LOG_LEVEL); return gemfireProperties.build(); } diff --git a/src/main/java/org/springframework/data/gemfire/config/annotation/AutoRegionLookupConfiguration.java b/src/main/java/org/springframework/data/gemfire/config/annotation/AutoRegionLookupConfiguration.java index 31123735..176b1aec 100644 --- a/src/main/java/org/springframework/data/gemfire/config/annotation/AutoRegionLookupConfiguration.java +++ b/src/main/java/org/springframework/data/gemfire/config/annotation/AutoRegionLookupConfiguration.java @@ -18,22 +18,21 @@ package org.springframework.data.gemfire.config.annotation; import java.util.Map; +import java.util.Optional; import java.util.concurrent.atomic.AtomicBoolean; import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanFactory; -import org.springframework.beans.factory.BeanFactoryAware; 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.EnvironmentAware; import org.springframework.context.annotation.ImportBeanDefinitionRegistrar; import org.springframework.context.expression.BeanFactoryResolver; -import org.springframework.core.convert.ConversionService; import org.springframework.core.env.Environment; import org.springframework.core.type.AnnotationMetadata; +import org.springframework.data.gemfire.config.annotation.support.AbstractAnnotationConfigSupport; import org.springframework.data.gemfire.config.support.AutoRegionLookupBeanPostProcessor; import org.springframework.expression.EvaluationException; import org.springframework.expression.ExpressionParser; @@ -42,7 +41,6 @@ import org.springframework.expression.spel.standard.SpelExpressionParser; 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.Assert; import org.springframework.util.StringUtils; /** @@ -56,16 +54,22 @@ import org.springframework.util.StringUtils; * * @author John Blum * @see org.springframework.beans.factory.BeanFactory - * @see org.springframework.beans.factory.BeanFactoryAware - * @see org.springframework.context.EnvironmentAware + * @see org.springframework.beans.factory.support.AbstractBeanDefinition + * @see org.springframework.beans.factory.support.BeanDefinitionBuilder + * @see org.springframework.beans.factory.support.BeanDefinitionRegistry * @see org.springframework.context.annotation.ImportBeanDefinitionRegistrar * @see org.springframework.core.env.Environment + * @see org.springframework.core.type.AnnotationMetadata * @see org.springframework.data.gemfire.config.annotation.EnableAutoRegionLookup + * @see org.springframework.data.gemfire.config.annotation.support.AbstractAnnotationConfigSupport * @see org.springframework.data.gemfire.config.support.AutoRegionLookupBeanPostProcessor + * @see org.springframework.expression.ExpressionParser * @since 1.9.0 */ -public class AutoRegionLookupConfiguration implements BeanFactoryAware, EnvironmentAware, - ImportBeanDefinitionRegistrar { +public class AutoRegionLookupConfiguration extends AbstractAnnotationConfigSupport + implements ImportBeanDefinitionRegistrar { + + private static final boolean DEFAULT_ENABLED = true; private static final AtomicBoolean AUTO_REGION_LOOKUP_BEAN_POST_PROCESSOR_REGISTERED = new AtomicBoolean(false); @@ -75,84 +79,83 @@ public class AutoRegionLookupConfiguration implements BeanFactoryAware, Environm private StandardEvaluationContext evaluationContext = new StandardEvaluationContext(); + /* (non-Javadoc) */ + @Override + protected Class getAnnotationType() { + return EnableAutoRegionLookup.class; + } + /** * {@inheritDoc} */ @Override public void setBeanFactory(BeanFactory beanFactory) throws BeansException { - evaluationContext.setBeanResolver(new BeanFactoryResolver(beanFactory)); + + super.setBeanFactory(beanFactory); + + this.evaluationContext.setBeanResolver(new BeanFactoryResolver(beanFactory)); if (beanFactory instanceof ConfigurableBeanFactory) { + ConfigurableBeanFactory configurableBeanFactory = (ConfigurableBeanFactory) beanFactory; - evaluationContext.setTypeLocator(new StandardTypeLocator(configurableBeanFactory.getBeanClassLoader())); + this.evaluationContext.setTypeLocator(new StandardTypeLocator( + configurableBeanFactory.getBeanClassLoader())); - ConversionService conversionService = configurableBeanFactory.getConversionService(); - - if (conversionService != null) { - evaluationContext.setTypeConverter(new StandardTypeConverter(conversionService)); - } + Optional.ofNullable(configurableBeanFactory.getConversionService()) + .ifPresent(conversionService -> + this.evaluationContext.setTypeConverter(new StandardTypeConverter(conversionService))); } } - /** - * {@inheritDoc} - */ - @Override - public void setEnvironment(Environment environment) { - this.environment = environment; - } - - /** - * Returns a reference to the configured {@link Environment} in the Spring application context. - * - * @return a reference to the configured {@link Environment}. - * @throws IllegalStateException if the {@link Environment} reference was not properly configured. - * @see org.springframework.core.env.Environment - */ - protected Environment getEnvironment() { - Assert.state(environment != null, "The Environment was not properly configured"); - return this.environment; - } - /** * {@inheritDoc} */ @Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { + Map enableAutoRegionLookupAttributes = importingClassMetadata.getAnnotationAttributes(EnableAutoRegionLookup.class.getName()); - String enabled = (String) enableAutoRegionLookupAttributes.get("enabled"); - - if (isEnabled(enabled)) { - registerAutoRegionLookupBeanPostProcessor(registry); - } + Optional.ofNullable(resolveProperty(propertyName("enable-auto-region-lookup"), + (Boolean) enableAutoRegionLookupAttributes.get("enabled"))) + .filter(Boolean.TRUE::equals) + .ifPresent(enabled -> registerAutoRegionLookupBeanPostProcessor(registry)); } - /* (non-Javadoc) */ + /** + * (non-Javadoc) + * + * This method was used to support Spring property placeholders and SpEL Expressions + * in the {@link EnableAutoRegionLookup#enabled()} attribute. However, this required the attribute to be + * of type {@link String}, which violates type-safety. We are favoring type-safety over configuration + * flexibility and offering alternative means to achieve flexible and dynamic configuration, e.g. properties + * from an {@literal application.properties} file. + */ private boolean isEnabled(String enabled) { + enabled = StringUtils.trimWhitespace(enabled); if (!Boolean.parseBoolean(enabled)) { try { // try parsing as a SpEL expression... - return spelParser.parseExpression(enabled).getValue(evaluationContext, Boolean.TYPE); + return this.spelParser.parseExpression(enabled).getValue(this.evaluationContext, Boolean.TYPE); } catch (EvaluationException ignore) { return false; } catch (ParseException ignore) { // try resolving as a Spring property placeholder expression... - return getEnvironment().getProperty(enabled, Boolean.TYPE, false); + return environment().getProperty(enabled, Boolean.TYPE, false); } } - return true; + return DEFAULT_ENABLED; } /* (non-Javadoc) */ private void registerAutoRegionLookupBeanPostProcessor(BeanDefinitionRegistry registry) { + if (AUTO_REGION_LOOKUP_BEAN_POST_PROCESSOR_REGISTERED.compareAndSet(false, true)) { AbstractBeanDefinition autoRegionLookupBeanPostProcessor = BeanDefinitionBuilder .rootBeanDefinition(AutoRegionLookupBeanPostProcessor.class) diff --git a/src/main/java/org/springframework/data/gemfire/config/annotation/CacheServerApplication.java b/src/main/java/org/springframework/data/gemfire/config/annotation/CacheServerApplication.java index 19eef694..c95cf5c1 100644 --- a/src/main/java/org/springframework/data/gemfire/config/annotation/CacheServerApplication.java +++ b/src/main/java/org/springframework/data/gemfire/config/annotation/CacheServerApplication.java @@ -40,14 +40,15 @@ import org.springframework.data.gemfire.server.SubscriptionEvictionPolicy; * and therefore will be configured, constructed and initialized as a Spring bean in the application context. * * @author John Blum + * @see org.apache.geode.cache.control.ResourceManager + * @see org.apache.geode.cache.server.CacheServer + * @see org.apache.geode.cache.server.ClientSubscriptionConfig + * @see org.springframework.beans.factory.BeanFactory * @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 * @since 1.9.0 */ @Target(ElementType.TYPE) @@ -62,28 +63,36 @@ public @interface CacheServerApplication { /** * Configures whether the {@link CacheServer} should start automatically at runtime. * - * Default is {@literal true). + * Defaults to {@literal true). + * + * Use {@literal spring.data.gemfire.cache.server.auto-startup} property in {@literal application.properties}. */ boolean autoStartup() default true; /** * Configures the ip address or host name that this cache server will listen on. * - * @see org.apache.geode.cache.server.CacheServer#DEFAULT_BIND_ADDRESS + * Defaults to {@link CacheServer#DEFAULT_BIND_ADDRESS}. + * + * Use {@literal spring.data.gemfire.cache.server.bind-address} property in {@literal application.properties}. */ String bindAddress() default CacheServer.DEFAULT_BIND_ADDRESS; /** * Indicates whether the "copy on read" is enabled for this cache. * - * Default is {@literal false}. + * Defaults to {@literal false}. + * + * Use {@literal spring.data.gemfire.cache.copy-on-read} property in {@literal application.properties}. */ boolean copyOnRead() default false; /** * Configures the percentage of heap at or above which the cache is considered in danger of becoming inoperable. * - * @see org.apache.geode.cache.control.ResourceManager#DEFAULT_CRITICAL_PERCENTAGE + * Defaults to {@link ResourceManager#DEFAULT_CRITICAL_PERCENTAGE}. + * + * Use {@literal spring.data.gemfire.cache.critical-heap-percentage} property in {@literal application.properties}. */ float criticalHeapPercentage() default ResourceManager.DEFAULT_CRITICAL_PERCENTAGE; @@ -92,7 +101,10 @@ public @interface CacheServerApplication { * after it has been forced out of the distributed system by a network partition event or has otherwise been * shunned by other members. Use this property to enable the auto-reconnect behavior. * - * Default is {@literal false}. + * Defaults to {@literal false}. + * + * Use {@literal spring.data.gemfire.cache.peer.enable-auto-reconnect} property + * in {@literal application.properties}. */ boolean enableAutoReconnect() default false; @@ -100,7 +112,9 @@ public @interface CacheServerApplication { * Configures the percentage of heap at or above which the eviction should begin on Regions configured * for HeapLRU eviction. * - * @see org.apache.geode.cache.control.ResourceManager#DEFAULT_EVICTION_PERCENTAGE + * Defaults to {@link ResourceManager#DEFAULT_EVICTION_PERCENTAGE}. + * + * Use {@literal spring.data.gemfire.cache.eviction-heap-percentage} property in {@literal application.properties}. */ float evictionHeapPercentage() default ResourceManager.DEFAULT_EVICTION_PERCENTAGE; @@ -108,69 +122,90 @@ public @interface CacheServerApplication { * Configures the ip address or host name that server locators will tell clients that this cache server * is listening on. * - * @see org.apache.geode.cache.server.CacheServer#DEFAULT_HOSTNAME_FOR_CLIENTS + * Defaults to {@link CacheServer#DEFAULT_HOSTNAME_FOR_CLIENTS}. + * + * Use {@literal spring.data.gemfire.cache.server.hostname-for-clients} property + * in {@literal application.properties}. */ String hostnameForClients() default CacheServer.DEFAULT_HOSTNAME_FOR_CLIENTS; /** * Configures the frequency in milliseconds to poll the load probe on this cache server. * - * @see org.apache.geode.cache.server.CacheServer#DEFAULT_LOAD_POLL_INTERVAL + * Defaults to {@link CacheServer#DEFAULT_LOAD_POLL_INTERVAL}. + * + * Use {@literal spring.data.gemfire.cache.server.load-poll-interval} property in {@literal application.properties}. */ long loadPollInterval() default CacheServer.DEFAULT_LOAD_POLL_INTERVAL; /** - * Configures the list of GemFire Locators defining the cluster to which this GemFire cache data node - * should connect. + * Configures the list of Locators defining the cluster to which this Spring cache application will connect. + * + * Use {@literal spring.data.gemfire.cache.copy-on-read} property in {@literal application.properties}. */ String locators() default ""; /** * Configures the length, in seconds, of distributed lock leases obtained by this cache. * - * Default is {@literal 120} seconds. + * Defaults to {@literal 120} seconds. + * + * Use {@literal spring.data.gemfire.cache.peer.lock-lease} property in {@literal application.properties}. */ int lockLease() default 120; /** * Configures the number of seconds a cache operation will wait to obtain a distributed lock lease. * - * Default is {@literal 60} seconds + * Defaults to {@literal 60} seconds. + * + * Use {@literal spring.data.gemfire.cache.peer.lock-timeout} property in {@literal application.properties}. */ int lockTimeout() default 60; /** * Configures the log level used to output log messages at GemFire cache runtime. * - * Default is {@literal config}. + * Defaults to {@literal config}. + * + * Use {@literal spring.data.gemfire.cache.log-level} property in {@literal application.properties}. */ String logLevel() default CacheServerConfiguration.DEFAULT_LOG_LEVEL; /** * Configures the maximum allowed client connections. * - * @see org.apache.geode.cache.server.CacheServer#DEFAULT_MAX_CONNECTIONS + * Defaults to {@link CacheServer#DEFAULT_MAX_CONNECTIONS}. + * + * Use {@literal spring.data.gemfire.cache.server.max-connections} property in {@literal application.properties}. */ int maxConnections() default CacheServer.DEFAULT_MAX_CONNECTIONS; /** * Configures he maximum number of messages that can be enqueued in a client-queue. * - * @see org.apache.geode.cache.server.CacheServer#DEFAULT_MAXIMUM_MESSAGE_COUNT + * Defaults to {@link CacheServer#DEFAULT_MAXIMUM_MESSAGE_COUNT}. + * + * Use {@literal spring.data.gemfire.cache.server.max-message-count} property in {@literal application.properties}. */ int maxMessageCount() default CacheServer.DEFAULT_MAXIMUM_MESSAGE_COUNT; /** * Configures the maximum number of threads allowed in this cache server to service client requests. * - * @see org.apache.geode.cache.server.CacheServer#DEFAULT_MAX_THREADS + * Defaults to {@link CacheServer#DEFAULT_MAX_THREADS}. + * + * Use {@literal spring.data.gemfire.cache.server.max-threads} property in {@literal application.properties}. */ int maxThreads() default CacheServer.DEFAULT_MAX_THREADS; /** * Configures the maximum amount of time between client pings. * - * @see org.apache.geode.cache.server.CacheServer#DEFAULT_MAXIMUM_TIME_BETWEEN_PINGS + * Defaults to {@link CacheServer#DEFAULT_MAXIMUM_TIME_BETWEEN_PINGS}. + * + * Use {@literal spring.data.gemfire.cache.server.max-time-between-pings} property + * in {@literal application.properties}. */ int maxTimeBetweenPings() default CacheServer.DEFAULT_MAXIMUM_TIME_BETWEEN_PINGS; @@ -178,54 +213,74 @@ public @interface CacheServerApplication { * Configures the frequency (in seconds) at which a message will be sent by the primary cache-server to all * the secondary cache-server nodes to remove the events which have already been dispatched from the queue. * - * Default is {@literal 1} second. + * Defaults to {@literal 1} second. + * + * Use {@literal spring.data.gemfire.cache.peer.message-sync-interval} property + * in {@literal application.properties}. */ int messageSyncInterval() default 1; /** * Configures the time (in seconds ) after which a message in the client queue will expire. * - * @see org.apache.geode.cache.server.CacheServer#DEFAULT_MESSAGE_TIME_TO_LIVE + * Defaults to {@link CacheServer#DEFAULT_MESSAGE_TIME_TO_LIVE}. + * + * Use {@literal spring.data.gemfire.cache.server.message-time-to-live} property + * in {@literal application.properties}. */ int messageTimeToLive() default CacheServer.DEFAULT_MESSAGE_TIME_TO_LIVE; /** * Configures the name of this GemFire member in the cluster (distributed system). * - * Default is {@literal SpringBasedCacheClientApplication}. + * Defaults to {@literal SpringBasedCacheServerApplication}. + * + * Use {@literal spring.data.gemfire.cache.name} property in {@literal application.properties}. */ String name() default CacheServerConfiguration.DEFAULT_NAME; /** * Configures the port on which this cache server listens for clients. * - * @see org.apache.geode.cache.server.CacheServer#DEFAULT_PORT + * Defaults to {@link CacheServer#DEFAULT_PORT}. + * + * Use {@literal spring.data.gemfire.cache.server.port} property in {@literal application.properties}. */ int port() default CacheServer.DEFAULT_PORT; /** * Configures the number of seconds a cache get operation can spend searching for a value before it times out. * - * Default is {@literal 300} seconds. + * Defaults to {@literal 300} seconds, or 5 minutes. + * + * Use {@literal spring.data.gemfire.cache.peer.search-timeout} property in {@literal application.properties}. */ int searchTimeout() default 300; /** * Configures the configured buffer size of the socket connection for this CacheServer. * - * @see org.apache.geode.cache.server.CacheServer#DEFAULT_SOCKET_BUFFER_SIZE + * Defaults to {@link CacheServer#DEFAULT_SOCKET_BUFFER_SIZE}. + * + * Use {@literal spring.data.gemfire.cache.server.socket-buffer-size} property in {@literal application.properties}. */ int socketBufferSize() default CacheServer.DEFAULT_SOCKET_BUFFER_SIZE; /** * Configures the capacity of the client queue. * - * @see org.apache.geode.cache.server.ClientSubscriptionConfig#DEFAULT_CAPACITY + * Defaults to {@link ClientSubscriptionConfig#DEFAULT_CAPACITY}. + * + * Use {@literal spring.data.gemfire.cache.server.subscription-capacity} property + * in {@literal application.properties}. */ int subscriptionCapacity() default ClientSubscriptionConfig.DEFAULT_CAPACITY; /** * Configures the disk store name for overflow. + * + * Use {@literal spring.data.gemfire.cache.server.subscription-disk-store-name} property + * in {@literal application.properties}. */ String subscriptionDiskStoreName() default ""; @@ -233,6 +288,9 @@ public @interface CacheServerApplication { * Configures the eviction policy that is executed when capacity of the client queue is reached. * * Defaults to {@link SubscriptionEvictionPolicy#NONE}. + * + * Use {@literal spring.data.gemfire.cache.server.subscription-eviction-policy} property + * in {@literal application.properties}. */ SubscriptionEvictionPolicy subscriptionEvictionPolicy() default SubscriptionEvictionPolicy.NONE; @@ -242,6 +300,8 @@ public @interface CacheServerApplication { * created in a non-Spring managed, GemFire context. * * Defaults to {@literal false}. + * + * Use {@literal spring.data.gemfire.use-bean-factory-locator} property in {@literal application.properties}. */ boolean useBeanFactoryLocator() default false; @@ -249,8 +309,22 @@ public @interface CacheServerApplication { * Configures whether this GemFire cache member node would pull it's configuration meta-data * from the cluster-based Cluster Configuration service. * - * Default is {@literal false}. + * Defaults to {@literal false}. + * + * Use {@literal spring.data.gemfire.cache.peer.use-cluster-configuration} property + * in {@literal application.properties}. */ boolean useClusterConfiguration() default false; + /** + * Configures the tcpNoDelay setting of sockets used to send messages to clients. + * + * TcpNoDelay is enabled by default. + * + * Use either the {@literal spring.data.gemfire.cache.server..tcp-no-delay} property + * or the {@literal spring.data.gemfire.cache.server.tcp-no-delay} property + * in {@literal application.properties}. + */ + boolean tcpNoDelay() default CacheServer.DEFAULT_TCP_NO_DELAY; + } diff --git a/src/main/java/org/springframework/data/gemfire/config/annotation/CacheServerConfiguration.java b/src/main/java/org/springframework/data/gemfire/config/annotation/CacheServerConfiguration.java index c867231b..ab12ad89 100644 --- a/src/main/java/org/springframework/data/gemfire/config/annotation/CacheServerConfiguration.java +++ b/src/main/java/org/springframework/data/gemfire/config/annotation/CacheServerConfiguration.java @@ -28,11 +28,13 @@ import java.util.Set; import java.util.stream.Collectors; import org.apache.geode.cache.Cache; +import org.apache.geode.cache.GemFireCache; 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.apache.shiro.util.Assert; import org.springframework.beans.factory.ListableBeanFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; @@ -70,6 +72,8 @@ public class CacheServerConfiguration extends PeerCacheConfiguration { private boolean autoStartup = DEFAULT_AUTO_STARTUP; + private Boolean tcpNoDelay; + private Integer maxConnections; private Integer maxMessageCount; private Integer maxThreads; @@ -105,28 +109,32 @@ public class CacheServerConfiguration extends PeerCacheConfiguration { * @see org.apache.geode.cache.Cache */ @Bean - public CacheServerFactoryBean gemfireCacheServer(Cache gemfireCache) { + public CacheServerFactoryBean gemfireCacheServer(GemFireCache gemfireCache) { + + Assert.isInstanceOf(Cache.class, gemfireCache, + "GemFireCache must be an instance of org.apache.geode.cache.Cache"); CacheServerFactoryBean gemfireCacheServer = new CacheServerFactoryBean(); - gemfireCacheServer.setCache(gemfireCache); + gemfireCacheServer.setCache((Cache) gemfireCache); gemfireCacheServer.setCacheServerConfigurers(resolveCacheServerConfigurers()); - gemfireCacheServer.setAutoStartup(autoStartup()); - gemfireCacheServer.setBindAddress(bindAddress()); - gemfireCacheServer.setHostNameForClients(hostnameForClients()); - gemfireCacheServer.setListeners(interestRegistrationListeners()); - gemfireCacheServer.setLoadPollInterval(loadPollInterval()); - gemfireCacheServer.setMaxConnections(maxConnections()); - gemfireCacheServer.setMaxMessageCount(maxMessageCount()); - gemfireCacheServer.setMaxThreads(maxThreads()); - gemfireCacheServer.setMaxTimeBetweenPings(maxTimeBetweenPings()); - gemfireCacheServer.setMessageTimeToLive(messageTimeToLive()); - gemfireCacheServer.setPort(port()); - gemfireCacheServer.setServerLoadProbe(serverLoadProbe()); - gemfireCacheServer.setSocketBufferSize(socketBufferSize()); - gemfireCacheServer.setSubscriptionCapacity(subscriptionCapacity()); - gemfireCacheServer.setSubscriptionDiskStore(subscriptionDiskStoreName()); - gemfireCacheServer.setSubscriptionEvictionPolicy(subscriptionEvictionPolicy()); + gemfireCacheServer.setAutoStartup(isAutoStartup()); + gemfireCacheServer.setBindAddress(getBindAddress()); + gemfireCacheServer.setHostNameForClients(getHostnameForClients()); + gemfireCacheServer.setListeners(getInterestRegistrationListeners()); + gemfireCacheServer.setLoadPollInterval(getLoadPollInterval()); + gemfireCacheServer.setMaxConnections(getMaxConnections()); + gemfireCacheServer.setMaxMessageCount(getMaxMessageCount()); + gemfireCacheServer.setMaxThreads(getMaxThreads()); + gemfireCacheServer.setMaxTimeBetweenPings(getMaxTimeBetweenPings()); + gemfireCacheServer.setMessageTimeToLive(getMessageTimeToLive()); + gemfireCacheServer.setPort(getPort()); + gemfireCacheServer.setServerLoadProbe(getServerLoadProbe()); + gemfireCacheServer.setSocketBufferSize(getSocketBufferSize()); + gemfireCacheServer.setSubscriptionCapacity(getSubscriptionCapacity()); + gemfireCacheServer.setSubscriptionDiskStore(getSubscriptionDiskStoreName()); + gemfireCacheServer.setSubscriptionEvictionPolicy(getSubscriptionEvictionPolicy()); + gemfireCacheServer.setTcpNoDelay(getTcpNoDelay()); return gemfireCacheServer; } @@ -140,10 +148,12 @@ public class CacheServerConfiguration extends PeerCacheConfiguration { Optional.of(this.beanFactory()) .filter(beanFactory -> beanFactory instanceof ListableBeanFactory) .map(beanFactory -> { + Map beansOfType = ((ListableBeanFactory) beanFactory) .getBeansOfType(CacheServerConfigurer.class, true, true); return nullSafeMap(beansOfType).values().stream().collect(Collectors.toList()); + }) .orElseGet(Collections::emptyList) ); @@ -165,24 +175,53 @@ public class CacheServerConfiguration extends PeerCacheConfiguration { if (isCacheServerApplication(importMetadata)) { - Map cacheServerApplicationMetadata = + Map cacheServerApplicationAttributes = importMetadata.getAnnotationAttributes(getAnnotationTypeName()); - setAutoStartup(Boolean.TRUE.equals(cacheServerApplicationMetadata.get("autoStartup"))); - setBindAddress((String) cacheServerApplicationMetadata.get("bindAddress")); - setHostnameForClients((String) cacheServerApplicationMetadata.get("hostnameForClients")); - setLoadPollInterval((Long) cacheServerApplicationMetadata.get("loadPollInterval")); - setMaxConnections((Integer) cacheServerApplicationMetadata.get("maxConnections")); - setMaxMessageCount((Integer) cacheServerApplicationMetadata.get("maxMessageCount")); - setMaxThreads((Integer) cacheServerApplicationMetadata.get("maxThreads")); - setMaxTimeBetweenPings((Integer) cacheServerApplicationMetadata.get("maxTimeBetweenPings")); - setMessageTimeToLive((Integer) cacheServerApplicationMetadata.get("messageTimeToLive")); - setPort((Integer) cacheServerApplicationMetadata.get("port")); - setSocketBufferSize((Integer) cacheServerApplicationMetadata.get("socketBufferSize")); - setSubscriptionCapacity((Integer) cacheServerApplicationMetadata.get("subscriptionCapacity")); - setSubscriptionDiskStoreName((String) cacheServerApplicationMetadata.get("subscriptionDiskStoreName")); - setSubscriptionEvictionPolicy((SubscriptionEvictionPolicy) - cacheServerApplicationMetadata.get("subscriptionEvictionPolicy")); + setAutoStartup(resolveProperty(cacheServerProperty("auto-startup"), + Boolean.TRUE.equals(cacheServerApplicationAttributes.get("autoStartup")))); + + setBindAddress(resolveProperty(cacheServerProperty("bind-address"), + (String) cacheServerApplicationAttributes.get("bindAddress"))); + + setHostnameForClients(resolveProperty(cacheServerProperty("hostname-for-clients"), + (String) cacheServerApplicationAttributes.get("hostnameForClients"))); + + setLoadPollInterval(resolveProperty(cacheServerProperty("load-poll-interval"), + (Long) cacheServerApplicationAttributes.get("loadPollInterval"))); + + setMaxConnections(resolveProperty(cacheServerProperty("max-connections"), + (Integer) cacheServerApplicationAttributes.get("maxConnections"))); + + setMaxMessageCount(resolveProperty(cacheServerProperty("max-message-count"), + (Integer) cacheServerApplicationAttributes.get("maxMessageCount"))); + + setMaxThreads(resolveProperty(cacheServerProperty("max-threads"), + (Integer) cacheServerApplicationAttributes.get("maxThreads"))); + + setMaxTimeBetweenPings(resolveProperty(cacheServerProperty("max-time-between-pings"), + (Integer) cacheServerApplicationAttributes.get("maxTimeBetweenPings"))); + + setMessageTimeToLive(resolveProperty(cacheServerProperty("message-time-to-live"), + (Integer) cacheServerApplicationAttributes.get("messageTimeToLive"))); + + setPort(resolveProperty(cacheServerProperty("port"), + (Integer) cacheServerApplicationAttributes.get("port"))); + + setSocketBufferSize(resolveProperty(cacheServerProperty("socket-buffer-size"), + (Integer) cacheServerApplicationAttributes.get("socketBufferSize"))); + + setSubscriptionCapacity(resolveProperty(cacheServerProperty("subscription-capacity"), + (Integer) cacheServerApplicationAttributes.get("subscriptionCapacity"))); + + setSubscriptionDiskStoreName(resolveProperty(cacheServerProperty("subscription-disk-store-name"), + (String) cacheServerApplicationAttributes.get("subscriptionDiskStoreName"))); + + setSubscriptionEvictionPolicy(resolveProperty(cacheServerProperty("subscription-eviction-policy"), + SubscriptionEvictionPolicy.class, (SubscriptionEvictionPolicy) cacheServerApplicationAttributes.get("subscriptionEvictionPolicy"))); + + setTcpNoDelay(resolveProperty(cacheServerProperty("tcpNoDelay"), + (Boolean) cacheServerApplicationAttributes.get("tcpNoDelay"))); } } @@ -199,7 +238,7 @@ public class CacheServerConfiguration extends PeerCacheConfiguration { this.autoStartup = autoStartup; } - protected boolean autoStartup() { + protected boolean isAutoStartup() { return this.autoStartup; } @@ -208,7 +247,7 @@ public class CacheServerConfiguration extends PeerCacheConfiguration { this.bindAddress = bindAddress; } - protected String bindAddress() { + protected String getBindAddress() { return Optional.ofNullable(this.bindAddress).filter(StringUtils::hasText) .orElse(CacheServer.DEFAULT_BIND_ADDRESS); } @@ -218,7 +257,7 @@ public class CacheServerConfiguration extends PeerCacheConfiguration { this.hostnameForClients = hostnameForClients; } - protected String hostnameForClients() { + protected String getHostnameForClients() { return Optional.ofNullable(this.hostnameForClients).filter(StringUtils::hasText) .orElse(CacheServer.DEFAULT_HOSTNAME_FOR_CLIENTS); } @@ -228,7 +267,7 @@ public class CacheServerConfiguration extends PeerCacheConfiguration { this.interestRegistrationListeners = interestRegistrationListeners; } - protected Set interestRegistrationListeners() { + protected Set getInterestRegistrationListeners() { return nullSafeSet(this.interestRegistrationListeners); } @@ -237,7 +276,7 @@ public class CacheServerConfiguration extends PeerCacheConfiguration { this.loadPollInterval = loadPollInterval; } - protected Long loadPollInterval() { + protected Long getLoadPollInterval() { return Optional.ofNullable(this.loadPollInterval).orElse(CacheServer.DEFAULT_LOAD_POLL_INTERVAL); } @@ -246,7 +285,7 @@ public class CacheServerConfiguration extends PeerCacheConfiguration { this.maxConnections = maxConnections; } - protected Integer maxConnections() { + protected Integer getMaxConnections() { return Optional.ofNullable(this.maxConnections).orElse(CacheServer.DEFAULT_MAX_CONNECTIONS); } @@ -255,7 +294,7 @@ public class CacheServerConfiguration extends PeerCacheConfiguration { this.maxMessageCount = maxMessageCount; } - protected Integer maxMessageCount() { + protected Integer getMaxMessageCount() { return Optional.ofNullable(this.maxMessageCount).orElse(CacheServer.DEFAULT_MAXIMUM_MESSAGE_COUNT); } @@ -264,7 +303,7 @@ public class CacheServerConfiguration extends PeerCacheConfiguration { this.maxThreads = maxThreads; } - protected Integer maxThreads() { + protected Integer getMaxThreads() { return Optional.ofNullable(this.maxThreads).orElse(CacheServer.DEFAULT_MAX_THREADS); } @@ -273,7 +312,7 @@ public class CacheServerConfiguration extends PeerCacheConfiguration { this.maxTimeBetweenPings = maxTimeBetweenPings; } - protected Integer maxTimeBetweenPings() { + protected Integer getMaxTimeBetweenPings() { return Optional.ofNullable(this.maxTimeBetweenPings).orElse(CacheServer.DEFAULT_MAXIMUM_TIME_BETWEEN_PINGS); } @@ -282,7 +321,7 @@ public class CacheServerConfiguration extends PeerCacheConfiguration { this.messageTimeToLive = messageTimeToLive; } - protected Integer messageTimeToLive() { + protected Integer getMessageTimeToLive() { return Optional.ofNullable(this.messageTimeToLive).orElse(CacheServer.DEFAULT_MESSAGE_TIME_TO_LIVE); } @@ -291,7 +330,7 @@ public class CacheServerConfiguration extends PeerCacheConfiguration { this.port = port; } - protected Integer port() { + protected Integer getPort() { return Optional.ofNullable(this.port).orElse(CacheServer.DEFAULT_PORT); } @@ -300,7 +339,7 @@ public class CacheServerConfiguration extends PeerCacheConfiguration { this.serverLoadProbe = serverLoadProbe; } - protected ServerLoadProbe serverLoadProbe() { + protected ServerLoadProbe getServerLoadProbe() { return Optional.ofNullable(this.serverLoadProbe).orElse(CacheServer.DEFAULT_LOAD_PROBE); } @@ -309,7 +348,7 @@ public class CacheServerConfiguration extends PeerCacheConfiguration { this.socketBufferSize = socketBufferSize; } - protected Integer socketBufferSize() { + protected Integer getSocketBufferSize() { return Optional.ofNullable(this.socketBufferSize).orElse(CacheServer.DEFAULT_SOCKET_BUFFER_SIZE); } @@ -318,7 +357,7 @@ public class CacheServerConfiguration extends PeerCacheConfiguration { this.subscriptionCapacity = subscriptionCapacity; } - protected Integer subscriptionCapacity() { + protected Integer getSubscriptionCapacity() { return Optional.ofNullable(this.subscriptionCapacity).orElse(ClientSubscriptionConfig.DEFAULT_CAPACITY); } @@ -327,7 +366,7 @@ public class CacheServerConfiguration extends PeerCacheConfiguration { this.subscriptionDiskStoreName = subscriptionDiskStoreName; } - protected String subscriptionDiskStoreName() { + protected String getSubscriptionDiskStoreName() { return this.subscriptionDiskStoreName; } @@ -336,10 +375,19 @@ public class CacheServerConfiguration extends PeerCacheConfiguration { this.subscriptionEvictionPolicy = subscriptionEvictionPolicy; } - protected SubscriptionEvictionPolicy subscriptionEvictionPolicy() { + protected SubscriptionEvictionPolicy getSubscriptionEvictionPolicy() { return Optional.ofNullable(this.subscriptionEvictionPolicy).orElse(SubscriptionEvictionPolicy.DEFAULT); } + /* (non-Javadoc) */ + void setTcpNoDelay(Boolean tcpNoDelay) { + this.tcpNoDelay = tcpNoDelay; + } + + protected Boolean getTcpNoDelay() { + return Optional.ofNullable(this.tcpNoDelay).orElse(CacheServer.DEFAULT_TCP_NO_DELAY); + } + @Override public String toString() { return DEFAULT_NAME; diff --git a/src/main/java/org/springframework/data/gemfire/config/annotation/ClientCacheApplication.java b/src/main/java/org/springframework/data/gemfire/config/annotation/ClientCacheApplication.java index dea2dec8..26b059fa 100644 --- a/src/main/java/org/springframework/data/gemfire/config/annotation/ClientCacheApplication.java +++ b/src/main/java/org/springframework/data/gemfire/config/annotation/ClientCacheApplication.java @@ -56,14 +56,18 @@ public @interface ClientCacheApplication { /** * Indicates whether the "copy on read" is enabled for this cache. * - * Default is {@literal false}. + * Defaults to {@literal false}. + * + * Use {@literal spring.data.gemfire.cache.copy-on-read} property in {@literal application.properties}. */ boolean copyOnRead() default false; /** * Configures the percentage of heap at or above which the cache is considered in danger of becoming inoperable. * - * @see org.apache.geode.cache.control.ResourceManager#DEFAULT_CRITICAL_PERCENTAGE + * Defaults to {@link ResourceManager#DEFAULT_CRITICAL_PERCENTAGE}. + * + * Use {@literal spring.data.gemfire.cache.critical-heap-percentage} property in {@literal application.properties}. */ float criticalHeapPercentage() default ResourceManager.DEFAULT_CRITICAL_PERCENTAGE; @@ -71,12 +75,19 @@ public @interface ClientCacheApplication { * Used only for clients in a client/server installation. If set, this indicates that the client is durable * and identifies the client. The ID is used by servers to reestablish any messaging that was interrupted * by client downtime. + * + * Use {@literal spring.data.gemfire.cache.client.durable-client-id} property in {@literal application.properties}. */ String durableClientId() default ""; /** * Used only for clients in a client/server installation. Number of seconds this client can remain disconnected * from its server and have the server continue to accumulate durable events for it. + * + * Defaults to {@literal 300} seconds, or 5 minutes. + * + * Use {@literal spring.data.gemfire.cache.client.durable-client-timeout} property + * in {@literal application.properties}. */ int durableClientTimeout() default 300; @@ -84,83 +95,117 @@ public @interface ClientCacheApplication { * Configures the percentage of heap at or above which the eviction should begin on Regions configured * for HeapLRU eviction. * - * @see org.apache.geode.cache.control.ResourceManager#DEFAULT_EVICTION_PERCENTAGE + * Defaults to {@link ResourceManager#DEFAULT_EVICTION_PERCENTAGE}. + * + * Use {@literal spring.data.gemfire.cache.eviction-heap-percentage} property in {@literal application.properties}. */ float evictionHeapPercentage() default ResourceManager.DEFAULT_EVICTION_PERCENTAGE; /** * Configures the free connection timeout for this pool. * - * @see org.apache.geode.cache.client.PoolFactory#DEFAULT_FREE_CONNECTION_TIMEOUT + * Defaults to {@link PoolFactory#DEFAULT_FREE_CONNECTION_TIMEOUT}. + * + * Use either the {@literal spring.data.gemfire.pool.default.free-connection-timeout} property + * or the {@literal spring.data.gemfire.pool.free-connection-timeout} property in {@literal application.properties}. */ int freeConnectionTimeout() default PoolFactory.DEFAULT_FREE_CONNECTION_TIMEOUT; /** * Configures the amount of time a connection can be idle before expiring the connection. * - * @see org.apache.geode.cache.client.PoolFactory#DEFAULT_IDLE_TIMEOUT + * Defaults to {@link PoolFactory#DEFAULT_IDLE_TIMEOUT}. + * + * Use either the {@literal spring.data.gemfire.pool.default.idle-timeout} property + * or the {@literal spring.data.gemfire.pool.idle-timeout} property in {@literal application.properties}. */ long idleTimeout() default PoolFactory.DEFAULT_IDLE_TIMEOUT; /** * Configures whether to keep the client queues alive on the server when the client is disconnected * - * Default is {@literal false}. + * Defaults to {@literal false}. + * + * Use {@literal spring.data.gemfire.cache.client.keep-alive} property in {@literal application.properties}. */ boolean keepAlive() default false; /** * Configures the load conditioning interval for this pool. * - * @see org.apache.geode.cache.client.PoolFactory#DEFAULT_LOAD_CONDITIONING_INTERVAL + * Defaults to {@link PoolFactory#DEFAULT_LOAD_CONDITIONING_INTERVAL}. + * + * Use either the {@literal spring.data.gemfire.pool.default.load-conditioning-interval} property + * or the {@literal spring.data.gemfire.pool.load-conditioning-interval} property + * in {@literal application.properties}. */ int loadConditioningInterval() default PoolFactory.DEFAULT_LOAD_CONDITIONING_INTERVAL; /** - * Configures the GemFire {@link org.apache.geode.distributed.Locator}s to which + * Configures the GemFire {@link org.apache.geode.distributed.Locator Locators} to which * this cache client will connect. + * + * Use either the {@literal spring.data.gemfire.pool.default.locators} property + * or the {@literal spring.data.gemfire.pool.locators} property in {@literal application.properties}. */ Locator[] locators() default {}; /** * Configures the log level used to output log messages at GemFire cache runtime. * - * Default is {@literal config}. + * Defaults to {@literal config}. + * + * Use {@literal spring.data.gemfire.cache.log-level} property in {@literal application.properties}. */ String logLevel() default ClientCacheConfiguration.DEFAULT_LOG_LEVEL; /** * Configures the max number of client to server connections that the pool will create. * - * @see org.apache.geode.cache.client.PoolFactory#DEFAULT_MAX_CONNECTIONS + * Defaults to {@link PoolFactory#DEFAULT_MAX_CONNECTIONS}. + * + * Use either the {@literal spring.data.gemfire.pool.default.max-connections} property + * or the {@literal spring.data.gemfire.pool.max-connections} property in {@literal application.properties}. */ int maxConnections() default PoolFactory.DEFAULT_MAX_CONNECTIONS; /** * Configures the minimum number of connections to keep available at all times. * - * @see org.apache.geode.cache.client.PoolFactory#DEFAULT_MIN_CONNECTIONS + * Defaults to {@link PoolFactory#DEFAULT_MIN_CONNECTIONS}. + * + * Use either the {@literal spring.data.gemfire.pool.default.min-connections} property + * or the {@literal spring.data.gemfire.pool.min-connections} property in {@literal application.properties}. */ int minConnections() default PoolFactory.DEFAULT_MIN_CONNECTIONS; /** * If set to true then the created pool can be used by multiple users. * - * @see org.apache.geode.cache.client.PoolFactory#DEFAULT_MULTIUSER_AUTHENTICATION + * Defaults to {@link PoolFactory#DEFAULT_MULTIUSER_AUTHENTICATION}. + * + * Use either the {@literal spring.data.gemfire.pool.default.multi-user-authentication} property + * or the {@literal spring.data.gemfire.pool.multi-user-authentication} property + * in {@literal application.properties}. */ boolean multiUserAuthentication() default PoolFactory.DEFAULT_MULTIUSER_AUTHENTICATION; /** * Configures the name of this GemFire member in the cluster (distributed system). * - * Default is {@literal SpringBasedCacheClientApplication}. + * Defaults to {@literal SpringBasedCacheClientApplication}. + * + * Use {@literal spring.data.gemfire.cache.name} property in {@literal application.properties}. */ String name() default ClientCacheConfiguration.DEFAULT_NAME; /** * Configures how often to ping servers to verify that they are still alive. * - * @see org.apache.geode.cache.client.PoolFactory#DEFAULT_PING_INTERVAL + * Defaults to {@link PoolFactory#DEFAULT_PING_INTERVAL}. + * + * Use either the {@literal spring.data.gemfire.pool.default.ping-interval} property + * or the {@literal spring.data.gemfire.pool.ping-interval} property in {@literal application.properties}. */ long pingInterval() default PoolFactory.DEFAULT_PING_INTERVAL; @@ -168,7 +213,10 @@ public @interface ClientCacheApplication { * By default {@code prSingleHopEnabled} is {@literal true} in which case the client is aware of the location * of partitions on servers hosting Regions with {@link org.apache.geode.cache.DataPolicy#PARTITION}. * - * @see org.apache.geode.cache.client.PoolFactory#DEFAULT_PR_SINGLE_HOP_ENABLED + * Defaults to {@link PoolFactory#DEFAULT_PR_SINGLE_HOP_ENABLED}. + * + * Use either the {@literal spring.data.gemfire.pool.default.pr-single-hop-enabled} property + * or the {@literal spring.data.gemfire.pool.pr-single-hop-enabled} property in {@literal application.properties}. */ boolean prSingleHopEnabled() default PoolFactory.DEFAULT_PR_SINGLE_HOP_ENABLED; @@ -176,48 +224,69 @@ public @interface ClientCacheApplication { * Configures the number of milliseconds to wait for a response from a server before timing out the operation * and trying another server (if any are available). * - * @see org.apache.geode.cache.client.PoolFactory#DEFAULT_READ_TIMEOUT + * Defaults to {@link PoolFactory#DEFAULT_READ_TIMEOUT}. + * + * Use either the {@literal spring.data.gemfire.pool.default.read-timeout} property + * or the {@literal spring.data.gemfire.pool.read-timeout} property in {@literal application.properties}. */ int readTimeout() default PoolFactory.DEFAULT_READ_TIMEOUT; /** * Notifies the server that this durable client is ready to receive updates. * - * Default is {@literal false}. + * Defaults to {@literal false}. + * + * Use either the {@literal spring.data.gemfire.pool.default.ready-for-events} property + * or the {@literal spring.data.gemfire.pool.ready-for-events} property in {@literal application.properties}. */ boolean readyForEvents() default false; /** * Configures the number of times to retry a request after timeout/exception. * - * @see org.apache.geode.cache.client.PoolFactory#DEFAULT_RETRY_ATTEMPTS + * Defaults to {@link PoolFactory#DEFAULT_RETRY_ATTEMPTS}. + * + * Use either the {@literal spring.data.gemfire.pool.default.retry-attempts} property + * or the {@literal spring.data.gemfire.pool.retry-attempts} property in {@literal application.properties}. */ int retryAttempts() default PoolFactory.DEFAULT_RETRY_ATTEMPTS; /** * 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 + * Defaults to {@link PoolFactory#DEFAULT_SERVER_GROUP}. + * + * Use either the {@literal spring.data.gemfire.pool.default.server-group} property + * or the {@literal spring.data.gemfire.pool.server-group} property in {@literal application.properties}. */ String serverGroup() default PoolFactory.DEFAULT_SERVER_GROUP; /** - * Configures the GemFire {@link org.apache.geode.cache.server.CacheServer}s to which + * Configures the GemFire {@link org.apache.geode.cache.server.CacheServer CacheServers} to which * this cache client will connect. + * + * Use either the {@literal spring.data.gemfire.pool.default.servers} property + * or the {@literal spring.data.gemfire.pool.servers} property in {@literal application.properties}. */ Server[] servers() default {}; /** * Configures the socket buffer size for each connection made in this pool. * - * @see org.apache.geode.cache.client.PoolFactory#DEFAULT_SOCKET_BUFFER_SIZE + * Defaults to {@link PoolFactory#DEFAULT_SOCKET_BUFFER_SIZE}. + * + * Use either the {@literal spring.data.gemfire.pool.default.socket-buffer-size} property + * or the {@literal spring.data.gemfire.pool.socket-buffer-size} property in {@literal application.properties}. */ int socketBufferSize() default PoolFactory.DEFAULT_SOCKET_BUFFER_SIZE; /** * Configures how often to send client statistics to the server. * - * @see org.apache.geode.cache.client.PoolFactory#DEFAULT_STATISTIC_INTERVAL + * Defaults to {@link PoolFactory#DEFAULT_STATISTIC_INTERVAL}. + * + * Use either the {@literal spring.data.gemfire.pool.default.statistic-interval} property + * or the {@literal spring.data.gemfire.pool.statistic-interval} property in {@literal application.properties}. */ int statisticInterval() default PoolFactory.DEFAULT_STATISTIC_INTERVAL; @@ -225,14 +294,21 @@ public @interface ClientCacheApplication { * Configures the interval in milliseconds to wait before sending acknowledgements to the cache server * for events received from the server subscriptions. * - * @see org.apache.geode.cache.client.PoolFactory#DEFAULT_SUBSCRIPTION_ACK_INTERVAL + * Defaults to {@link PoolFactory#DEFAULT_SUBSCRIPTION_ACK_INTERVAL}. + * + * Use either the {@literal spring.data.gemfire.pool.default.subscription-ack-interval} property + * or the {@literal spring.data.gemfire.pool.subscription-ack-interval} property + * in {@literal application.properties}. */ int subscriptionAckInterval() default PoolFactory.DEFAULT_SUBSCRIPTION_ACK_INTERVAL; /** * If set to true then the created pool will have server-to-client subscriptions enabled. * - * @see org.apache.geode.cache.client.PoolFactory#DEFAULT_SUBSCRIPTION_ENABLED + * Defaults to {@link PoolFactory#DEFAULT_SUBSCRIPTION_ENABLED}. + * + * Use either the {@literal spring.data.gemfire.pool.default.subscription-enabled} property + * or the {@literal spring.data.gemfire.pool.subscription-enabled} property in {@literal application.properties}. */ boolean subscriptionEnabled() default PoolFactory.DEFAULT_SUBSCRIPTION_ENABLED; @@ -240,21 +316,32 @@ public @interface ClientCacheApplication { * Configures the messageTrackingTimeout attribute which is the time-to-live period, in milliseconds, * for subscription events the client has received from the server. * - * @see org.apache.geode.cache.client.PoolFactory#DEFAULT_SUBSCRIPTION_MESSAGE_TRACKING_TIMEOUT + * Defaults to {@link PoolFactory#DEFAULT_SUBSCRIPTION_MESSAGE_TRACKING_TIMEOUT}. + * + * Use either the {@literal spring.data.gemfire.pool.default.subscription-message-tracking-timeout} property + * or the {@literal spring.data.gemfire.pool.subscription-message-tracking-timeout} property + * in {@literal application.properties}. */ int subscriptionMessageTrackingTimeout() default PoolFactory.DEFAULT_SUBSCRIPTION_MESSAGE_TRACKING_TIMEOUT; /** * Configures the redundancy level for this pools server-to-client subscriptions. * - * @see org.apache.geode.cache.client.PoolFactory#DEFAULT_SUBSCRIPTION_REDUNDANCY + * Defaults to {@link PoolFactory#DEFAULT_SUBSCRIPTION_REDUNDANCY}. + * + * Use either the {@literal spring.data.gemfire.pool.default.subscription-redundancy} property + * or the {@literal spring.data.gemfire.pool.subscription-redundancy} property in {@literal application.properties}. */ int subscriptionRedundancy() default PoolFactory.DEFAULT_SUBSCRIPTION_REDUNDANCY; /** * Configures the thread local connections policy for this pool. * - * @see org.apache.geode.cache.client.PoolFactory#DEFAULT_THREAD_LOCAL_CONNECTIONS + * Defaults to {@link PoolFactory#DEFAULT_THREAD_LOCAL_CONNECTIONS}. + * + * Use either the {@literal spring.data.gemfire.pool.default.thread-local-connections} property + * or the {@literal spring.data.gemfire.pool.thread-local-connections} property + * in {@literal application.properties}. */ boolean threadLocalConnections() default PoolFactory.DEFAULT_THREAD_LOCAL_CONNECTIONS; @@ -264,6 +351,8 @@ public @interface ClientCacheApplication { * created in a non-Spring managed, GemFire context. * * Defaults to {@literal false}. + * + * Use {@literal spring.data.gemfire.use-bean-factory-locator} property in {@literal application.properties}. */ boolean useBeanFactoryLocator() default false; diff --git a/src/main/java/org/springframework/data/gemfire/config/annotation/ClientCacheConfiguration.java b/src/main/java/org/springframework/data/gemfire/config/annotation/ClientCacheConfiguration.java index 1fca763a..26a69238 100644 --- a/src/main/java/org/springframework/data/gemfire/config/annotation/ClientCacheConfiguration.java +++ b/src/main/java/org/springframework/data/gemfire/config/annotation/ClientCacheConfiguration.java @@ -28,6 +28,7 @@ import java.util.stream.Collectors; import org.apache.geode.cache.client.ClientCache; import org.apache.geode.cache.client.Pool; +import org.apache.geode.cache.server.CacheServer; import org.springframework.beans.factory.ListableBeanFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.config.BeanDefinition; @@ -37,10 +38,12 @@ import org.springframework.context.annotation.Configuration; import org.springframework.core.annotation.AnnotationAttributes; import org.springframework.core.type.AnnotationMetadata; import org.springframework.data.gemfire.CacheFactoryBean; +import org.springframework.data.gemfire.GemfireUtils; import org.springframework.data.gemfire.client.ClientCacheFactoryBean; import org.springframework.data.gemfire.config.support.ClientRegionPoolBeanFactoryPostProcessor; import org.springframework.data.gemfire.support.ConnectionEndpoint; import org.springframework.data.gemfire.support.ConnectionEndpointList; +import org.springframework.util.StringUtils; /** * Spring {@link Configuration} class used to construct, configure and initialize @@ -122,35 +125,36 @@ public class ClientCacheConfiguration extends AbstractCacheConfiguration { ClientCacheFactoryBean gemfireCache = constructCacheFactoryBean(); gemfireCache.setClientCacheConfigurers(resolveClientCacheConfigurers()); - gemfireCache.setDurableClientId(durableClientId()); - gemfireCache.setDurableClientTimeout(durableClientTimeout()); - gemfireCache.setFreeConnectionTimeout(freeConnectionTimeout()); - gemfireCache.setIdleTimeout(idleTimeout()); - gemfireCache.setKeepAlive(keepAlive()); - gemfireCache.setLocators(poolLocators()); - gemfireCache.setLoadConditioningInterval(loadConditioningInterval()); - gemfireCache.setMaxConnections(maxConnections()); - gemfireCache.setMinConnections(minConnections()); - gemfireCache.setMultiUserAuthentication(multiUserAuthentication()); - gemfireCache.setPingInterval(pingInterval()); - gemfireCache.setPrSingleHopEnabled(prSingleHopEnabled()); - gemfireCache.setReadTimeout(readTimeout()); - gemfireCache.setReadyForEvents(readyForEvents()); - gemfireCache.setRetryAttempts(retryAttempts()); - gemfireCache.setServerGroup(serverGroup()); - gemfireCache.setServers(poolServers()); - gemfireCache.setSocketBufferSize(socketBufferSize()); - gemfireCache.setStatisticsInterval(statisticsInterval()); - gemfireCache.setSubscriptionAckInterval(subscriptionAckInterval()); - gemfireCache.setSubscriptionEnabled(subscriptionEnabled()); - gemfireCache.setSubscriptionMessageTrackingTimeout(subscriptionMessageTrackingTimeout()); - gemfireCache.setSubscriptionRedundancy(subscriptionRedundancy()); - gemfireCache.setThreadLocalConnections(threadLocalConnections()); + gemfireCache.setDurableClientId(getDurableClientId()); + gemfireCache.setDurableClientTimeout(getDurableClientTimeout()); + gemfireCache.setFreeConnectionTimeout(getFreeConnectionTimeout()); + gemfireCache.setIdleTimeout(getIdleTimeout()); + gemfireCache.setKeepAlive(getKeepAlive()); + gemfireCache.setLocators(getPoolLocators()); + gemfireCache.setLoadConditioningInterval(getLoadConditioningInterval()); + gemfireCache.setMaxConnections(getMaxConnections()); + gemfireCache.setMinConnections(getMinConnections()); + gemfireCache.setMultiUserAuthentication(getMultiUserAuthentication()); + gemfireCache.setPingInterval(getPingInterval()); + gemfireCache.setPrSingleHopEnabled(getPrSingleHopEnabled()); + gemfireCache.setReadTimeout(getReadTimeout()); + gemfireCache.setReadyForEvents(getReadyForEvents()); + gemfireCache.setRetryAttempts(getRetryAttempts()); + gemfireCache.setServerGroup(getServerGroup()); + gemfireCache.setServers(getPoolServers()); + gemfireCache.setSocketBufferSize(getSocketBufferSize()); + gemfireCache.setStatisticsInterval(getStatisticsInterval()); + gemfireCache.setSubscriptionAckInterval(getSubscriptionAckInterval()); + gemfireCache.setSubscriptionEnabled(getSubscriptionEnabled()); + gemfireCache.setSubscriptionMessageTrackingTimeout(getSubscriptionMessageTrackingTimeout()); + gemfireCache.setSubscriptionRedundancy(getSubscriptionRedundancy()); + gemfireCache.setThreadLocalConnections(getThreadLocalConnections()); return gemfireCache; } /* (non-Javadoc) */ + @SuppressWarnings("all") private List resolveClientCacheConfigurers() { return Optional.ofNullable(this.clientCacheConfigurers) @@ -159,10 +163,12 @@ public class ClientCacheConfiguration extends AbstractCacheConfiguration { Optional.of(this.beanFactory()) .filter(beanFactory -> beanFactory instanceof ListableBeanFactory) .map(beanFactory -> { + Map beansOfType = ((ListableBeanFactory) beanFactory) .getBeansOfType(ClientCacheConfigurer.class, true, true); return nullSafeMap(beansOfType).values().stream().collect(Collectors.toList()); + }) .orElseGet(Collections::emptyList) ); @@ -227,28 +233,109 @@ public class ClientCacheConfiguration extends AbstractCacheConfiguration { Map clientCacheApplicationAttributes = importMetadata.getAnnotationAttributes(getAnnotationTypeName()); - setDurableClientId((String) clientCacheApplicationAttributes.get("durableClientId")); - setDurableClientTimeout((Integer) clientCacheApplicationAttributes.get("durableClientTimeout")); - setFreeConnectionTimeout((Integer) clientCacheApplicationAttributes.get("freeConnectionTimeout")); - setIdleTimeout((Long) clientCacheApplicationAttributes.get("idleTimeout")); - setKeepAlive(Boolean.TRUE.equals(clientCacheApplicationAttributes.get("keepAlive"))); - setLoadConditioningInterval((Integer) clientCacheApplicationAttributes.get("loadConditioningInterval")); - setMaxConnections((Integer) clientCacheApplicationAttributes.get("maxConnections")); - setMinConnections((Integer) clientCacheApplicationAttributes.get("minConnections")); - setMultiUserAuthentication(Boolean.TRUE.equals(clientCacheApplicationAttributes.get("multiUserAuthentication"))); - setPingInterval((Long) clientCacheApplicationAttributes.get("pingInterval")); - setPrSingleHopEnabled(Boolean.TRUE.equals(clientCacheApplicationAttributes.get("prSingleHopEnabled"))); - setReadTimeout((Integer) clientCacheApplicationAttributes.get("readTimeout")); - setReadyForEvents(Boolean.TRUE.equals(clientCacheApplicationAttributes.get("readyForEvents"))); - setRetryAttempts((Integer) clientCacheApplicationAttributes.get("retryAttempts")); - setServerGroup((String) clientCacheApplicationAttributes.get("serverGroup")); - setSocketBufferSize((Integer) clientCacheApplicationAttributes.get("socketBufferSize")); - setStatisticsInterval((Integer) clientCacheApplicationAttributes.get("statisticInterval")); - setSubscriptionAckInterval((Integer) clientCacheApplicationAttributes.get("subscriptionAckInterval")); - setSubscriptionEnabled(Boolean.TRUE.equals(clientCacheApplicationAttributes.get("subscriptionEnabled"))); - setSubscriptionMessageTrackingTimeout((Integer) clientCacheApplicationAttributes.get("subscriptionMessageTrackingTimeout")); - setSubscriptionRedundancy((Integer) clientCacheApplicationAttributes.get("subscriptionRedundancy")); - setThreadLocalConnections(Boolean.TRUE.equals(clientCacheApplicationAttributes.get("threadLocalConnections"))); + setDurableClientId(resolveProperty(cacheClientProperty("durable-client-id"), + (String) clientCacheApplicationAttributes.get("durableClientId"))); + + setDurableClientTimeout(resolveProperty(cacheClientProperty("durable-client-timeout"), + (Integer) clientCacheApplicationAttributes.get("durableClientTimeout"))); + + setFreeConnectionTimeout( + resolveProperty(namedPoolProperty("default", "free-connection-timeout"), + resolveProperty(poolProperty("free-connection-timeout"), + (Integer) clientCacheApplicationAttributes.get("freeConnectionTimeout")))); + + setIdleTimeout( + resolveProperty(namedPoolProperty("default", "idle-timeout"), + resolveProperty(poolProperty("idle-timeout"), + (Long) clientCacheApplicationAttributes.get("idleTimeout")))); + + setKeepAlive(resolveProperty(cacheClientProperty("keep-alive"), + Boolean.TRUE.equals(clientCacheApplicationAttributes.get("keepAlive")))); + + setLoadConditioningInterval( + resolveProperty(namedPoolProperty("default","load-conditioning-interval"), + resolveProperty(poolProperty("load-conditioning-interval"), + (Integer) clientCacheApplicationAttributes.get("loadConditioningInterval")))); + + setMaxConnections( + resolveProperty(namedPoolProperty("default", "max-connections"), + resolveProperty(poolProperty("max-connections"), + (Integer) clientCacheApplicationAttributes.get("maxConnections")))); + + setMinConnections( + resolveProperty(namedPoolProperty("default", "min-connections"), + resolveProperty(poolProperty("min-connections"), + (Integer) clientCacheApplicationAttributes.get("minConnections")))); + + setMultiUserAuthentication( + resolveProperty(namedPoolProperty("default", "multi-user-authentication"), + resolveProperty(poolProperty("multi-user-authentication"), + Boolean.TRUE.equals(clientCacheApplicationAttributes.get("multiUserAuthentication"))))); + + setPingInterval( + resolveProperty(namedPoolProperty("default", "ping-interval"), + resolveProperty(poolProperty("ping-interval"), + (Long) clientCacheApplicationAttributes.get("pingInterval")))); + + setPrSingleHopEnabled( + resolveProperty(namedPoolProperty("default", "pr-single-hop-enabled"), + resolveProperty(poolProperty("pr-single-hop-enabled"), + Boolean.TRUE.equals(clientCacheApplicationAttributes.get("prSingleHopEnabled"))))); + + setReadTimeout( + resolveProperty(namedPoolProperty("default", "read-timeout"), + resolveProperty(poolProperty("read-timeout"), + (Integer) clientCacheApplicationAttributes.get("readTimeout")))); + + setReadyForEvents( + resolveProperty(namedPoolProperty("default", "ready-for-events"), + resolveProperty(poolProperty("ready-for-events"), + Boolean.TRUE.equals(clientCacheApplicationAttributes.get("readyForEvents"))))); + + setRetryAttempts( + resolveProperty(namedPoolProperty("default", "retry-attempts"), + resolveProperty(poolProperty("retry-attempts"), + (Integer) clientCacheApplicationAttributes.get("retryAttempts")))); + + setServerGroup( + resolveProperty(namedPoolProperty("default", "server-group"), + resolveProperty(poolProperty("server-group"), + (String) clientCacheApplicationAttributes.get("serverGroup")))); + + setSocketBufferSize( + resolveProperty(namedPoolProperty("default", "socket-buffer-size"), + resolveProperty(poolProperty("socket-buffer-size"), + (Integer) clientCacheApplicationAttributes.get("socketBufferSize")))); + + setStatisticsInterval( + resolveProperty(namedPoolProperty("default", "statistic-interval"), + resolveProperty(poolProperty("statistic-interval"), + (Integer) clientCacheApplicationAttributes.get("statisticInterval")))); + + setSubscriptionAckInterval( + resolveProperty(namedPoolProperty("default", "subscription-ack-interval"), + resolveProperty(poolProperty("subscription-ack-interval"), + (Integer) clientCacheApplicationAttributes.get("subscriptionAckInterval")))); + + setSubscriptionEnabled( + resolveProperty(namedPoolProperty("default", "subscription-enabled"), + resolveProperty(poolProperty("subscription-enabled"), + Boolean.TRUE.equals(clientCacheApplicationAttributes.get("subscriptionEnabled"))))); + + setSubscriptionMessageTrackingTimeout( + resolveProperty(namedPoolProperty("default", "subscription-message-tracking-timeout"), + resolveProperty(poolProperty("subscription-message-tracking-timeout"), + (Integer) clientCacheApplicationAttributes.get("subscriptionMessageTrackingTimeout")))); + + setSubscriptionRedundancy( + resolveProperty(namedPoolProperty("default", "subscription-redundancy"), + resolveProperty(poolProperty("subscription-redundancy"), + (Integer) clientCacheApplicationAttributes.get("subscriptionRedundancy")))); + + setThreadLocalConnections( + resolveProperty(namedPoolProperty("default", "thread-local-connections"), + resolveProperty(poolProperty("thread-local-connections"), + Boolean.TRUE.equals(clientCacheApplicationAttributes.get("threadLocalConnections"))))); configureLocatorsAndServers(clientCacheApplicationAttributes); } @@ -265,22 +352,44 @@ public class ClientCacheConfiguration extends AbstractCacheConfiguration { */ private void configureLocatorsAndServers(Map clientCacheApplicationAttributes) { - ConnectionEndpointList poolLocators = new ConnectionEndpointList(); + ConnectionEndpointList poolLocators; - AnnotationAttributes[] locators = (AnnotationAttributes[]) clientCacheApplicationAttributes.get("locators"); + String locatorsFromProperty = resolveProperty(namedPoolProperty("default", "locators"), + resolveProperty(poolProperty("locators"), (String) null)); - for (AnnotationAttributes locator : locators) { - poolLocators.add(newConnectionEndpoint((String) locator.get("host"), (Integer) locator.get("port"))); + if (StringUtils.hasText(locatorsFromProperty)) { + String[] locatorHostsPorts = locatorsFromProperty.split(","); + poolLocators = ConnectionEndpointList.parse(GemfireUtils.DEFAULT_LOCATOR_PORT, locatorHostsPorts); + } + else { + poolLocators = new ConnectionEndpointList(); + + AnnotationAttributes[] locators = (AnnotationAttributes[]) clientCacheApplicationAttributes.get("locators"); + + for (AnnotationAttributes locator : locators) { + poolLocators.add(newConnectionEndpoint((String) locator.get("host"), (Integer) locator.get("port"))); + } } setPoolLocators(poolLocators); - ConnectionEndpointList poolServers = new ConnectionEndpointList(); + ConnectionEndpointList poolServers; - AnnotationAttributes[] servers = (AnnotationAttributes[]) clientCacheApplicationAttributes.get("servers"); + String serversFromProperty = resolveProperty(namedPoolProperty("default", "servers"), + resolveProperty(poolProperty("servers"), (String) null)); - for (AnnotationAttributes server : servers) { - poolServers.add(newConnectionEndpoint((String) server.get("host"), (Integer) server.get("port"))); + if (StringUtils.hasText(serversFromProperty)) { + String[] serverHostsPorts = serversFromProperty.split(","); + poolServers = ConnectionEndpointList.parse(CacheServer.DEFAULT_PORT, serverHostsPorts); + } + else { + poolServers = new ConnectionEndpointList(); + + AnnotationAttributes[] servers = (AnnotationAttributes[]) clientCacheApplicationAttributes.get("servers"); + + for (AnnotationAttributes server : servers) { + poolServers.add(newConnectionEndpoint((String) server.get("host"), (Integer) server.get("port"))); + } } setPoolServers(poolServers); @@ -304,7 +413,7 @@ public class ClientCacheConfiguration extends AbstractCacheConfiguration { this.durableClientId = durableClientId; } - protected String durableClientId() { + protected String getDurableClientId() { return this.durableClientId; } @@ -313,7 +422,7 @@ public class ClientCacheConfiguration extends AbstractCacheConfiguration { this.durableClientTimeout = durableClientTimeout; } - protected Integer durableClientTimeout() { + protected Integer getDurableClientTimeout() { return this.durableClientTimeout; } @@ -322,7 +431,7 @@ public class ClientCacheConfiguration extends AbstractCacheConfiguration { this.freeConnectionTimeout = freeConnectionTimeout; } - protected Integer freeConnectionTimeout() { + protected Integer getFreeConnectionTimeout() { return this.freeConnectionTimeout; } @@ -331,7 +440,7 @@ public class ClientCacheConfiguration extends AbstractCacheConfiguration { this.idleTimeout = idleTimeout; } - protected Long idleTimeout() { + protected Long getIdleTimeout() { return this.idleTimeout; } @@ -340,7 +449,7 @@ public class ClientCacheConfiguration extends AbstractCacheConfiguration { this.keepAlive = keepAlive; } - protected Boolean keepAlive() { + protected Boolean getKeepAlive() { return this.keepAlive; } @@ -349,7 +458,7 @@ public class ClientCacheConfiguration extends AbstractCacheConfiguration { this.loadConditioningInterval = loadConditioningInterval; } - protected Integer loadConditioningInterval() { + protected Integer getLoadConditioningInterval() { return this.loadConditioningInterval; } @@ -358,7 +467,7 @@ public class ClientCacheConfiguration extends AbstractCacheConfiguration { this.maxConnections = maxConnections; } - protected Integer maxConnections() { + protected Integer getMaxConnections() { return this.maxConnections; } @@ -367,7 +476,7 @@ public class ClientCacheConfiguration extends AbstractCacheConfiguration { this.minConnections = minConnections; } - protected Integer minConnections() { + protected Integer getMinConnections() { return this.minConnections; } @@ -376,7 +485,7 @@ public class ClientCacheConfiguration extends AbstractCacheConfiguration { this.multiUserAuthentication = multiUserAuthentication; } - protected Boolean multiUserAuthentication() { + protected Boolean getMultiUserAuthentication() { return this.multiUserAuthentication; } @@ -385,7 +494,7 @@ public class ClientCacheConfiguration extends AbstractCacheConfiguration { this.pingInterval = pingInterval; } - protected Long pingInterval() { + protected Long getPingInterval() { return this.pingInterval; } @@ -394,7 +503,7 @@ public class ClientCacheConfiguration extends AbstractCacheConfiguration { this.locators = locators; } - protected Iterable poolLocators() { + protected Iterable getPoolLocators() { return this.locators; } @@ -403,7 +512,7 @@ public class ClientCacheConfiguration extends AbstractCacheConfiguration { this.servers = servers; } - protected Iterable poolServers() { + protected Iterable getPoolServers() { return this.servers; } @@ -412,7 +521,7 @@ public class ClientCacheConfiguration extends AbstractCacheConfiguration { this.prSingleHopEnabled = prSingleHopEnabled; } - protected Boolean prSingleHopEnabled() { + protected Boolean getPrSingleHopEnabled() { return this.prSingleHopEnabled; } @@ -421,7 +530,7 @@ public class ClientCacheConfiguration extends AbstractCacheConfiguration { this.readTimeout = readTimeout; } - protected Integer readTimeout() { + protected Integer getReadTimeout() { return this.readTimeout; } @@ -430,7 +539,7 @@ public class ClientCacheConfiguration extends AbstractCacheConfiguration { this.readyForEvents = readyForEvents; } - protected boolean readyForEvents() { + protected boolean getReadyForEvents() { return this.readyForEvents; } @@ -439,7 +548,7 @@ public class ClientCacheConfiguration extends AbstractCacheConfiguration { this.retryAttempts = retryAttempts; } - protected Integer retryAttempts() { + protected Integer getRetryAttempts() { return this.retryAttempts; } @@ -448,7 +557,7 @@ public class ClientCacheConfiguration extends AbstractCacheConfiguration { this.serverGroup = serverGroup; } - protected String serverGroup() { + protected String getServerGroup() { return this.serverGroup; } @@ -457,7 +566,7 @@ public class ClientCacheConfiguration extends AbstractCacheConfiguration { this.socketBufferSize = socketBufferSize; } - protected Integer socketBufferSize() { + protected Integer getSocketBufferSize() { return this.socketBufferSize; } @@ -466,7 +575,7 @@ public class ClientCacheConfiguration extends AbstractCacheConfiguration { this.statisticsInterval = statisticsInterval; } - protected Integer statisticsInterval() { + protected Integer getStatisticsInterval() { return this.statisticsInterval; } @@ -475,7 +584,7 @@ public class ClientCacheConfiguration extends AbstractCacheConfiguration { this.subscriptionAckInterval = subscriptionAckInterval; } - protected Integer subscriptionAckInterval() { + protected Integer getSubscriptionAckInterval() { return this.subscriptionAckInterval; } @@ -484,7 +593,7 @@ public class ClientCacheConfiguration extends AbstractCacheConfiguration { this.subscriptionEnabled = subscriptionEnabled; } - protected Boolean subscriptionEnabled() { + protected Boolean getSubscriptionEnabled() { return this.subscriptionEnabled; } @@ -493,7 +602,7 @@ public class ClientCacheConfiguration extends AbstractCacheConfiguration { this.subscriptionMessageTrackingTimeout = subscriptionMessageTrackingTimeout; } - protected Integer subscriptionMessageTrackingTimeout() { + protected Integer getSubscriptionMessageTrackingTimeout() { return this.subscriptionMessageTrackingTimeout; } @@ -502,7 +611,7 @@ public class ClientCacheConfiguration extends AbstractCacheConfiguration { this.subscriptionRedundancy = subscriptionRedundancy; } - protected Integer subscriptionRedundancy() { + protected Integer getSubscriptionRedundancy() { return this.subscriptionRedundancy; } @@ -511,7 +620,7 @@ public class ClientCacheConfiguration extends AbstractCacheConfiguration { this.threadLocalConnections = threadLocalConnections; } - protected Boolean threadLocalConnections() { + protected Boolean getThreadLocalConnections() { return this.threadLocalConnections; } diff --git a/src/main/java/org/springframework/data/gemfire/config/annotation/DiskStoreConfiguration.java b/src/main/java/org/springframework/data/gemfire/config/annotation/DiskStoreConfiguration.java index db9d2e26..cb41d346 100644 --- a/src/main/java/org/springframework/data/gemfire/config/annotation/DiskStoreConfiguration.java +++ b/src/main/java/org/springframework/data/gemfire/config/annotation/DiskStoreConfiguration.java @@ -17,17 +17,20 @@ package org.springframework.data.gemfire.config.annotation; +import static java.util.Arrays.stream; +import static org.springframework.data.gemfire.util.ArrayUtils.nullSafeArray; import static org.springframework.data.gemfire.util.CollectionUtils.nullSafeMap; import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Optional; +import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Collectors; -import org.springframework.beans.BeansException; -import org.springframework.beans.factory.BeanFactory; -import org.springframework.beans.factory.BeanFactoryAware; +import org.apache.geode.cache.DiskStore; +import org.apache.geode.cache.DiskStoreFactory; import org.springframework.beans.factory.ListableBeanFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.config.BeanDefinition; @@ -38,14 +41,16 @@ import org.springframework.context.annotation.ImportBeanDefinitionRegistrar; import org.springframework.core.annotation.AnnotationAttributes; import org.springframework.core.type.AnnotationMetadata; import org.springframework.data.gemfire.DiskStoreFactoryBean; +import org.springframework.data.gemfire.config.annotation.support.AbstractAnnotationConfigSupport; import org.springframework.data.gemfire.config.xml.GemfireConstants; -import org.springframework.data.gemfire.util.ArrayUtils; +import org.springframework.util.StringUtils; /** * The {@link DiskStoreConfiguration} class is a Spring {@link ImportBeanDefinitionRegistrar} used to register * a GemFire/Geode {@link org.apache.geode.cache.DiskStore} bean definition. * * @author John Blum + * @see org.apache.geode.cache.DiskStore * @see org.springframework.beans.factory.config.BeanDefinition * @see org.springframework.beans.factory.support.BeanDefinitionBuilder * @see org.springframework.beans.factory.support.BeanDefinitionRegistry @@ -54,34 +59,61 @@ import org.springframework.data.gemfire.util.ArrayUtils; * @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 + * @see org.springframework.data.gemfire.config.annotation.support.AbstractAnnotationConfigSupport * @since 1.9.0 */ -public class DiskStoreConfiguration implements BeanFactoryAware, ImportBeanDefinitionRegistrar { +public class DiskStoreConfiguration extends AbstractAnnotationConfigSupport + implements ImportBeanDefinitionRegistrar { - private BeanFactory beanFactory; + protected static final boolean DEFAULT_ALLOW_FORCE_COMPACTION = DiskStoreFactory.DEFAULT_ALLOW_FORCE_COMPACTION; + protected static final boolean DEFAULT_AUTO_COMPACT = DiskStoreFactory.DEFAULT_AUTO_COMPACT; + + protected static final float DEFAULT_DISK_USAGE_CRITICAL_PERCENTAGE = + DiskStoreFactory.DEFAULT_DISK_USAGE_CRITICAL_PERCENTAGE; + + protected static final float DEFAULT_DISK_USAGE_WARNING_PERCENTAGE = + DiskStoreFactory.DEFAULT_DISK_USAGE_WARNING_PERCENTAGE; + + protected static final int DEFAULT_COMPACTION_THRESHOLD = DiskStoreFactory.DEFAULT_COMPACTION_THRESHOLD; + protected static final int DEFAULT_QUEUE_SIZE = DiskStoreFactory.DEFAULT_QUEUE_SIZE; + protected static final int DEFAULT_WRITE_BUFFER_SIZE = DiskStoreFactory.DEFAULT_WRITE_BUFFER_SIZE; + + protected static final long DEFAULT_MAX_OPLOG_SIZE = 1024L; + protected static final long DEFAULT_TIME_INTERVAL = DiskStoreFactory.DEFAULT_TIME_INTERVAL; @Autowired(required = false) private List diskStoreConfigurers = Collections.emptyList(); + /** + * Returns the {@link DiskStore} {@link java.lang.annotation.Annotation} type specified in configuration. + * + * @return the {@link DiskStore} {@link java.lang.annotation.Annotation} type specified in configuration. + * @see org.springframework.data.gemfire.config.annotation.EnableDiskStores + * @see org.springframework.data.gemfire.config.annotation.EnableDiskStore + */ + @Override + protected Class getAnnotationType() { + return EnableDiskStore.class; + } + /** * @inheritDoc */ @Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { - if (importingClassMetadata.hasAnnotation(EnableDiskStore.class.getName())) { + if (importingClassMetadata.hasAnnotation(getAnnotationTypeName())) { - AnnotationAttributes enableDiskStoreAttributes = AnnotationAttributes.fromMap( - importingClassMetadata.getAnnotationAttributes(EnableDiskStore.class.getName())); + AnnotationAttributes enableDiskStoreAttributes = + AnnotationAttributes.fromMap(importingClassMetadata.getAnnotationAttributes(getAnnotationTypeName())); - registerDiskStoreBeanDefinition(importingClassMetadata, enableDiskStoreAttributes, registry); + registerDiskStoreBeanDefinition(enableDiskStoreAttributes, registry); } } /* (non-Javadoc) */ - protected void registerDiskStoreBeanDefinition(AnnotationMetadata importingClassMetadata, - AnnotationAttributes enableDiskStoreAttributes, BeanDefinitionRegistry registry) { + protected void registerDiskStoreBeanDefinition(AnnotationAttributes enableDiskStoreAttributes, + BeanDefinitionRegistry registry) { BeanDefinitionBuilder diskStoreFactoryBeanBuilder = BeanDefinitionBuilder.genericBeanDefinition(DiskStoreFactoryBean.class); @@ -95,33 +127,80 @@ public class DiskStoreConfiguration implements BeanFactoryAware, ImportBeanDefin diskStoreFactoryBeanBuilder.addPropertyValue("diskStoreConfigurers", resolveDiskStoreConfigurers()); setPropertyValueIfNotDefault(diskStoreFactoryBeanBuilder, "allowForceCompaction", - enableDiskStoreAttributes.getBoolean("allowForceCompaction"), false); + enableDiskStoreAttributes.getBoolean("allowForceCompaction"), DEFAULT_ALLOW_FORCE_COMPACTION); + + Optional.ofNullable(resolveProperty(namedDiskStoreProperty(diskStoreName, "allow-force-compaction"), + resolveProperty(diskStoreProperty("allow-force-compaction"), (Boolean) null))) + .ifPresent(allowForceCompaction -> + diskStoreFactoryBeanBuilder.addPropertyValue("allowForceCompaction", allowForceCompaction)); setPropertyValueIfNotDefault(diskStoreFactoryBeanBuilder, "autoCompact", - enableDiskStoreAttributes.getBoolean("autoCompact"), false); + enableDiskStoreAttributes.getBoolean("autoCompact"), DEFAULT_AUTO_COMPACT); + + Optional.ofNullable(resolveProperty(namedDiskStoreProperty(diskStoreName, "auto-compact"), + resolveProperty(diskStoreProperty("auto-compact"), (Boolean) null))) + .ifPresent(autoCompact -> diskStoreFactoryBeanBuilder.addPropertyValue("autoCompact", autoCompact)); setPropertyValueIfNotDefault(diskStoreFactoryBeanBuilder, "compactionThreshold", - enableDiskStoreAttributes.getNumber("compactionThreshold"), 50); + enableDiskStoreAttributes.getNumber("compactionThreshold"), + DEFAULT_COMPACTION_THRESHOLD); + + Optional.ofNullable(resolveProperty(namedDiskStoreProperty(diskStoreName, "compaction-threshold"), + resolveProperty(diskStoreProperty("compaction-threshold"), (Integer) null))) + .ifPresent(compactionThreshold -> + diskStoreFactoryBeanBuilder.addPropertyValue("compactionThreshold", compactionThreshold)); setPropertyValueIfNotDefault(diskStoreFactoryBeanBuilder, "diskUsageCriticalPercentage", - enableDiskStoreAttributes.getNumber("diskUsageCriticalPercentage"), 99.0f); + enableDiskStoreAttributes.getNumber("diskUsageCriticalPercentage"), + DEFAULT_DISK_USAGE_CRITICAL_PERCENTAGE); + + Optional.ofNullable(resolveProperty(namedDiskStoreProperty(diskStoreName, "disk-usage-critical-percentage"), + resolveProperty(diskStoreProperty("disk-usage-critical-percentage"), (Float) null))) + .ifPresent(diskUsageCriticalPercentage -> + diskStoreFactoryBeanBuilder.addPropertyValue("diskUsageCriticalPercentage", diskUsageCriticalPercentage)); setPropertyValueIfNotDefault(diskStoreFactoryBeanBuilder, "diskUsageWarningPercentage", - enableDiskStoreAttributes.getNumber("diskUsageWarningPercentage"), 90.0f); + enableDiskStoreAttributes.getNumber("diskUsageWarningPercentage"), + DEFAULT_DISK_USAGE_WARNING_PERCENTAGE); + + Optional.ofNullable(resolveProperty(namedDiskStoreProperty(diskStoreName, "disk-usage-warning-percentage"), + resolveProperty(diskStoreProperty("disk-usage-warning-percentage"), (Float) null))) + .ifPresent(diskUsageWarningPercentage -> + diskStoreFactoryBeanBuilder.addPropertyValue("diskUsageWarningPercentage", diskUsageWarningPercentage)); setPropertyValueIfNotDefault(diskStoreFactoryBeanBuilder, "maxOplogSize", - enableDiskStoreAttributes.getNumber("maxOplogSize"), 1024L); + enableDiskStoreAttributes.getNumber("maxOplogSize"), DEFAULT_MAX_OPLOG_SIZE); + + Optional.ofNullable(resolveProperty(namedDiskStoreProperty(diskStoreName, "max-oplog-size"), + resolveProperty(diskStoreProperty("max-oplog-size"), (Long) null))) + .ifPresent(maxOplogSize -> + diskStoreFactoryBeanBuilder.addPropertyValue("maxOplogSize", maxOplogSize)); setPropertyValueIfNotDefault(diskStoreFactoryBeanBuilder, "queueSize", - enableDiskStoreAttributes.getNumber("queueSize"), 0); + enableDiskStoreAttributes.getNumber("queueSize"), DEFAULT_QUEUE_SIZE); + + Optional.ofNullable(resolveProperty(namedDiskStoreProperty(diskStoreName, "queue-size"), + resolveProperty(diskStoreProperty("queue-size"), (Integer) null))) + .ifPresent(queueSize -> + diskStoreFactoryBeanBuilder.addPropertyValue("queueSize", queueSize)); setPropertyValueIfNotDefault(diskStoreFactoryBeanBuilder, "timeInterval", - enableDiskStoreAttributes.getNumber("timeInterval"), 1000L); + enableDiskStoreAttributes.getNumber("timeInterval"), DEFAULT_TIME_INTERVAL); + + Optional.ofNullable(resolveProperty(namedDiskStoreProperty(diskStoreName, "time-interval"), + resolveProperty(diskStoreProperty("time-interval"), (Long) null))) + .ifPresent(timeInterval -> + diskStoreFactoryBeanBuilder.addPropertyValue("timeInterval", timeInterval)); setPropertyValueIfNotDefault(diskStoreFactoryBeanBuilder, "writeBufferSize", - enableDiskStoreAttributes.getNumber("writeBufferSize"), 32768); + enableDiskStoreAttributes.getNumber("writeBufferSize"), DEFAULT_WRITE_BUFFER_SIZE); - parseDiskStoreDiskDirectories(importingClassMetadata, enableDiskStoreAttributes, diskStoreFactoryBeanBuilder); + Optional.ofNullable(resolveProperty(namedDiskStoreProperty(diskStoreName, "write-buffer-size"), + resolveProperty(diskStoreProperty("write-buffer-size"), (Integer) null))) + .ifPresent(writeBufferSize -> + diskStoreFactoryBeanBuilder.addPropertyValue("writeBufferSize", writeBufferSize)); + + resolveDiskStoreDirectories(diskStoreName, enableDiskStoreAttributes, diskStoreFactoryBeanBuilder); registry.registerBeanDefinition(diskStoreName, diskStoreFactoryBeanBuilder.getBeanDefinition()); } @@ -132,42 +211,143 @@ public class DiskStoreConfiguration implements BeanFactoryAware, ImportBeanDefin return Optional.ofNullable(this.diskStoreConfigurers) .filter(diskStoreConfigurers -> !diskStoreConfigurers.isEmpty()) .orElseGet(() -> - Optional.of(this.beanFactory) + Optional.of(this.beanFactory()) .filter(beanFactory -> beanFactory instanceof ListableBeanFactory) .map(beanFactory -> { + Map 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) { + protected BeanDefinitionBuilder resolveDiskStoreDirectories(String diskStoreName, + AnnotationAttributes enableDiskStoreAttributes, BeanDefinitionBuilder diskStoreFactoryBeanBuilder) { - AnnotationAttributes[] diskDirectories = ArrayUtils.nullSafeArray( - enableDiskStoreAttributes.getAnnotationArray("diskDirectories"), AnnotationAttributes.class); + ManagedList diskStoreDirectoryBeans = new ManagedList<>(); - ManagedList diskDirectoryBeans = new ManagedList(diskDirectories.length); + String diskStoreDirectoryLocation = + resolveProperty(diskStoreProperty("directory.location"), String.class); - for (AnnotationAttributes diskDirectoryAttributes : diskDirectories) { - BeanDefinitionBuilder diskDirectoryBuilder = - BeanDefinitionBuilder.genericBeanDefinition(DiskStoreFactoryBean.DiskDir.class); + String namedDiskStoreDirectoryLocation = + resolveProperty(namedDiskStoreProperty(diskStoreName, "directory.location"), String.class); - diskDirectoryBuilder.addConstructorArgValue(diskDirectoryAttributes.getString("location")); - diskDirectoryBuilder.addConstructorArgValue(diskDirectoryAttributes.getNumber("maxSize")); + Integer diskStoreDirectorySize = + resolveProperty(diskStoreProperty("directory.size"), Integer.class); - diskDirectoryBeans.add(diskDirectoryBuilder.getBeanDefinition()); + Integer namedDiskStoreDirectorySize = + resolveProperty(namedDiskStoreProperty(diskStoreName, "directory.size"), Integer.class); + + List namedDiskStoreDirectoryLocationProperties = arrayOfPropertyNamesFor( + namedDiskStoreProperty(diskStoreName, "directory"), "location"); + + if (!namedDiskStoreDirectoryLocationProperties.isEmpty()) { + + AtomicInteger index = new AtomicInteger(0); + + namedDiskStoreDirectoryLocationProperties.forEach(property -> { + + String location = requireProperty(property, String.class); + + Integer maxSize = resolveProperty(asArrayProperty( + namedDiskStoreProperty(diskStoreName, "directory"), index.getAndIncrement(), + "size"), Integer.class); + + maxSize = resolveDiskStoreDirectorySize(maxSize, namedDiskStoreDirectorySize, diskStoreDirectorySize); + + diskStoreDirectoryBeans.add(newDiskStoreDirectoryBean(location, maxSize)); + }); + } + else if (Optional.ofNullable(namedDiskStoreDirectoryLocation).filter(StringUtils::hasText).isPresent()) { + diskStoreDirectoryBeans.add(newDiskStoreDirectoryBean(namedDiskStoreDirectoryLocation, + resolveDiskStoreDirectorySize(namedDiskStoreDirectorySize, diskStoreDirectorySize))); + } + else { + List diskStoreDirectoryLocationProperties = + arrayOfPropertyNamesFor(diskStoreProperty("directory"), "location"); + + if (!diskStoreDirectoryLocationProperties.isEmpty()) { + + AtomicInteger index = new AtomicInteger(0); + + diskStoreDirectoryLocationProperties.forEach(property -> { + + String location = requireProperty(property, String.class); + + Integer maxSize = resolveProperty(asArrayProperty(diskStoreProperty("directory"), + index.getAndIncrement(), "size"), Integer.class); + + maxSize = resolveDiskStoreDirectorySize(namedDiskStoreDirectorySize, maxSize, + diskStoreDirectorySize); + + diskStoreDirectoryBeans.add(newDiskStoreDirectoryBean(location, maxSize)); + }); + } + else if (Optional.ofNullable(diskStoreDirectoryLocation).filter(StringUtils::hasText).isPresent()) { + diskStoreDirectoryBeans.add(newDiskStoreDirectoryBean(diskStoreDirectoryLocation, + resolveDiskStoreDirectorySize(namedDiskStoreDirectorySize, diskStoreDirectorySize))); + } + else { + diskStoreDirectoryBeans.addAll(parseDiskStoreDirectories(enableDiskStoreAttributes)); + } } - if (!diskDirectoryBeans.isEmpty()) { - diskStoreBeanFactoryBuilder.addPropertyValue("diskDirs", diskDirectoryBeans); - } + Optional.of(diskStoreDirectoryBeans) + .filter(beans -> !beans.isEmpty()) + .ifPresent(beans -> diskStoreFactoryBeanBuilder.addPropertyValue("diskDirs", diskStoreDirectoryBeans)); - return diskStoreBeanFactoryBuilder; + return diskStoreFactoryBeanBuilder; + } + + /* (non-Javadoc) */ + @SuppressWarnings("unused") + private String resolveDiskStoreDirectoryLocation(String... locations) { + + return stream(nullSafeArray(locations, String.class)) + .filter(StringUtils::hasText) + .findFirst() + .orElse("."); + } + + /* (non-Javadoc) */ + private Integer resolveDiskStoreDirectorySize(Integer... sizes) { + + return stream(nullSafeArray(sizes, Integer.class)) + .filter(Objects::nonNull) + .findFirst() + .orElse(Integer.MAX_VALUE); + } + + /* (non-Javadoc) */ + protected ManagedList parseDiskStoreDirectories(AnnotationAttributes enableDiskStoreAttributes) { + + AnnotationAttributes[] diskDirectories = + enableDiskStoreAttributes.getAnnotationArray("diskDirectories"); + + ManagedList diskDirectoryBeans = new ManagedList<>(diskDirectories.length); + + stream(nullSafeArray(diskDirectories, AnnotationAttributes.class)).forEach(diskDirectoryAttributes -> + diskDirectoryBeans.add(newDiskStoreDirectoryBean(diskDirectoryAttributes.getString("location"), + diskDirectoryAttributes.getNumber("maxSize")))); + + return diskDirectoryBeans; + } + + /* (non-Javadoc) */ + private BeanDefinition newDiskStoreDirectoryBean(String location, Integer maxSize) { + + BeanDefinitionBuilder diskDirectoryBuilder = + BeanDefinitionBuilder.genericBeanDefinition(DiskStoreFactoryBean.DiskDir.class); + + diskDirectoryBuilder.addConstructorArgValue(location); + diskDirectoryBuilder.addConstructorArgValue(maxSize); + + return diskDirectoryBuilder.getBeanDefinition(); } /* (non-Javadoc) */ @@ -177,9 +357,4 @@ public class DiskStoreConfiguration implements BeanFactoryAware, ImportBeanDefin return (value != null && !value.equals(defaultValue) ? beanDefinitionBuilder.addPropertyValue(propertyName, value) : beanDefinitionBuilder); } - - @Override - public void setBeanFactory(BeanFactory beanFactory) throws BeansException { - this.beanFactory = beanFactory; - } } diff --git a/src/main/java/org/springframework/data/gemfire/config/annotation/DiskStoresConfiguration.java b/src/main/java/org/springframework/data/gemfire/config/annotation/DiskStoresConfiguration.java index 4a4e2e04..6e80b215 100644 --- a/src/main/java/org/springframework/data/gemfire/config/annotation/DiskStoresConfiguration.java +++ b/src/main/java/org/springframework/data/gemfire/config/annotation/DiskStoresConfiguration.java @@ -17,10 +17,12 @@ package org.springframework.data.gemfire.config.annotation; +import static java.util.Arrays.stream; +import static org.springframework.data.gemfire.util.ArrayUtils.nullSafeArray; + import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.core.annotation.AnnotationAttributes; import org.springframework.core.type.AnnotationMetadata; -import org.springframework.data.gemfire.util.ArrayUtils; /** * The {@link DiskStoresConfiguration} class is a Spring {@link org.springframework.context.annotation.ImportBeanDefinitionRegistrar} @@ -36,22 +38,21 @@ import org.springframework.data.gemfire.util.ArrayUtils; */ public class DiskStoresConfiguration extends DiskStoreConfiguration { - /** - * @inheritDoc - */ + /* (non-Javadoc) */ @Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { + if (importingClassMetadata.hasAnnotation(EnableDiskStores.class.getName())) { + AnnotationAttributes enableDiskStoresAttributes = AnnotationAttributes.fromMap( importingClassMetadata.getAnnotationAttributes(EnableDiskStores.class.getName())); - AnnotationAttributes[] diskStores = ArrayUtils.nullSafeArray( - enableDiskStoresAttributes.getAnnotationArray("diskStores"), AnnotationAttributes.class); + AnnotationAttributes[] diskStores = + enableDiskStoresAttributes.getAnnotationArray("diskStores"); - for (AnnotationAttributes diskStoreAttributes : diskStores) { - registerDiskStoreBeanDefinition(importingClassMetadata, - mergeDiskStoreAttributes(enableDiskStoresAttributes, diskStoreAttributes), registry); - } + stream(nullSafeArray(diskStores, AnnotationAttributes.class)).forEach(diskStoreAttributes -> + registerDiskStoreBeanDefinition( + mergeDiskStoreAttributes(enableDiskStoresAttributes, diskStoreAttributes), registry)); } } diff --git a/src/main/java/org/springframework/data/gemfire/config/annotation/EnableAuth.java b/src/main/java/org/springframework/data/gemfire/config/annotation/EnableAuth.java index 3e127222..e3007673 100644 --- a/src/main/java/org/springframework/data/gemfire/config/annotation/EnableAuth.java +++ b/src/main/java/org/springframework/data/gemfire/config/annotation/EnableAuth.java @@ -27,13 +27,15 @@ import java.lang.annotation.Target; import org.apache.geode.security.AccessControl; import org.apache.geode.security.AuthInitialize; import org.apache.geode.security.Authenticator; +import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; /** - * The EnableAuth annotation marks a Spring {@link org.springframework.context.annotation.Configuration @Configuration} - * annotated class to configure and enable GemFire/Geode's Authentication and Authorization framework services. + * The {@link EnableAuth} annotation marks a Spring {@link Configuration @Configuration} annotated {@link Class} + * to configure and enable Pivotal GemFire/Apache Geode's Authentication and Authorization framework and services. * * @author John Blum + * @see java.lang.annotation.Annotation * @see org.apache.geode.security.AccessControl * @see org.apache.geode.security.AuthInitialize * @see org.apache.geode.security.Authenticator @@ -57,6 +59,8 @@ public @interface EnableAuth { * in the pre-operation phase, which is when the request for the operation is received from the client. * * Defaults to unset. + * + * Use the {@literal spring.data.gemfire.security.client.accessor} property in {@literal application.properties}. */ String clientAccessor() default ""; @@ -67,8 +71,11 @@ public @interface EnableAuth { * through the notification channel. * * Defaults to unset. + * + * Use the {@literal spring.data.gemfire.security.client.accessor-post-processor} property + * in {@literal application.properties}. */ - String clientAccessPostOperation() default ""; + String clientAccessorPostProcessor() default ""; /** * Used for authentication. Static creation method returning an {@link AuthInitialize} object, @@ -77,6 +84,9 @@ public @interface EnableAuth { * on the clients. * * Defaults to unset. + * + * Use the {@literal spring.data.gemfire.security.client.authentication-initializer} property + * in {@literal application.properties}. */ String clientAuthenticationInitializer() default ""; @@ -85,6 +95,9 @@ public @interface EnableAuth { * which is used by a server to verify the credentials of the connecting client. * * Defaults to unset. + * + * Use the {@literal spring.data.gemfire.security.client.authenticator} property + * in {@literal application.properties}. */ String clientAuthenticator() default ""; @@ -95,6 +108,9 @@ public @interface EnableAuth { * supported by the JDK. * * Defaults to unset. + * + * Use the {@literal spring.data.gemfire.security.client.diffie-hellman-algorithm} property + * in {@literal application.properties}. */ String clientDiffieHellmanAlgorithm() default ""; @@ -104,6 +120,9 @@ public @interface EnableAuth { * {@link Authenticator} specified through the {@literal security-peer-authenticator} property on the peers. * * Defaults to unset. + * + * Use the {@literal spring.data.gemfire.security.peer.authentication-initializer} property + * in {@literal application.properties}. */ String peerAuthenticationInitializer() default ""; @@ -112,6 +131,8 @@ public @interface EnableAuth { * by a peer to verify the credentials of the connecting peer. * * Defaults to unset. + * + * Use the {@literal spring.data.gemfire.security.peer.authenticator} property in {@literal application.properties}. */ String peerAuthenticator() default ""; @@ -120,6 +141,9 @@ public @interface EnableAuth { * authenticated peer requesting a secure connection. * * Defaults to {@literal 1000} milliseconds. + * + * Use the {@literal spring.data.gemfire.security.peer.verify-member-timeout} property + * in {@literal application.properties}. */ long peerVerifyMemberTimeout() default AuthConfiguration.DEFAULT_PEER_VERIFY_MEMBER_TIMEOUT; @@ -128,6 +152,8 @@ public @interface EnableAuth { * regular log file is used. * * Defaults to unset. + * + * Use the {@literal spring.data.gemfire.security.log.file} property in {@literal application.properties}. */ String securityLogFile() default ""; @@ -138,6 +164,8 @@ public @interface EnableAuth { * {@literal error}, {@literal severe}, and {@literal none}. * * Defaults to {@literal config}. + * + * Use the {@literal spring.data.gemfire.security.log.level} property in {@literal application.properties}. */ String securityLogLevel() default AuthConfiguration.DEFAULT_SECURITY_LOG_LEVEL; @@ -152,6 +180,8 @@ public @interface EnableAuth { * or write access for your {@literal gemfire.properties} file. * * Defaults to unset. + * + * Use the {@literal spring.data.gemfire.security.properties-file} property in {@literal application.properties}. */ String securityPropertiesFile() default ""; diff --git a/src/main/java/org/springframework/data/gemfire/config/annotation/EnableAutoRegionLookup.java b/src/main/java/org/springframework/data/gemfire/config/annotation/EnableAutoRegionLookup.java index 627590b2..5153cb03 100644 --- a/src/main/java/org/springframework/data/gemfire/config/annotation/EnableAutoRegionLookup.java +++ b/src/main/java/org/springframework/data/gemfire/config/annotation/EnableAutoRegionLookup.java @@ -36,6 +36,7 @@ import org.springframework.context.annotation.Import; * expression or a Spring property placeholder. * * @author John Blum + * @see org.springframework.data.gemfire.RegionFactoryBean#setLookupEnabled(Boolean) * @see org.springframework.data.gemfire.config.annotation.AutoRegionLookupConfiguration * @since 1.9.0 */ @@ -48,13 +49,13 @@ import org.springframework.context.annotation.Import; public @interface EnableAutoRegionLookup { /** - * Attribute to indicate whether auto {@link org.apache.geode.cache.Region} lookup should be enabled; + * Attribute indicating whether auto {@link org.apache.geode.cache.Region} lookup should be enabled; + * * Defaults to {@literal true}. * - * This attribute accepts either a SpEL or Spring property placeholder expression so that - * auto {@link org.apache.geode.cache.Region} lookup behavior can be determined - * at application configuration time. + * Use the {@literal spring.data.gemfire.enable-auto-region-lookup} in {@literal application.properties} + * to dynamically customize this configuration setting. */ - String enabled() default "true"; + boolean enabled() default true; } diff --git a/src/main/java/org/springframework/data/gemfire/config/annotation/EnableCacheServer.java b/src/main/java/org/springframework/data/gemfire/config/annotation/EnableCacheServer.java index e80aeb17..be9cc95a 100644 --- a/src/main/java/org/springframework/data/gemfire/config/annotation/EnableCacheServer.java +++ b/src/main/java/org/springframework/data/gemfire/config/annotation/EnableCacheServer.java @@ -58,14 +58,22 @@ public @interface EnableCacheServer { /** * Configures whether the {@link CacheServer} should start automatically at runtime. * - * Default is {@literal true). + * Defaults to {@literal true). + * + * Use either the {@literal spring.data.gemfire.cache.server..auto-startup} property + * or the {@literal spring.data.gemfire.cache.server.auto-startup} property + * in {@literal application.properties}. */ boolean autoStartup() default true; /** * Configures the ip address or host name that this cache server will listen on. * - * @see org.apache.geode.cache.server.CacheServer#DEFAULT_BIND_ADDRESS + * Defaults to {@link CacheServer#DEFAULT_BIND_ADDRESS}. + * + * Use either the {@literal spring.data.gemfire.cache.server..bind-address} property + * or the {@literal spring.data.gemfire.cache.server.bind-address} property + * in {@literal application.properties}. */ String bindAddress() default CacheServer.DEFAULT_BIND_ADDRESS; @@ -73,82 +81,131 @@ public @interface EnableCacheServer { * Configures the ip address or host name that server locators will tell clients that this cache server * is listening on. * - * @see org.apache.geode.cache.server.CacheServer#DEFAULT_HOSTNAME_FOR_CLIENTS + * Defaults to {@link CacheServer#DEFAULT_HOSTNAME_FOR_CLIENTS}. + * + * Use either the {@literal spring.data.gemfire.cache.server..hostname-for-clients} property + * or the {@literal spring.data.gemfire.cache.server.hostname-for-clients} property + * in {@literal application.properties}. */ String hostnameForClients() default CacheServer.DEFAULT_HOSTNAME_FOR_CLIENTS; /** * Configures the frequency in milliseconds to poll the load probe on this cache server. * - * @see org.apache.geode.cache.server.CacheServer#DEFAULT_LOAD_POLL_INTERVAL + * Defaults to {@link CacheServer#DEFAULT_LOAD_POLL_INTERVAL}. + * + * Use either the {@literal spring.data.gemfire.cache.server..load-poll-interval} property + * or the {@literal spring.data.gemfire.cache.server.load-poll-interval} property + * in {@literal application.properties}. */ long loadPollInterval() default CacheServer.DEFAULT_LOAD_POLL_INTERVAL; /** * Configures the maximum allowed client connections. * - * @see org.apache.geode.cache.server.CacheServer#DEFAULT_MAX_CONNECTIONS + * Defaults to {@link CacheServer#DEFAULT_MAX_CONNECTIONS}. + * + * Use either the {@literal spring.data.gemfire.cache.server..max-connections} property + * or the {@literal spring.data.gemfire.cache.server.max-connections} property + * in {@literal application.properties}. */ int maxConnections() default CacheServer.DEFAULT_MAX_CONNECTIONS; /** * Configures he maximum number of messages that can be enqueued in a client-queue. * - * @see org.apache.geode.cache.server.CacheServer#DEFAULT_MAXIMUM_MESSAGE_COUNT + * Defaults to {@link CacheServer#DEFAULT_MAXIMUM_MESSAGE_COUNT}. + * + * Use either the {@literal spring.data.gemfire.cache.server..max-message-count} property + * or the {@literal spring.data.gemfire.cache.server.max-message-count} property + * in {@literal application.properties}. */ int maxMessageCount() default CacheServer.DEFAULT_MAXIMUM_MESSAGE_COUNT; /** * Configures the maximum number of threads allowed in this cache server to service client requests. * - * @see org.apache.geode.cache.server.CacheServer#DEFAULT_MAX_THREADS + * Defaults to {@link CacheServer#DEFAULT_MAX_THREADS}. + * + * Use either the {@literal spring.data.gemfire.cache.server..max-threads} property + * or the {@literal spring.data.gemfire.cache.server.max-threads} property + * in {@literal application.properties}. */ int maxThreads() default CacheServer.DEFAULT_MAX_THREADS; /** * Configures the maximum amount of time between client pings. * - * @see org.apache.geode.cache.server.CacheServer#DEFAULT_MAXIMUM_TIME_BETWEEN_PINGS + * Defaults to {@link CacheServer#DEFAULT_MAXIMUM_TIME_BETWEEN_PINGS}. + * + * Use either the {@literal spring.data.gemfire.cache.server..max-time-between-pings} property + * or the {@literal spring.data.gemfire.cache.server.max-time-between-pings} property + * in {@literal application.properties}. */ int maxTimeBetweenPings() default CacheServer.DEFAULT_MAXIMUM_TIME_BETWEEN_PINGS; /** * Configures the time (in seconds ) after which a message in the client queue will expire. * - * @see org.apache.geode.cache.server.CacheServer#DEFAULT_MESSAGE_TIME_TO_LIVE + * Defaults to {@link CacheServer#DEFAULT_MESSAGE_TIME_TO_LIVE}. + * + * Use either the {@literal spring.data.gemfire.cache.server..message-time-to-live} property + * or the {@literal spring.data.gemfire.cache.server.message-time-to-live} property + * in {@literal application.properties}. */ int messageTimeToLive() default CacheServer.DEFAULT_MESSAGE_TIME_TO_LIVE; /** - * Configures the name of the Spring bean defined in the Spring application context. + * Configures the {@link String name} of the Spring bean defined in the Spring application context. * * Defaults to empty. + * + * This attribute is also used to resolve named {@link CacheServer} properties + * from {@literal application.properties} specific to the configuration of this {@link CacheServer} definition, + * therefore, this attribute must be specified when external configuration (e.g. {@literal application.properties}) + * is used. */ String name() default ""; /** * Configures the port on which this cache server listens for clients. * - * @see org.apache.geode.cache.server.CacheServer#DEFAULT_PORT + * Defaults to {@link CacheServer#DEFAULT_PORT}. + * + * Use either the {@literal spring.data.gemfire.cache.server..port} property + * or the {@literal spring.data.gemfire.cache.server.port} property + * in {@literal application.properties}. */ int port() default CacheServer.DEFAULT_PORT; /** * Configures the configured buffer size of the socket connection for this CacheServer. * - * @see org.apache.geode.cache.server.CacheServer#DEFAULT_SOCKET_BUFFER_SIZE + * Defaults to {@link CacheServer#DEFAULT_SOCKET_BUFFER_SIZE}. + * + * Use either the {@literal spring.data.gemfire.cache.server..socket-buffer-size} property + * or the {@literal spring.data.gemfire.cache.server.socket-buffer-size} property + * in {@literal application.properties}. */ int socketBufferSize() default CacheServer.DEFAULT_SOCKET_BUFFER_SIZE; /** * Configures the capacity of the client queue. * - * @see org.apache.geode.cache.server.ClientSubscriptionConfig#DEFAULT_CAPACITY + * Defaults to {@link ClientSubscriptionConfig#DEFAULT_CAPACITY}. + * + * Use either the {@literal spring.data.gemfire.cache.server..subscription-capacity} property + * or the {@literal spring.data.gemfire.cache.server.subscription-capacity} property + * in {@literal application.properties}. */ int subscriptionCapacity() default ClientSubscriptionConfig.DEFAULT_CAPACITY; /** * Configures the disk store name for overflow. + * + * Use either the {@literal spring.data.gemfire.cache.server..subscription-disk-store-name} property + * or the {@literal spring.data.gemfire.cache.server.subscription-disk-store-name} property + * in {@literal application.properties}. */ String subscriptionDiskStoreName() default ""; @@ -156,7 +213,22 @@ public @interface EnableCacheServer { * Configures the eviction policy that is executed when capacity of the client queue is reached. * * Defaults to {@link SubscriptionEvictionPolicy#NONE}. + * + * Use either the {@literal spring.data.gemfire.cache.server..subscription-eviction-policy} property + * or the {@literal spring.data.gemfire.cache.server.subscription-eviction-policy} property + * in {@literal application.properties}. */ SubscriptionEvictionPolicy subscriptionEvictionPolicy() default SubscriptionEvictionPolicy.NONE; + /** + * Configures the tcpNoDelay setting of sockets used to send messages to clients. + * + * TcpNoDelay is enabled by default. + * + * Use either the {@literal spring.data.gemfire.cache.server..tcp-no-delay} property + * or the {@literal spring.data.gemfire.cache.server.tcp-no-delay} property + * in {@literal application.properties}. + */ + boolean tcpNoDelay() default CacheServer.DEFAULT_TCP_NO_DELAY; + } diff --git a/src/main/java/org/springframework/data/gemfire/config/annotation/EnableDiskStore.java b/src/main/java/org/springframework/data/gemfire/config/annotation/EnableDiskStore.java index b88378c0..d63fe853 100644 --- a/src/main/java/org/springframework/data/gemfire/config/annotation/EnableDiskStore.java +++ b/src/main/java/org/springframework/data/gemfire/config/annotation/EnableDiskStore.java @@ -17,6 +17,16 @@ package org.springframework.data.gemfire.config.annotation; +import static org.springframework.data.gemfire.config.annotation.DiskStoreConfiguration.DEFAULT_ALLOW_FORCE_COMPACTION; +import static org.springframework.data.gemfire.config.annotation.DiskStoreConfiguration.DEFAULT_AUTO_COMPACT; +import static org.springframework.data.gemfire.config.annotation.DiskStoreConfiguration.DEFAULT_COMPACTION_THRESHOLD; +import static org.springframework.data.gemfire.config.annotation.DiskStoreConfiguration.DEFAULT_DISK_USAGE_CRITICAL_PERCENTAGE; +import static org.springframework.data.gemfire.config.annotation.DiskStoreConfiguration.DEFAULT_DISK_USAGE_WARNING_PERCENTAGE; +import static org.springframework.data.gemfire.config.annotation.DiskStoreConfiguration.DEFAULT_MAX_OPLOG_SIZE; +import static org.springframework.data.gemfire.config.annotation.DiskStoreConfiguration.DEFAULT_QUEUE_SIZE; +import static org.springframework.data.gemfire.config.annotation.DiskStoreConfiguration.DEFAULT_TIME_INTERVAL; +import static org.springframework.data.gemfire.config.annotation.DiskStoreConfiguration.DEFAULT_WRITE_BUFFER_SIZE; + import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Inherited; @@ -24,14 +34,15 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +import org.apache.geode.cache.DiskStore; +import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; import org.springframework.core.annotation.AliasFor; /** - * The {@link EnableDiskStore} annotation marks a Spring {@link org.springframework.context.annotation.Configuration @Configuration} - * annotated application class to configure a single GemFire/Geode {@link org.apache.geode.cache.DiskStore} bean - * in the Spring context in which to persist or overflow data from 1 or more GemFire/Geode - * {@link org.apache.geode.cache.Region Regions} + * The {@link EnableDiskStore} annotation marks a Spring {@link Configuration @Configuration} annotated {@link Class} + * to configure a single GemFire/Geode {@link org.apache.geode.cache.DiskStore} bean in the Spring application context + * in which to persist or overflow data from 1 or more cache {@link org.apache.geode.cache.Region Regions}. * * @author John Blum * @see org.apache.geode.cache.DiskStore @@ -52,13 +63,20 @@ import org.springframework.core.annotation.AliasFor; public @interface EnableDiskStore { /** - * Name of the {@link org.apache.geode.cache.DiskStore}. + * Name of the {@link DiskStore}. + * + * Required! */ @AliasFor(attribute = "name") String value() default ""; /** - * Name of the {@link org.apache.geode.cache.DiskStore}. + * Name of the {@link DiskStore}. + * + * Required! + * + * This value of this attribute is also used to resolve {@link DiskStore} specific properties defined in + * {@literal application.properties}. */ @AliasFor(attribute = "value") String name() default ""; @@ -66,16 +84,24 @@ public @interface EnableDiskStore { /** * Set to true to allow disk compaction to be forced on this disk store. * - * Default is {@literal false}. + * Defaults to {@literal false}. + * + * Use either the {@literal spring.data.gemfire.disk.store..allow-force-compaction} property + * or the {@literal spring.data.gemfire.disk.store.allow-force-compaction} property + * in {@literal application.properties}. */ - boolean allowForceCompaction() default false; + boolean allowForceCompaction() default DEFAULT_ALLOW_FORCE_COMPACTION; /** * Set to true to automatically compact the disk files. * - * Default is {@literal false}. + * Defaults to {@literal true}. + * + * Use either the {@literal spring.data.gemfire.disk.store..auto-compact} property + * or the {@literal spring.data.gemfire.disk.store.auto-compact} property + * in {@literal application.properties}. */ - boolean autoCompact() default false; + boolean autoCompact() default DEFAULT_AUTO_COMPACT; /** * The threshold at which an oplog will become compactable. Until it reaches this threshold the oplog @@ -84,13 +110,27 @@ public @interface EnableDiskStore { * The threshold is a percentage in the range 0 to 100. * * Defaults to {@literal 50} percent. + * + * Use either the {@literal spring.data.gemfire.disk.store..compaction-threshold} property + * or the {@literal spring.data.gemfire.disk.store.compaction-threshold} property + * in {@literal application.properties}. */ - int compactionThreshold() default 50; + int compactionThreshold() default DEFAULT_COMPACTION_THRESHOLD; /** * File system directory location(s) in which the {@link org.apache.geode.cache.DiskStore} files are stored. * * Defaults to current working directory with 2 petabytes of storage capacity maximum size. + * + * Use either the {@literal spring.data.gemfire.disk.store..directory[#].location}, + * {@literal spring.data.gemfire.disk.store..directory[#].size}, + * {@literal spring.data.gemfire.disk.store..directory.location}, + * {@literal spring.data.gemfire.disk.store..directory.size} properties, + * or the {@literal spring.data.gemfire.disk.store.directory[#].location} + * {@literal spring.data.gemfire.disk.store.directory[#].size}, + * {@literal spring.data.gemfire.disk.store.directory.location}, + * {@literal spring.data.gemfire.disk.store.directory.size} properties, + * in {@literal application.properties}. */ DiskDirectory[] diskDirectories() default {}; @@ -103,8 +143,12 @@ public @interface EnableDiskStore { * Set to "0" (zero) to disable. * * Defaults to {@literal 99} percent. + * + * Use either the {@literal spring.data.gemfire.disk.store..disk-usage-critical-percentage} property + * or the {@literal spring.data.gemfire.disk.store.disk-usage-critical-percentage} property + * in {@literal application.properties}. */ - float diskUsageCriticalPercentage() default 99.0f; + float diskUsageCriticalPercentage() default DEFAULT_DISK_USAGE_CRITICAL_PERCENTAGE; /** * Disk usage above this threshold generates a warning message. @@ -115,29 +159,45 @@ public @interface EnableDiskStore { * Set to "0" (zero) to disable. * * Defaults to {@literal 90} percent. + * + * Use either the {@literal spring.data.gemfire.disk.store..disk-usage-warning-percentage} property + * or the {@literal spring.data.gemfire.disk.store.disk-usage-warning-percentage} property + * in {@literal application.properties}. */ - float diskUsageWarningPercentage() default 90.0f; + float diskUsageWarningPercentage() default DEFAULT_DISK_USAGE_WARNING_PERCENTAGE; /** * The maximum size, in megabytes, of an oplog (operation log) file. * * Defaults to {@literal 1024} MB. + * + * Use either the {@literal spring.data.gemfire.disk.store..max-oplog-size} property + * or the {@literal spring.data.gemfire.disk.store.max-oplog-size} property + * in {@literal application.properties}. */ - long maxOplogSize() default 1024L; + long maxOplogSize() default DEFAULT_MAX_OPLOG_SIZE; /** * Maximum number of operations that can be asynchronously queued to be written to disk. * * Defaults to {@literal 0} (unlimited). + * + * Use either the {@literal spring.data.gemfire.disk.store..queue-size} property + * or the {@literal spring.data.gemfire.disk.store.queue-size} property + * in {@literal application.properties}. */ - int queueSize() default 0; + int queueSize() default DEFAULT_QUEUE_SIZE; /** * The number of milliseconds that can elapse before unwritten data is written to disk. * * Defaults to {@literal 1000} ms. + * + * Use either the {@literal spring.data.gemfire.disk.store..time-interval} property + * or the {@literal spring.data.gemfire.disk.store.time-interval} property + * in {@literal application.properties}. */ - long timeInterval() default 1000L; + long timeInterval() default DEFAULT_TIME_INTERVAL; /** * The size of the write buffer that this disk store uses when writing data to disk. @@ -146,8 +206,12 @@ public @interface EnableDiskStore { * one direct memory buffer of this size. * * Defaults to {@literal 32768} bytes. + * + * Use either the {@literal spring.data.gemfire.disk.store..write-buffer-size} property + * or the {@literal spring.data.gemfire.disk.store.write-buffer-size} property + * in {@literal application.properties}. */ - int writeBufferSize() default 32768; + int writeBufferSize() default DEFAULT_WRITE_BUFFER_SIZE; @interface DiskDirectory { diff --git a/src/main/java/org/springframework/data/gemfire/config/annotation/EnableHttpService.java b/src/main/java/org/springframework/data/gemfire/config/annotation/EnableHttpService.java index 25e10f01..e13f3294 100644 --- a/src/main/java/org/springframework/data/gemfire/config/annotation/EnableHttpService.java +++ b/src/main/java/org/springframework/data/gemfire/config/annotation/EnableHttpService.java @@ -17,6 +17,7 @@ package org.springframework.data.gemfire.config.annotation; +import java.lang.annotation.Annotation; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Inherited; @@ -24,16 +25,24 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; /** - * The EnableHttpService annotation marks a Spring {@link org.springframework.context.annotation.Configuration @Configuration} - * annotated class to configure and enable GemFire/Geode's embedded HTTP service. + * The {@link EnableHttpService} annotation marks a Spring {@link Configuration @Configuration} + * annotated {@link Class} to configure and enable Pivotal GemFire/Apache Geode's embedded HTTP service. * - * By using this annotation, this allows GemFire's embedded HTTP services, like Pulse, the Management REST API - * and the Developer REST API to be enabled. + * By using this {@link Annotation}, this enables the embedded HTTP services like Pulse, the Management REST API + * and the Developer REST API on startup. + * + * However, the embedded Pivotal GemFire/Apache Geode HTTP service and all dependent services (e.g. Pulse) + * can be enabled/disabled externally in {@literal application.properties} with + * the {@literal spring.data.gemfire.service.http.enabled} property even when this {@link Annotation} is present, + * thereby serving as a toggle. * * @author John Blum + * @see java.lang.annotation.Annotation + * @see org.springframework.context.annotation.Import * @see org.springframework.data.gemfire.config.annotation.HttpServiceConfiguration * @see Developing REST Applications for Apache Geode * @since 1.9.0 @@ -53,6 +62,8 @@ public @interface EnableHttpService { * and the Developer REST API service. * * Defaults to unset. + * + * Use the {@literal spring.data.gemfire.service.http.bind-address} property in {@literal application.properties}. */ String bindAddress() default ""; @@ -64,6 +75,8 @@ public @interface EnableHttpService { * and {@literal start-dev-rest-api} are both set to {@literal false}. * * Defaults to {@literal 7070}. + * + * Use the {@literal spring.data.gemfire.service.http.port} property in {@literal application.properties}. */ int port() default HttpServiceConfiguration.DEFAULT_HTTP_SERVICE_PORT; @@ -77,15 +90,21 @@ public @interface EnableHttpService { * {@link org.springframework.data.gemfire.config.annotation.EnableSsl.Component#HTTP}. * * Defaults to {@literal false}. + * + * Use the {@literal spring.data.gemfire.service.http.ssl-require-authentication} property + * in {@literal application.properties}. */ boolean sslRequireAuthentication() default false; /** - * If set to true, then the developer REST API service will be started when cache is created. - * The REST service can be configured using {@literal http-service-port} and {@literal http-service-bind-address} - * GemFire System Properties. + * If set to {@literal true}, then the Developer REST API service will be started when the cache is created. + * The REST service can be configured using {@literal http-service-bind-address} and {@literal http-service-port} + * Pivotal GemFire/Apache Geode System Properties. * * Defaults to {@literal false}. + * + * Use the {@literal spring.data.gemfire.service.http.dev-rest-api.start} property + * in {@literal application.properties}. */ boolean startDeveloperRestApi() default false; diff --git a/src/main/java/org/springframework/data/gemfire/config/annotation/EnableLocator.java b/src/main/java/org/springframework/data/gemfire/config/annotation/EnableLocator.java index 60d3b357..5d9ec277 100644 --- a/src/main/java/org/springframework/data/gemfire/config/annotation/EnableLocator.java +++ b/src/main/java/org/springframework/data/gemfire/config/annotation/EnableLocator.java @@ -17,6 +17,7 @@ package org.springframework.data.gemfire.config.annotation; +import java.lang.annotation.Annotation; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Inherited; @@ -24,13 +25,20 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +import org.apache.geode.distributed.Locator; +import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; /** - * The EnableLocator annotation configures a Spring {@link org.springframework.context.annotation.Configuration @Configuration} - * annotated class to start an embedded GemFire Locator service in this GemFire server/data node. + * The {@link EnableLocator} annotation configures a Spring {@link Configuration @Configuration} annotated {@link Class} + * to start an embedded Pivotal GemFire/Apache Geode {@link Locator} service in this cluster member. + * + * However, the embedded Pivotal GemFire/Apache Geode Locator service can be enabled/disabled externally + * in {@literal application.properties} with the {@literal spring.data.gemfire.service.http.enabled} property + * even when this {@link Annotation} is present, thereby serving as a toggle. * * @author John Blum + * @see java.lang.annotation.Annotation * @see org.springframework.context.annotation.Import * @see org.springframework.data.gemfire.config.annotation.LocatorConfiguration * @since 1.9.0 @@ -47,7 +55,9 @@ public @interface EnableLocator { * Configures the host/IP address on which the embedded Locator service will bind to for accepting connections * from clients sending Locator requests. * - * Default is {@literal localhost}. + * Defaults to {@literal localhost}. + * + * Use the {@literal spring.data.gemfire.locator.host} property in {@literal application.properties}. */ String host() default LocatorConfiguration.DEFAULT_HOST; @@ -55,7 +65,9 @@ public @interface EnableLocator { * Configures the port on which the embedded Locator service will bind to listening for client connections * sending Locator requests. * - * Default is {@literal 10334}. + * Defaults to {@literal 10334}. + * + * Use the {@literal spring.data.gemfire.locator.host} property in {@literal application.properties}. */ int port() default LocatorConfiguration.DEFAULT_LOCATOR_PORT; diff --git a/src/main/java/org/springframework/data/gemfire/config/annotation/EnableLogging.java b/src/main/java/org/springframework/data/gemfire/config/annotation/EnableLogging.java index cc58a21a..99037124 100644 --- a/src/main/java/org/springframework/data/gemfire/config/annotation/EnableLogging.java +++ b/src/main/java/org/springframework/data/gemfire/config/annotation/EnableLogging.java @@ -24,13 +24,16 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; /** - * The EnableLogging annotation marks a Spring {@link org.springframework.context.annotation.Configuration @Configuration} - * annotated class to configure and enable GemFire/Geode system logging. + * The {@link EnableLogging} annotation marks a Spring {@link Configuration @Configuration} annotated {@link Class} + * to configure and enable Pivotal GemFire/Apache Geode system logging. * * @author John Blum + * @see java.lang.annotation.Annotation + * @see org.springframework.context.annotation.Import * @see org.springframework.data.gemfire.config.annotation.LoggingConfiguration * @since 1.9.0 */ @@ -47,6 +50,9 @@ public @interface EnableLogging { * are deleted, oldest first, until the total size is within the limit. If set to zero, disk space use is unlimited. * * Defaults to {@literal 0} MB. + * + * Use the {@literal spring.data.gemfire.logging.log-disk-space-limit} property + * in {@literal application.properties}. */ int logDiskSpaceLimit() default LoggingConfiguration.DEFAULT_LOG_DISK_SPACE_LIMIT; @@ -54,6 +60,8 @@ public @interface EnableLogging { * File to which a running system member writes log messages. Logs to standard out by default. * * Defaults to unset. + * + * Use the {@literal spring.data.gemfire.logging.log-file} property in {@literal application.properties}. */ String logFile() default ""; @@ -62,6 +70,8 @@ public @interface EnableLogging { * If set to 0, log rolling is disabled. * * Defaults to {@literal 0} MB. + * + * Use the {@literal spring.data.gemfire.logging.log-file-size-limit} property in {@literal application.properties}. */ int logFileSizeLimit() default LoggingConfiguration.DEFAULT_LOG_FILE_SIZE_LIMIT; @@ -73,6 +83,8 @@ public @interface EnableLogging { * {@literal error}, {@literal severe}, and {@literal none}. * * Defaults to {@literal config}. + * + * Use the {@literal spring.data.gemfire.logging.level} property in {@literal application.properties}. */ String logLevel() default "config"; diff --git a/src/main/java/org/springframework/data/gemfire/config/annotation/EnableManager.java b/src/main/java/org/springframework/data/gemfire/config/annotation/EnableManager.java index 07458bc2..eb098e81 100644 --- a/src/main/java/org/springframework/data/gemfire/config/annotation/EnableManager.java +++ b/src/main/java/org/springframework/data/gemfire/config/annotation/EnableManager.java @@ -17,6 +17,7 @@ package org.springframework.data.gemfire.config.annotation; +import java.lang.annotation.Annotation; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Inherited; @@ -24,15 +25,22 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; /** - * The EnableManager annotation marks a Spring {@link org.springframework.context.annotation.Configuration @Configuration} - * annotated class to configure, embed and start a GemFire/Geode Manager service in the GemFire/Geode Server. + * The {@link EnableManager} annotation marks a Spring {@link Configuration @Configuration} annotated {@link Class} + * to configure, embed and start a Pivotal GemFire/Apache Geode Manager service in this cluster member. * - * Automatically sets {@literal jmx-manager} to {@literal true}. + * Automatically sets {@literal jmx-manager} to {@literal true} just by specifying this {@link Annotation} + * on your Spring application {@link Configuration @Configuration} annotated {@link Class}. + * + * However, the embedded Pivotal GemFire/Apache Geode Manager can be enabled/disabled externally + * in {@literal application.properties} by using the {@literal spring.data.gemfire.manager.enabled} property + * even when this {@link Annotation} is present, thereby serving as a toggle. * * @author John Blum + * @see java.lang.annotation.Annotation * @see org.springframework.context.annotation.Import * @see org.springframework.data.gemfire.config.annotation.ManagerConfiguration * @since 1.9.0 @@ -54,6 +62,8 @@ public @interface EnableManager { * is false or if {@literal jmx-manager-port} is zero. * * Defaults to unset. + * + * Use the {@literal spring.data.gemfire.manager.access-file} property in {@literal application.properties}. */ String accessFile() default ""; @@ -63,6 +73,8 @@ public @interface EnableManager { * non-HTTP connections. Ignored if JMX Manager is {@literal false} or {@literal jmx-manager-port} is zero. * * Defaults to unset. + * + * Use the {@literal spring.data.gemfire.manager.bind-address} property in {@literal application.properties}. */ String bindAddress() default ""; @@ -73,6 +85,9 @@ public @interface EnableManager { * {@literal jmx-manager} is {@literal false} or {@literal jmx-manager-port} is zero. * * Defaults to unset. + * + * Use the {@literal spring.data.gemfire.manager.hostname-for-clients} property + * in {@literal application.properties}. */ String hostnameForClients() default ""; @@ -84,6 +99,8 @@ public @interface EnableManager { * System property. Ignored if {@literal jmx-manager} is {@literal false} or {@literal jmx-manager-port} is zero. * * Defaults to unset. + * + * Use the {@literal spring.data.gemfire.manager.password-file} property in {@literal application.properties}. */ String passwordFile() default ""; @@ -93,6 +110,8 @@ public @interface EnableManager { * by the JVM for configuring access from remote JMX clients. Ignored if {@literal jmx-manager} is {@literal false}. * * Defaults to {@literal 1099}. + * + * Use the {@literal spring.data.gemfire.manager.port} property in {@literal application.properties}. */ int port() default ManagerConfiguration.DEFAULT_JMX_MANAGER_PORT; @@ -103,6 +122,8 @@ public @interface EnableManager { * to {@literal true}. Ignored if {@literal jmx-manager} is {@literal false}. * * Defaults to {@literal false}. + * + * Use the {@literal spring.data.gemfire.manager.start} property in {@literal application.properties}. */ boolean start() default false; @@ -112,6 +133,8 @@ public @interface EnableManager { * cause stale values to be seen by Gfsh and GemFire Pulse. * * Defaults to {@literal 2000} milliseconds. + * + * Use the {@literal spring.data.gemfire.manager.update-rate} property in {@literal application.properties}. */ int updateRate() default 2000; diff --git a/src/main/java/org/springframework/data/gemfire/config/annotation/EnableMcast.java b/src/main/java/org/springframework/data/gemfire/config/annotation/EnableMcast.java index 7100538a..9670db58 100644 --- a/src/main/java/org/springframework/data/gemfire/config/annotation/EnableMcast.java +++ b/src/main/java/org/springframework/data/gemfire/config/annotation/EnableMcast.java @@ -24,14 +24,17 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; /** - * The EnableMcast annotation marks a Spring {@link org.springframework.context.annotation.Configuration @Configuration} - * annotated class to configure and enable GemFire/Geode's multi-cast networking support. + * The {@link EnableMcast} annotation marks a Spring {@link Configuration @Configuration} annotated {@link Class} + * to configure and enable Pivotal GemFire/Apache Geode's multi-cast networking features. * * @author John Blum - * @see org.springframework.data.gemfire.config.annotation.EnableMcast + * @see java.lang.annotation.Annotation + * @see org.springframework.context.annotation.Import + * @see org.springframework.data.gemfire.config.annotation.McastConfiguration * @since 1.9.0 */ @Target(ElementType.TYPE) diff --git a/src/main/java/org/springframework/data/gemfire/config/annotation/EnableMemcachedServer.java b/src/main/java/org/springframework/data/gemfire/config/annotation/EnableMemcachedServer.java index 70037210..4c70232b 100644 --- a/src/main/java/org/springframework/data/gemfire/config/annotation/EnableMemcachedServer.java +++ b/src/main/java/org/springframework/data/gemfire/config/annotation/EnableMemcachedServer.java @@ -17,6 +17,7 @@ package org.springframework.data.gemfire.config.annotation; +import java.lang.annotation.Annotation; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Inherited; @@ -24,16 +25,22 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; /** - * The EnableMemcachedServer annotation marks a Spring {@link org.springframework.context.annotation.Configuration @Configuration} - * annotated class to start an embedded Memcached Server (Gemcached) service in the GemFire server/data node. + * The {@link EnableMemcachedServer} annotation marks a Spring {@link Configuration @Configuration} + * annotated {@link Class} to start an embedded Memcached Server (Gemcached) service in this cluster member. * * The Gemcached service implements the Memcached Server protocol enabling Memcached clients to connect to * and communicate with Pivotal GemFire or Apache Geode servers. * + * However, the embedded Pivotal GemFire/Apache Geode Memcached Service can be enabled/disabled externally + * in {@literal application.properties} by using the {@literal spring.data.gemfire.service.memcached.enabled} property + * even when this {@link Annotation} is present, thereby serving as a toggle. + * * @author John Blum + * @see java.lang.annotation.Annotation * @see org.springframework.context.annotation.Import * @see org.springframework.data.gemfire.config.annotation.MemcachedServerConfiguration * @since 1.9.0 @@ -51,6 +58,8 @@ public @interface EnableMemcachedServer { * and starts the Gemcached server. * * Default to {@literal 11211}. + * + * Use the {@literal spring.data.gemfire.service.memcached.port} property in {@literal application.properties}. */ int port() default MemcachedServerConfiguration.DEFAULT_MEMCACHED_SERVER_PORT; @@ -59,6 +68,8 @@ public @interface EnableMemcachedServer { * If you omit this property, the ASCII protocol is used. * * Default to {@link MemcachedProtocol#ASCII}. + * + * Use the {@literal spring.data.gemfire.service.memcached.protocol} property in {@literal application.properties}. */ MemcachedProtocol protocol() default MemcachedProtocol.ASCII; diff --git a/src/main/java/org/springframework/data/gemfire/config/annotation/EnableOffHeap.java b/src/main/java/org/springframework/data/gemfire/config/annotation/EnableOffHeap.java index 79a24970..e524a193 100644 --- a/src/main/java/org/springframework/data/gemfire/config/annotation/EnableOffHeap.java +++ b/src/main/java/org/springframework/data/gemfire/config/annotation/EnableOffHeap.java @@ -24,14 +24,18 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +import org.apache.geode.cache.Region; +import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; /** - * The EnableOffHeap annotation marks a Spring {@link org.springframework.context.annotation.Configuration @Configuration} - * annotated class to configure and enable Apache Geode Off-Heap Memory support and data storage - * in Geode's cache {@link org.apache.geode.cache.Region Regions}. + * The {@link EnableOffHeap} annotation marks a Spring {@link Configuration @Configuration} annotated {@link Class} + * to configure and enable Pivotal GemFire/Apache Geode Off-Heap Memory support and data storage + * in cache {@link org.apache.geode.cache.Region Regions}. * * @author John Blum + * @see java.lang.annotation.Annotation + * @see org.springframework.context.annotation.Import * @see org.springframework.data.gemfire.config.annotation.OffHeapConfiguration * @since 1.9.0 */ @@ -44,7 +48,9 @@ import org.springframework.context.annotation.Import; public @interface EnableOffHeap { /** - * Specifies the size of off-heap memory in megabytes (m) or gigabytes (g). For example: + * Specifies the size of off-heap memory in megabytes (m) or gigabytes (g). + * + * For example: * *
 	 *     
@@ -54,13 +60,17 @@ public @interface EnableOffHeap {
 	 * 
* * Defaults to unset. + * + * Use the {@literal spring.data.gemfire.cache.off-heap-memory-size} property in {@literal application.properties}. */ String memorySize(); /** - * Idenfitied the Regions by name in which the off-heap memory setting will be applied. + * Identifies all the {@link Region Regions} by name in which the off-heap memory setting will be applied. * * Defaults to all Regions. + * + * Use the {@literal spring.data.gemfire.cache.region-names} property in {@literal application.properties}. */ String[] regionNames() default {}; diff --git a/src/main/java/org/springframework/data/gemfire/config/annotation/EnablePdx.java b/src/main/java/org/springframework/data/gemfire/config/annotation/EnablePdx.java index 96f8a2c6..9d380452 100644 --- a/src/main/java/org/springframework/data/gemfire/config/annotation/EnablePdx.java +++ b/src/main/java/org/springframework/data/gemfire/config/annotation/EnablePdx.java @@ -24,12 +24,17 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.type.AnnotationMetadata; + /** - * The EnablePdx annotation marks a Spring {@link org.springframework.context.annotation.Configuration @Configuration} - * annotated class to enable the GemFire PDX features and functionality in a GemFire server/data node - * or GemFire cache client application. + * The {@link EnablePdx} annotation marks a Spring {@link Configuration @Configuration} annotated {@link Class} + * to enable the Pivotal GemFire/Apache Geode PDX features and functionality in this peer cache, cluster member + * or cache client application. * * @author John Blum + * @see java.lang.annotation.Annotation + * @see org.springframework.data.gemfire.config.annotation.AbstractCacheConfiguration#configurePdx(AnnotationMetadata) * @since 1.9.0 */ @Target(ElementType.TYPE) @@ -41,6 +46,8 @@ public @interface EnablePdx { /** * Configures the disk store that is used for PDX meta data. + * + * Use the {@literal spring.data.gemfire.pdx.disk-store-name} property in {@literal application.properties}. */ String diskStoreName() default ""; @@ -48,6 +55,8 @@ public @interface EnablePdx { * Configures whether pdx ignores fields that were unread during deserialization. * * Default is {@literal false}. + * + * Use the {@literal spring.data.gemfire.pdx.ignore-unread-fields} property in {@literal application.properties}. */ boolean ignoreUnreadFields() default false; @@ -55,6 +64,8 @@ public @interface EnablePdx { * Configures whether the type metadata for PDX objects is persisted to disk. * * Default is {@literal false}. + * + * Use the {@literal spring.data.gemfire.pdx.persistent} property in {@literal application.properties}. */ boolean persistent() default false; @@ -62,6 +73,8 @@ public @interface EnablePdx { * Configures the object preference to {@link org.apache.geode.pdx.PdxInstance} type or {@link Object}. * * Default is {@literal false}. + * + * Use the {@literal spring.data.gemfire.pdx.read-serialized} property in {@literal application.properties}. */ boolean readSerialized() default false; diff --git a/src/main/java/org/springframework/data/gemfire/config/annotation/EnablePool.java b/src/main/java/org/springframework/data/gemfire/config/annotation/EnablePool.java index 6ad19f45..efcdfe32 100644 --- a/src/main/java/org/springframework/data/gemfire/config/annotation/EnablePool.java +++ b/src/main/java/org/springframework/data/gemfire/config/annotation/EnablePool.java @@ -43,6 +43,7 @@ import org.springframework.data.gemfire.GemfireUtils; * @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.AddPoolsConfiguration * @see org.springframework.data.gemfire.config.annotation.EnablePools * @see org.springframework.data.gemfire.config.annotation.PoolConfigurer * @since 1.9.0 @@ -58,27 +59,43 @@ public @interface EnablePool { /** * Configures the free connection timeout for this pool. * - * @see org.apache.geode.cache.client.PoolFactory#DEFAULT_FREE_CONNECTION_TIMEOUT + * Defaults to {@link PoolFactory#DEFAULT_FREE_CONNECTION_TIMEOUT}. + * + * Use either the {@literal spring.data.gemfire.pool..free-connection-timeout} property + * or the {@literal spring.data.gemfire.pool.free-connection-timeout} property + * in {@literal application.properties}. */ int freeConnectionTimeout() default PoolFactory.DEFAULT_FREE_CONNECTION_TIMEOUT; /** * Configures the amount of time a connection can be idle before expiring the connection. * - * @see org.apache.geode.cache.client.PoolFactory#DEFAULT_IDLE_TIMEOUT + * Defaults to {@link PoolFactory#DEFAULT_IDLE_TIMEOUT}. + * + * Use either the {@literal spring.data.gemfire.pool..idle-timeout} property + * or the {@literal spring.data.gemfire.pool.idle-timeout} property + * in {@literal application.properties}. */ long idleTimeout() default PoolFactory.DEFAULT_IDLE_TIMEOUT; /** * Configures the load conditioning interval for this pool. * - * @see org.apache.geode.cache.client.PoolFactory#DEFAULT_LOAD_CONDITIONING_INTERVAL + * Defaults to {@link PoolFactory#DEFAULT_LOAD_CONDITIONING_INTERVAL}. + * + * Use either the {@literal spring.data.gemfire.pool..load-conditioning-interval} property + * or the {@literal spring.data.gemfire.pool.load-conditioning-interval} property + * in {@literal application.properties}. */ int loadConditioningInterval() default PoolFactory.DEFAULT_LOAD_CONDITIONING_INTERVAL; /** * Configures the GemFire {@link org.apache.geode.distributed.Locator Locators} to which * this cache client will connect. + * + * Use either the {@literal spring.data.gemfire.pool..locators} property + * or the {@literal spring.data.gemfire.pool.locators} property + * in {@literal application.properties}. */ Locator[] locators() default {}; @@ -87,39 +104,62 @@ public @interface EnablePool { * of GemFire Locators in the cluster. * * The {@link String} must be formatted as: 'host1[port], host2[port], ..., hostN[port]'. + * + * Use either the {@literal spring.data.gemfire.pool..locators} property + * or the {@literal spring.data.gemfire.pool.locators} property + * in {@literal application.properties}. */ String locatorsString() default ""; /** * Configures the max number of client to server connections that the pool will create. * - * @see org.apache.geode.cache.client.PoolFactory#DEFAULT_MAX_CONNECTIONS + * Defaults to {@link PoolFactory#DEFAULT_MAX_CONNECTIONS}. + * + * Use either the {@literal spring.data.gemfire.pool..max-connections} property + * or the {@literal spring.data.gemfire.pool.max-connections} property + * in {@literal application.properties}. */ int maxConnections() default PoolFactory.DEFAULT_MAX_CONNECTIONS; /** * Configures the minimum number of connections to keep available at all times. * - * @see org.apache.geode.cache.client.PoolFactory#DEFAULT_MIN_CONNECTIONS + * Defaults to {@link PoolFactory#DEFAULT_MIN_CONNECTIONS}. + * + * Use either the {@literal spring.data.gemfire.pool..min-connections} property + * or the {@literal spring.data.gemfire.pool.min-connections} property + * in {@literal application.properties}. */ int minConnections() default PoolFactory.DEFAULT_MIN_CONNECTIONS; /** * If set to true then the created pool can be used by multiple users. * - * @see org.apache.geode.cache.client.PoolFactory#DEFAULT_MULTIUSER_AUTHENTICATION + * Defaults to {@link PoolFactory#DEFAULT_MULTIUSER_AUTHENTICATION}. + * + * Use either the {@literal spring.data.gemfire.pool..multi-user-authentication} property + * or the {@literal spring.data.gemfire.pool.multi-user-authentication} property + * in {@literal application.properties}. */ boolean multiUserAuthentication() default PoolFactory.DEFAULT_MULTIUSER_AUTHENTICATION; /** - * Specifies the name of the GemFire client {@link Pool}. + * Specifies the {@link String name} of the client {@link Pool} in Pivotal GemFire/Apache Geode, which is also + * used as the Spring bean name in the container as well as the name + * (e.g. {@literal spring.data.gemfire.pool..max-connections} used in the resolution of {@link Pool} + * properties from {@literal application.properties} that are specific to this {@link Pool}. */ String name(); /** * Configures how often to ping servers to verify that they are still alive. * - * @see org.apache.geode.cache.client.PoolFactory#DEFAULT_PING_INTERVAL + * Defaults to {@link PoolFactory#DEFAULT_PING_INTERVAL}. + * + * Use either the {@literal spring.data.gemfire.pool..ping-interval} property + * or the {@literal spring.data.gemfire.pool.ping-interval} property + * in {@literal application.properties}. */ long pingInterval() default PoolFactory.DEFAULT_PING_INTERVAL; @@ -127,7 +167,11 @@ public @interface EnablePool { * By default {@code prSingleHopEnabled} is {@literal true} in which case the client is aware of the location * of partitions on servers hosting Regions with {@link org.apache.geode.cache.DataPolicy#PARTITION}. * - * @see org.apache.geode.cache.client.PoolFactory#DEFAULT_PR_SINGLE_HOP_ENABLED + * Defaults to {@link PoolFactory#DEFAULT_PR_SINGLE_HOP_ENABLED}. + * + * Use either the {@literal spring.data.gemfire.pool..pr-single-hop-enabled} property + * or the {@literal spring.data.gemfire.pool.pr-single-hop-enabled} property + * in {@literal application.properties}. */ boolean prSingleHopEnabled() default PoolFactory.DEFAULT_PR_SINGLE_HOP_ENABLED; @@ -135,27 +179,43 @@ public @interface EnablePool { * Configures the number of milliseconds to wait for a response from a server before timing out the operation * and trying another server (if any are available). * - * @see org.apache.geode.cache.client.PoolFactory#DEFAULT_READ_TIMEOUT + * Defaults to {@link PoolFactory#DEFAULT_READ_TIMEOUT}. + * + * Use either the {@literal spring.data.gemfire.pool..read-timeout} property + * or the {@literal spring.data.gemfire.pool.read-timeout} property + * in {@literal application.properties}. */ int readTimeout() default PoolFactory.DEFAULT_READ_TIMEOUT; /** * Configures the number of times to retry a request after timeout/exception. * - * @see org.apache.geode.cache.client.PoolFactory#DEFAULT_RETRY_ATTEMPTS + * Defaults to {@link PoolFactory#DEFAULT_RETRY_ATTEMPTS}. + * + * Use either the {@literal spring.data.gemfire.pool..retry-attempts} property + * or the {@literal spring.data.gemfire.pool.retry-attempts} property + * in {@literal application.properties}. */ 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 + * Defaults to {@link PoolFactory#DEFAULT_SERVER_GROUP}. + * + * Use either the {@literal spring.data.gemfire.pool..server-group} property + * or the {@literal spring.data.gemfire.pool.server-group} property + * in {@literal application.properties}. */ String serverGroup() default PoolFactory.DEFAULT_SERVER_GROUP; /** * Configures the GemFire {@link org.apache.geode.cache.server.CacheServer CacheServers} to which * this cache client will connect. + * + * Use either the {@literal spring.data.gemfire.pool..servers} property + * or the {@literal spring.data.gemfire.pool.servers} property + * in {@literal application.properties}. */ Server[] servers() default {}; @@ -164,20 +224,32 @@ public @interface EnablePool { * of GemFire Servers in the cluster. * * The {@link String} must be formatted as: 'host1[port], host2[port], ..., hostN[port]'. + * + * Use either the {@literal spring.data.gemfire.pool..servers} property + * or the {@literal spring.data.gemfire.pool.servers} property + * in {@literal application.properties}. */ String serversString() default ""; /** * Configures the socket buffer size for each connection made in this pool. * - * @see org.apache.geode.cache.client.PoolFactory#DEFAULT_SOCKET_BUFFER_SIZE + * Defaults to {@link PoolFactory#DEFAULT_SOCKET_BUFFER_SIZE}. + * + * Use either the {@literal spring.data.gemfire.pool..socket-buffer-size} property + * or the {@literal spring.data.gemfire.pool.socket-buffer-size} property + * in {@literal application.properties}. */ int socketBufferSize() default PoolFactory.DEFAULT_SOCKET_BUFFER_SIZE; /** * Configures how often to send client statistics to the server. * - * @see org.apache.geode.cache.client.PoolFactory#DEFAULT_STATISTIC_INTERVAL + * Defaults to {@link PoolFactory#DEFAULT_STATISTIC_INTERVAL}. + * + * Use either the {@literal spring.data.gemfire.pool..statistic-interval} property + * or the {@literal spring.data.gemfire.pool.statistic-interval} property + * in {@literal application.properties}. */ int statisticInterval() default PoolFactory.DEFAULT_STATISTIC_INTERVAL; @@ -185,14 +257,22 @@ public @interface EnablePool { * Configures the interval in milliseconds to wait before sending acknowledgements to the cache server * for events received from the server subscriptions. * - * @see org.apache.geode.cache.client.PoolFactory#DEFAULT_SUBSCRIPTION_ACK_INTERVAL + * Defaults to {@link PoolFactory#DEFAULT_SUBSCRIPTION_ACK_INTERVAL}. + * + * Use either the {@literal spring.data.gemfire.pool..subscription-ack-interval} property + * or the {@literal spring.data.gemfire.pool.subscription-ack-interval} property + * in {@literal application.properties}. */ int subscriptionAckInterval() default PoolFactory.DEFAULT_SUBSCRIPTION_ACK_INTERVAL; /** * If set to true then the created pool will have server-to-client subscriptions enabled. * - * @see org.apache.geode.cache.client.PoolFactory#DEFAULT_SUBSCRIPTION_ENABLED + * Defaults to {@link PoolFactory#DEFAULT_SUBSCRIPTION_ENABLED}. + * + * Use either the {@literal spring.data.gemfire.pool..subscription-enabled} property + * or the {@literal spring.data.gemfire.pool.subscription-enabled} property + * in {@literal application.properties}. */ boolean subscriptionEnabled() default PoolFactory.DEFAULT_SUBSCRIPTION_ENABLED; @@ -200,21 +280,33 @@ public @interface EnablePool { * Configures the messageTrackingTimeout attribute which is the time-to-live period, in milliseconds, * for subscription events the client has received from the server. * - * @see org.apache.geode.cache.client.PoolFactory#DEFAULT_SUBSCRIPTION_MESSAGE_TRACKING_TIMEOUT + * Defaults to {@link PoolFactory#DEFAULT_SUBSCRIPTION_MESSAGE_TRACKING_TIMEOUT}. + * + * Use either the {@literal spring.data.gemfire.pool..subscription-message-tracking-timeout} property + * or the {@literal spring.data.gemfire.pool.subscription-message-tracking-timeout} property + * in {@literal application.properties}. */ int subscriptionMessageTrackingTimeout() default PoolFactory.DEFAULT_SUBSCRIPTION_MESSAGE_TRACKING_TIMEOUT; /** * Configures the redundancy level for this pools server-to-client subscriptions. * - * @see org.apache.geode.cache.client.PoolFactory#DEFAULT_SUBSCRIPTION_REDUNDANCY + * Defaults to {@link PoolFactory#DEFAULT_SUBSCRIPTION_REDUNDANCY}. + * + * Use either the {@literal spring.data.gemfire.pool..subscription-redundancy} property + * or the {@literal spring.data.gemfire.pool.subscription-redundancy} property + * in {@literal application.properties}. */ int subscriptionRedundancy() default PoolFactory.DEFAULT_SUBSCRIPTION_REDUNDANCY; /** * Configures the thread local connections policy for this pool. * - * @see org.apache.geode.cache.client.PoolFactory#DEFAULT_THREAD_LOCAL_CONNECTIONS + * Defaults to {@link PoolFactory#DEFAULT_THREAD_LOCAL_CONNECTIONS}. + * + * Use either the {@literal spring.data.gemfire.pool..thread-local-connections} property + * or the {@literal spring.data.gemfire.pool.thread-local-connections} property + * in {@literal application.properties}. */ boolean threadLocalConnections() default PoolFactory.DEFAULT_THREAD_LOCAL_CONNECTIONS; diff --git a/src/main/java/org/springframework/data/gemfire/config/annotation/EnableRedisServer.java b/src/main/java/org/springframework/data/gemfire/config/annotation/EnableRedisServer.java index bbef33d9..3b4ac041 100644 --- a/src/main/java/org/springframework/data/gemfire/config/annotation/EnableRedisServer.java +++ b/src/main/java/org/springframework/data/gemfire/config/annotation/EnableRedisServer.java @@ -17,6 +17,7 @@ package org.springframework.data.gemfire.config.annotation; +import java.lang.annotation.Annotation; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Inherited; @@ -24,16 +25,23 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; /** - * The EnableRedisServer annotation marks a Spring {@link org.springframework.context.annotation.Configuration} - * class to embed the Redis service in the GemFire server-side data member node. + * The {@link EnableRedisServer} annotation marks a Spring {@link Configuration @Configuration} annotated {@link Class} + * to embed the Redis service in this cluster member. * - * The Redis service implements the Redis server protocol enabling Redis clients to connect and speak - * to Pivotal GemFire or Apache Geode. + * The Redis service implements the Redis server protocol enabling Redis clients to connect to and inter-operate with + * Pivotal GemFire or Apache Geode. + * + * However, the embedded Pivotal GemFire/Apache Geode Redis Service can be enabled/disabled externally + * in {@literal application.properties} by using the {@literal spring.data.gemfire.service.redis.enabled} property + * even when this {@link Annotation} is present, thereby serving as a toggle. * * @author John Blum + * @see java.lang.annotation.Annotation + * @see org.springframework.context.annotation.Import * @see org.springframework.data.gemfire.config.annotation.MemcachedServerConfiguration * @since 1.9.0 */ @@ -49,6 +57,8 @@ public @interface EnableRedisServer { * Configures the Network bind-address on which the Redis server will accept connections. * * Defaults to {@literal localhost}. + * + * Use the {@literal spring.data.gemfire.service.redis.bind-address} property in {@literal application.properties}. */ String bindAddress() default ""; @@ -56,6 +66,8 @@ public @interface EnableRedisServer { * Configures the Network port on which the Redis server will listen for Redis client connections. * * Defaults to {@literal 6379}. + * + * Use the {@literal spring.data.gemfire.service.redis.port} property in {@literal application.properties}. */ int port() default RedisServerConfiguration.DEFAULT_REDIS_PORT; diff --git a/src/main/java/org/springframework/data/gemfire/config/annotation/EnableSecurity.java b/src/main/java/org/springframework/data/gemfire/config/annotation/EnableSecurity.java index d1787d5d..a2b739dd 100644 --- a/src/main/java/org/springframework/data/gemfire/config/annotation/EnableSecurity.java +++ b/src/main/java/org/springframework/data/gemfire/config/annotation/EnableSecurity.java @@ -25,15 +25,16 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import org.apache.geode.security.AuthInitialize; +import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; /** - * The {@link EnableSecurity} annotation marks a Spring {@link org.springframework.context.annotation.Configuration} - * annotated class to configure and enable Apache Geode's Security features for authentication, authorization + * The {@link EnableSecurity} annotation marks a Spring {@link Configuration @Configuration} annotated {@link Class} + * to configure and enable Pivotal GemFire/Apache Geode's Security features for authentication, authorization * and post processing. * * @author John Blum - * @see GeodeIntegratedSecurityConfiguration + * @see java.lang.annotation.Annotation * @see org.apache.geode.security.AuthInitialize * @see org.apache.geode.security.SecurityManager * @see org.apache.geode.security.PostProcessor @@ -55,6 +56,9 @@ public @interface EnableSecurity { * which obtains credentials for clients. * * Defaults to unset. + * + * Use the {@literal spring.data.gemfire.security.client.authentication-initializer} property + * in {@literal application.properties}. */ String clientAuthenticationInitializer() default ""; @@ -63,6 +67,9 @@ public @interface EnableSecurity { * credentials for peers in a distributed system. * * Defaults to unset. + * + * Use the {@literal spring.data.gemfire.security.peer.authentication-initializer} property + * in {@literal application.properties}. */ String peerAuthenticationInitializer() default ""; @@ -81,6 +88,8 @@ public @interface EnableSecurity { * Use this Annotation attribute if you are uncertain whether the application class is on the classpath or not. * * Default is unset. + * + * Use the {@literal spring.data.gemfire.security.manager.class-name} property in {@literal application.properties}. */ String securityManagerClassName() default ""; @@ -101,6 +110,9 @@ public @interface EnableSecurity { * Use this Annotation attribute if you are uncertain whether the application class is on the classpath or not. * * Default is unset. + * + * Use the {@literal spring.data.gemfire.security.postprocessor.class-name} property + * in {@literal application.properties}. */ String securityPostProcessorClassName() default ""; @@ -109,6 +121,9 @@ public @interface EnableSecurity { * the Apache Shiro Security Framework to secure Apache Geode. * * Default is unset. + * + * Use the {@literal spring.data.gemfire.security.shiro.ini-resource-path} property + * in {@literal application.properties}. */ String shiroIniResourcePath() default ""; diff --git a/src/main/java/org/springframework/data/gemfire/config/annotation/EnableSsl.java b/src/main/java/org/springframework/data/gemfire/config/annotation/EnableSsl.java index 61a5035a..a53cdb51 100644 --- a/src/main/java/org/springframework/data/gemfire/config/annotation/EnableSsl.java +++ b/src/main/java/org/springframework/data/gemfire/config/annotation/EnableSsl.java @@ -24,13 +24,18 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; /** - * The EnableSsl class... + * The {@link EnableSsl} annotation marks a Spring {@link Configuration @Configuration} annotated {@link Class} + * to configure and enable Pivotal GemFire/Apache Geode's TCP/IP Socket SSL. * * @author John Blum - * @since 1.0.0 + * @see java.lang.annotation.Annotation + * @see org.springframework.context.annotation.Import + * @see org.springframework.data.gemfire.config.annotation.SslConfiguration + * @since 1.9.0 */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @@ -45,13 +50,21 @@ public @interface EnableSsl { * uses any ciphers that are enabled by default in the configured JSSE provider. * * Defaults to {@literal any}. + * + * Use either the {@literal spring.data.gemfire.security.ssl..ciphers} property + * or the {@literal spring.data.gemfire.security.ssl.ciphers} property + * in {@literal application.properties}. */ String ciphers() default "any"; /** - * A list of GemFire components in which SSL will be enabled. + * An array of Pivotal GemFire/Apache Geode Components in which SSL can be enabled. * - * Defaults to {@link org.springframework.data.gemfire.config.annotation.EnableSsl.Component#CLUSTER} + * Defaults to {@link EnableSsl.Component#CLUSTER}. + * + * The value(s) for this attribute are used to configure cluster-wide + * (e.g. {@literal spring.data.gemfire.security.ssl.cluster.keystore} SSL properties + * or individual component {e.g. {@literal spring.data.gemfire.security.ssl.locator.keystore}} SSL properties. */ Component[] components() default { Component.CLUSTER }; @@ -59,6 +72,10 @@ public @interface EnableSsl { * Pathname to the keystore used for SSL communications. * * Defaults to unset. + * + * Use either the {@literal spring.data.gemfire.security.ssl..keystore} property + * or the {@literal spring.data.gemfire.security.ssl.keystore} property + * in {@literal application.properties}. */ String keystore() default ""; @@ -66,15 +83,24 @@ public @interface EnableSsl { * Password to access the keys in the keystore used in SSL communications. * * Defaults to unset. + * + * Use either the {@literal spring.data.gemfire.security.ssl..keystore-password} property + * or the {@literal spring.data.gemfire.security.ssl.keystore-password} property + * in {@literal application.properties}. */ String keystorePassword() default ""; /** + * TODO change to an enum? + * * Identifies the type of keystore used in SSL communications. For example, JKS, PKCS11, etc. * * Defaults to unset. + * + * Use either the {@literal spring.data.gemfire.security.ssl..keystore-type} property + * or the {@literal spring.data.gemfire.security.ssl.keystore-type} property + * in {@literal application.properties}. */ - // TODO change to a enum? String keystoreType() default ""; /** @@ -82,6 +108,10 @@ public @interface EnableSsl { * uses any protocol that is enabled by default in the configured JSSE provider. * * Defaults to {@literal any}. + * + * Use either the {@literal spring.data.gemfire.security.ssl..protocols} property + * or the {@literal spring.data.gemfire.security.ssl.protocols} property + * in {@literal application.properties}. */ String protocols() default "any"; @@ -90,6 +120,10 @@ public @interface EnableSsl { * clients and servers, gateways, etc. * * Defaults to {@literal true}. + * + * Use either the {@literal spring.data.gemfire.security.ssl..require-authentication} property + * or the {@literal spring.data.gemfire.security.ssl.require-authentication} property + * in {@literal application.properties}. */ boolean requireAuthentication() default true; @@ -97,6 +131,10 @@ public @interface EnableSsl { * Pathname to the truststore used in SSL communications. * * Defaults to unset. + * + * Use either the {@literal spring.data.gemfire.security.ssl..truststore} property + * or the {@literal spring.data.gemfire.security.ssl.truststore} property + * in {@literal application.properties}. */ String truststore() default ""; @@ -104,10 +142,15 @@ public @interface EnableSsl { * Password to access the keys in the truststore used in SSL communications. * * Defaults to unset. + * + * Use either the {@literal spring.data.gemfire.security.ssl..truststore-password} property + * or the {@literal spring.data.gemfire.security.ssl.truststore-password} property + * in {@literal application.properties}. */ String truststorePassword() default ""; enum Component { + CLUSTER("cluster"), GATEWAY("gateway"), HTTP("http-service"), @@ -117,10 +160,17 @@ public @interface EnableSsl { private final String prefix; + /* (non-Javadoc) */ Component(String prefix) { this.prefix = prefix; } + /** + * Returns a {@link String} representation of this enumerated value. + * + * @return a {@link String} describing this enumerated value. + * @see java.lang.Object#toString() + */ @Override public String toString() { return prefix; diff --git a/src/main/java/org/springframework/data/gemfire/config/annotation/EnableStatistics.java b/src/main/java/org/springframework/data/gemfire/config/annotation/EnableStatistics.java index ca5f7555..7cc77468 100644 --- a/src/main/java/org/springframework/data/gemfire/config/annotation/EnableStatistics.java +++ b/src/main/java/org/springframework/data/gemfire/config/annotation/EnableStatistics.java @@ -24,15 +24,18 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; +import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; /** - * The EnableStatistics annotation marks a Spring {@link org.springframework.context.annotation.Configuration @Configuration} - * annotated class to configure and enable statistics and runtime metrics of a running GemFire/Geode system. + * The {@link EnableStatistics} annotation marks a Spring {@link Configuration @Configuration} annotated {@link Class} + * to configure and enable statistics and runtime metrics of a running Pivotal GemFire/Apache Geode system. * * Sets {@literal statistic-sampling-enabled} to {@literal true}. * * @author John Blum + * @see java.lang.annotation.Annotation + * @see org.springframework.context.annotation.Import * @see org.springframework.data.gemfire.config.annotation.StatisticsConfiguration * @since 1.9.0 */ @@ -50,6 +53,9 @@ public @interface EnableStatistics { * disk space use is unlimited. * * Defaults to {@literal 0} MB. + * + * Use the {@literal spring.data.gemfire.stats.archive-disk-space-limit} property + * in {@literal application.properties}. */ int archiveDiskSpaceLimit() default StatisticsConfiguration.DEFAULT_ARCHIVE_DISK_SPACE_LIMIT; @@ -58,6 +64,8 @@ public @interface EnableStatistics { * An empty string disables archiving. Adding .gz suffix to the file name causes it to be compressed. * * Defaults to unset. + * + * Use the {@literal spring.data.gemfire.stats.archive-file} property in {@literal application.properties}. */ String archiveFile() default ""; @@ -67,6 +75,9 @@ public @interface EnableStatistics { * file size is unlimited. * * Defaults to {@literal 0} MB. + * + * Use the {@literal spring.data.gemfire.stats.archive-file-size-limit} property + * in {@literal application.properties}. */ int archiveFileSizeLimit() default StatisticsConfiguration.DEFAULT_ARCHIVE_FILE_SIZE_LIMIT; @@ -75,6 +86,9 @@ public @interface EnableStatistics { * Disabled by default for performance reasons and not recommended for production environments. * * Defaults to {@literal false}. + * + * Use the {@literal spring.data.gemfire.stats.enable-time-statistics} property + * in {@literal application.properties}. */ boolean enableTimeStatistics() default StatisticsConfiguration.DEFAULT_ENABLE_TIME_STATISTICS; @@ -84,6 +98,8 @@ public @interface EnableStatistics { * Valid values are in the range 100..60000. * * Defaults to {@literal 1000} milliseconds. + * + * Use the {@literal spring.data.gemfire.stats.sample-rate} property in {@literal application.properties}. */ long sampleRate() default StatisticsConfiguration.DEFAULT_STATISTIC_SAMPLE_RATE; diff --git a/src/main/java/org/springframework/data/gemfire/config/annotation/GeodeIntegratedSecurityConfiguration.java b/src/main/java/org/springframework/data/gemfire/config/annotation/GeodeIntegratedSecurityConfiguration.java index 7d8d4fa0..1ed934b4 100644 --- a/src/main/java/org/springframework/data/gemfire/config/annotation/GeodeIntegratedSecurityConfiguration.java +++ b/src/main/java/org/springframework/data/gemfire/config/annotation/GeodeIntegratedSecurityConfiguration.java @@ -41,14 +41,24 @@ public class GeodeIntegratedSecurityConfiguration extends EmbeddedServiceConfigu protected static final String SECURITY_SHIRO_INIT = "security-shiro-init"; /** - * @inheritDoc + * Returns the {@link EnableSecurity} {@link java.lang.annotation.Annotation} {@link Class} type. + * + * @return the {@link EnableSecurity} {@link java.lang.annotation.Annotation} {@link Class} type. + * @see org.springframework.data.gemfire.config.annotation.EnableSecurity */ @Override protected Class getAnnotationType() { return EnableSecurity.class; } - /* (non-Javadoc) */ + /** + * Determines whether Pivotal GemFire/Apache Geode's Apache Shiro Security Framework support is enabled + * or available. + * + * @return a boolean value indicating whether Pivotal GemFire/Apache Geode's Apache Shiro Security Framework + * support is enabled or available. + * @see #isShiroSecurityNotConfigured() + */ protected boolean isShiroSecurityConfigured() { try { // NOTE experimental... @@ -60,38 +70,51 @@ public class GeodeIntegratedSecurityConfiguration extends EmbeddedServiceConfigu } } - /* (non-Javadoc) */ + /** + * Determines whether Pivotal GemFire/Apache Geode's Apache Shiro Security Framework support is enabled + * or available. + * + * @return a boolean value indicating whether Pivotal GemFire/Apache Geode's Apache Shiro Security Framework + * support is enabled or available. + * @see #isShiroSecurityConfigured() + */ protected boolean isShiroSecurityNotConfigured() { return !isShiroSecurityConfigured(); } - /** - * @inheritDoc - */ + /* (non-Javadoc) */ @Override protected Properties toGemFireProperties(Map annotationAttributes) { - PropertiesBuilder gemfireProperties = new PropertiesBuilder(); + + PropertiesBuilder gemfireProperties = PropertiesBuilder.create(); gemfireProperties.setProperty(SECURITY_CLIENT_AUTH_INIT, - annotationAttributes.get("clientAuthenticationInitializer")); + resolveProperty(securityProperty("client.authentication-initializer"), + (String) annotationAttributes.get("clientAuthenticationInitializer"))); if (isShiroSecurityNotConfigured()) { gemfireProperties.setPropertyIfNotDefault(SECURITY_MANAGER, annotationAttributes.get("securityManagerClass"), Void.class); - gemfireProperties.setProperty(SECURITY_MANAGER, annotationAttributes.get("securityManagerClassName")); + gemfireProperties.setProperty(SECURITY_MANAGER, + resolveProperty(securityProperty("manager.class-name"), + (String) annotationAttributes.get("securityManagerClassName"))); - gemfireProperties.setProperty(SECURITY_SHIRO_INIT, annotationAttributes.get("shiroIniResourcePath")); + gemfireProperties.setProperty(SECURITY_SHIRO_INIT, + resolveProperty(securityProperty("shiro.ini-resource-path"), + (String) annotationAttributes.get("shiroIniResourcePath"))); } gemfireProperties.setProperty(SECURITY_PEER_AUTH_INIT, - annotationAttributes.get("peerAuthenticationInitializer")); + resolveProperty(securityProperty("peer.authentication-initializer"), + (String) annotationAttributes.get("peerAuthenticationInitializer"))); gemfireProperties.setPropertyIfNotDefault(SECURITY_POST_PROCESSOR, annotationAttributes.get("securityPostProcessorClass"), Void.class); gemfireProperties.setProperty(SECURITY_POST_PROCESSOR, - annotationAttributes.get("securityPostProcessorClassName")); + resolveProperty(securityProperty("postprocessor.class-name"), + (String) annotationAttributes.get("securityPostProcessorClassName"))); return gemfireProperties.build(); } diff --git a/src/main/java/org/springframework/data/gemfire/config/annotation/HttpServiceConfiguration.java b/src/main/java/org/springframework/data/gemfire/config/annotation/HttpServiceConfiguration.java index 5e082857..3de194f2 100644 --- a/src/main/java/org/springframework/data/gemfire/config/annotation/HttpServiceConfiguration.java +++ b/src/main/java/org/springframework/data/gemfire/config/annotation/HttpServiceConfiguration.java @@ -18,17 +18,20 @@ package org.springframework.data.gemfire.config.annotation; import java.util.Map; +import java.util.Optional; import java.util.Properties; +import org.springframework.context.annotation.ImportBeanDefinitionRegistrar; import org.springframework.data.gemfire.config.annotation.support.EmbeddedServiceConfigurationSupport; import org.springframework.data.gemfire.util.PropertiesBuilder; /** - * The HttpServiceConfiguration class is a Spring {@link org.springframework.context.annotation.ImportBeanDefinitionRegistrar} - * that applies additional GemFire/Geode configuration by way of GemFire/Geode System properties to configure - * GemFire/Geode's embeded HTTP service and services. + * The {@link HttpServiceConfiguration} class is a Spring {@link ImportBeanDefinitionRegistrar} that applies + * additional configuration by way of Pivotal GemFire/Apache Geode {@link Properties} to configure + * Pivotal GemFire/Apache Geode's embedded HTTP service and dependent services (e.g. Pulse). * * @author John Blum + * @see org.springframework.context.annotation.ImportBeanDefinitionRegistrar * @see org.springframework.data.gemfire.config.annotation.EnableHttpService * @see org.springframework.data.gemfire.config.annotation.support.EmbeddedServiceConfigurationSupport * @see Developing REST Applications for Apache Geode @@ -41,7 +44,12 @@ public class HttpServiceConfiguration extends EmbeddedServiceConfigurationSuppor public static final int DEFAULT_HTTP_SERVICE_PORT = 7070; - /* (non-Javadoc) */ + /** + * Returns the {@link EnableHttpService} {@link java.lang.annotation.Annotation} {@link Class} type. + * + * @return the {@link EnableHttpService} {@link java.lang.annotation.Annotation} {@link Class} type. + * @see org.springframework.data.gemfire.config.annotation.EnableHttpService + */ @Override protected Class getAnnotationType() { return EnableHttpService.class; @@ -50,19 +58,35 @@ public class HttpServiceConfiguration extends EmbeddedServiceConfigurationSuppor /* (non-Javadoc) */ @Override protected Properties toGemFireProperties(Map annotationAttributes) { - PropertiesBuilder gemfireProperties = PropertiesBuilder.create(); - gemfireProperties.setProperty("http-service-bind-address", annotationAttributes.get("bindAddress")); + return Optional.of(resolveProperty(httpServiceProperty("enabled"), Boolean.TRUE)) + .filter(Boolean.TRUE::equals) + .map(enabled -> { - gemfireProperties.setPropertyIfNotDefault("http-service-port", - annotationAttributes.get("port"), DEFAULT_HTTP_SERVICE_PORT); + PropertiesBuilder gemfireProperties = PropertiesBuilder.create(); - gemfireProperties.setPropertyIfNotDefault("http-service-ssl-require-authentication", - annotationAttributes.get("sslRequireAuthentication"), DEFAULT_HTTP_SERVICE_SSL_REQUIRE_AUTHENTICATION); + gemfireProperties.setProperty("http-service-bind-address", + resolveProperty(httpServiceProperty("bind-address"), + (String) annotationAttributes.get("bindAddress"))); - gemfireProperties.setPropertyIfNotDefault("start-dev-rest-api", - annotationAttributes.get("startDeveloperRestApi"), DEFAULT_HTTP_SERVICE_START_DEVELOPER_REST_API); + gemfireProperties.setPropertyIfNotDefault("http-service-port", + resolveProperty(httpServiceProperty("port"), + (Integer) annotationAttributes.get("port")), + DEFAULT_HTTP_SERVICE_PORT); - return gemfireProperties.build(); + gemfireProperties.setPropertyIfNotDefault("http-service-ssl-require-authentication", + resolveProperty(httpServiceProperty("ssl-require-authentication"), + (Boolean) annotationAttributes.get("sslRequireAuthentication")), + DEFAULT_HTTP_SERVICE_SSL_REQUIRE_AUTHENTICATION); + + gemfireProperties.setPropertyIfNotDefault("start-dev-rest-api", + resolveProperty(httpServiceProperty("dev-rest-api.start"), + (Boolean) annotationAttributes.get("startDeveloperRestApi")), + DEFAULT_HTTP_SERVICE_START_DEVELOPER_REST_API); + + return gemfireProperties.build(); + + }) + .orElseGet(Properties::new); } } diff --git a/src/main/java/org/springframework/data/gemfire/config/annotation/LocatorConfiguration.java b/src/main/java/org/springframework/data/gemfire/config/annotation/LocatorConfiguration.java index b32224a0..3bbe06e6 100644 --- a/src/main/java/org/springframework/data/gemfire/config/annotation/LocatorConfiguration.java +++ b/src/main/java/org/springframework/data/gemfire/config/annotation/LocatorConfiguration.java @@ -18,19 +18,24 @@ package org.springframework.data.gemfire.config.annotation; import java.util.Map; +import java.util.Optional; import java.util.Properties; +import org.apache.geode.distributed.Locator; +import org.springframework.context.annotation.ImportBeanDefinitionRegistrar; import org.springframework.data.gemfire.GemfireUtils; import org.springframework.data.gemfire.config.annotation.support.EmbeddedServiceConfigurationSupport; import org.springframework.data.gemfire.util.PropertiesBuilder; /** - * The LocatorConfiguration class is a Spring {@link org.springframework.context.annotation.ImportBeanDefinitionRegistrar} - * that applies additional GemFire configuration by way of GemFire System properties to configure - * an embedded GemFire Locator. + * The {@link LocatorConfiguration} class is a Spring {@link ImportBeanDefinitionRegistrar} that applies + * additional configuration by way of Pivotal GemFire/Apache Geode {@link Properties} to configure + * an embedded {@link Locator}. * * @author John Blum - * @see EnableLocator + * @see org.apache.geode.distributed.Locator + * @see org.springframework.context.annotation.ImportBeanDefinitionRegistrar + * @see org.springframework.data.gemfire.config.annotation.EnableLocator * @see org.springframework.data.gemfire.config.annotation.support.EmbeddedServiceConfigurationSupport * @since 1.9.0 */ @@ -38,20 +43,37 @@ public class LocatorConfiguration extends EmbeddedServiceConfigurationSupport { protected static final int DEFAULT_LOCATOR_PORT = GemfireUtils.DEFAULT_LOCATOR_PORT; - protected static final String START_LOCATOR_GEMFIRE_SYSTEM_PROPERTY_NAME = "start-locator"; + protected static final String START_LOCATOR_GEMFIRE_PROPERTY_NAME = "start-locator"; + /** + * Returns the {@link EnableLocator} {@link java.lang.annotation.Annotation} {@link Class} type. + * + * @return the {@link EnableLocator} {@link java.lang.annotation.Annotation} {@link Class} type. + * @see org.springframework.data.gemfire.config.annotation.EnableLocator + */ @Override protected Class getAnnotationType() { return EnableLocator.class; } + /* (non-Javadoc) */ @Override protected Properties toGemFireProperties(Map annotationAttributes) { - String host = resolveHost((String) annotationAttributes.get("host")); - int port = resolvePort((Integer) annotationAttributes.get("port"), DEFAULT_LOCATOR_PORT); - return PropertiesBuilder.create() - .setProperty(START_LOCATOR_GEMFIRE_SYSTEM_PROPERTY_NAME, String.format("%s[%d]", host, port)) - .build(); + return Optional.of(resolveProperty(locatorProperty("enabled"), Boolean.TRUE)) + .filter(Boolean.TRUE::equals) + .map(enabled -> { + + String host = resolveHost(resolveProperty(locatorProperty("host"), + (String) annotationAttributes.get("host"))); + + int port = resolvePort(resolveProperty(locatorProperty("port"), + (Integer) annotationAttributes.get("port")), DEFAULT_LOCATOR_PORT); + + return PropertiesBuilder.create() + .setProperty(START_LOCATOR_GEMFIRE_PROPERTY_NAME, String.format("%s[%d]", host, port)) + .build(); + + }).orElseGet(Properties::new); } } diff --git a/src/main/java/org/springframework/data/gemfire/config/annotation/LoggingConfiguration.java b/src/main/java/org/springframework/data/gemfire/config/annotation/LoggingConfiguration.java index 1872dec1..5afd5b74 100644 --- a/src/main/java/org/springframework/data/gemfire/config/annotation/LoggingConfiguration.java +++ b/src/main/java/org/springframework/data/gemfire/config/annotation/LoggingConfiguration.java @@ -20,15 +20,17 @@ package org.springframework.data.gemfire.config.annotation; import java.util.Map; import java.util.Properties; +import org.springframework.context.annotation.ImportBeanDefinitionRegistrar; import org.springframework.data.gemfire.config.annotation.support.EmbeddedServiceConfigurationSupport; import org.springframework.data.gemfire.util.PropertiesBuilder; /** - * The LoggingConfiguration class is a Spring {@link org.springframework.context.annotation.ImportBeanDefinitionRegistrar} - * that applies additional GemFire/Geode configuration by way of GemFire/Geode System properties to configure - * GemFire/Geode logging. + * The {@link LoggingConfiguration} class is a Spring {@link ImportBeanDefinitionRegistrar} that applies + * additional configuration using Pivotal GemFire/Apache Geode {@link Properties} to configure + * Pivotal GemFire/Apache Geode logging. * * @author John Blum + * @see org.springframework.context.annotation.ImportBeanDefinitionRegistrar * @see org.springframework.data.gemfire.config.annotation.EnableLogging * @see org.springframework.data.gemfire.config.annotation.support.EmbeddedServiceConfigurationSupport * @since 1.9.0 @@ -40,7 +42,12 @@ public class LoggingConfiguration extends EmbeddedServiceConfigurationSupport { public static final String DEFAULT_LOG_LEVEL = "config"; - /* (non-Javadoc) */ + /** + * Returns the {@link EnableLogging} {@link java.lang.annotation.Annotation} {@link Class} type. + * + * @return the {@link EnableLogging} {@link java.lang.annotation.Annotation} {@link Class} type. + * @see org.springframework.data.gemfire.config.annotation.EnableLogging + */ @Override protected Class getAnnotationType() { return EnableLogging.class; @@ -49,18 +56,24 @@ public class LoggingConfiguration extends EmbeddedServiceConfigurationSupport { /* (non-Javadoc) */ @Override protected Properties toGemFireProperties(Map annotationAttributes) { + PropertiesBuilder gemfireProperties = PropertiesBuilder.create(); gemfireProperties.setPropertyIfNotDefault("log-disk-space-limit", - annotationAttributes.get("logDiskSpaceLimit"), DEFAULT_LOG_DISK_SPACE_LIMIT); + resolveProperty(loggingProperty("log-disk-space-limit"), + (Integer) annotationAttributes.get("logDiskSpaceLimit")), DEFAULT_LOG_DISK_SPACE_LIMIT); - gemfireProperties.setProperty("log-file", annotationAttributes.get("logFile")); + gemfireProperties.setProperty("log-file", + resolveProperty(loggingProperty("log-file"), + (String) annotationAttributes.get("logFile"))); gemfireProperties.setPropertyIfNotDefault("log-file-size-limit", - annotationAttributes.get("logFileSizeLimit"), DEFAULT_LOG_FILE_SIZE_LIMIT); + resolveProperty(loggingProperty("log-file-size-limit"), + (Integer) annotationAttributes.get("logFileSizeLimit")), DEFAULT_LOG_FILE_SIZE_LIMIT); gemfireProperties.setPropertyIfNotDefault("log-level", - annotationAttributes.get("logLevel"), DEFAULT_LOG_LEVEL); + resolveProperty(loggingProperty("level"), + (String) annotationAttributes.get("logLevel")), DEFAULT_LOG_LEVEL); return gemfireProperties.build(); } diff --git a/src/main/java/org/springframework/data/gemfire/config/annotation/ManagerConfiguration.java b/src/main/java/org/springframework/data/gemfire/config/annotation/ManagerConfiguration.java index dc84e588..2ea54d57 100644 --- a/src/main/java/org/springframework/data/gemfire/config/annotation/ManagerConfiguration.java +++ b/src/main/java/org/springframework/data/gemfire/config/annotation/ManagerConfiguration.java @@ -20,16 +20,18 @@ package org.springframework.data.gemfire.config.annotation; import java.util.Map; import java.util.Properties; +import org.springframework.context.annotation.ImportBeanDefinitionRegistrar; import org.springframework.data.gemfire.config.annotation.support.EmbeddedServiceConfigurationSupport; import org.springframework.data.gemfire.util.PropertiesBuilder; /** - * The ManagerConfiguration class is a Spring {@link org.springframework.context.annotation.ImportBeanDefinitionRegistrar} - * that applies additional GemFire configuration using GemFire System {@link Properties} to configure - * an embedded GemFire Manager. + * The {@link ManagerConfiguration} class is a Spring {@link ImportBeanDefinitionRegistrar} that applies + * additional configuration using Pivotal GemFire/Apache Geode {@link Properties} to configure an embedded Manager + * in this cluster member. * * @author John Blum - * @see EnableManager + * @see org.springframework.context.annotation.ImportBeanDefinitionRegistrar + * @see org.springframework.data.gemfire.config.annotation.EnableManager * @see org.springframework.data.gemfire.config.annotation.support.EmbeddedServiceConfigurationSupport * @since 1.9.0 */ @@ -37,24 +39,52 @@ public class ManagerConfiguration extends EmbeddedServiceConfigurationSupport { protected static final int DEFAULT_JMX_MANAGER_PORT = 1099; + /** + * Returns the {@link EnableManager} {@link java.lang.annotation.Annotation} {@link Class} type. + * + * @return the {@link EnableManager} {@link java.lang.annotation.Annotation} {@link Class} type. + * @see org.springframework.data.gemfire.config.annotation.EnableManager + */ @Override protected Class getAnnotationType() { return EnableManager.class; } + /* (non-Javadoc) */ @Override protected Properties toGemFireProperties(Map annotationAttributes) { + PropertiesBuilder gemfireProperties = PropertiesBuilder.create(); - gemfireProperties.setProperty("jmx-manager", Boolean.TRUE.toString()); - gemfireProperties.setProperty("jmx-manager-access-file", annotationAttributes.get("accessFile")); - gemfireProperties.setProperty("jmx-manager-bind-address", annotationAttributes.get("bindAddress")); - gemfireProperties.setProperty("jmx-manager-hostname-for-clients", annotationAttributes.get("hostnameForClients")); - gemfireProperties.setProperty("jmx-manager-password-file", annotationAttributes.get("passwordFile")); + gemfireProperties.setProperty("jmx-manager", + resolveProperty(managerProperty("enabled"), Boolean.TRUE)); + + gemfireProperties.setProperty("jmx-manager-access-file", + resolveProperty(managerProperty("access-file"), + (String) annotationAttributes.get("accessFile"))); + + gemfireProperties.setProperty("jmx-manager-bind-address", + resolveProperty(managerProperty("bind-address"), + (String) annotationAttributes.get("bindAddress"))); + + gemfireProperties.setProperty("jmx-manager-hostname-for-clients", + resolveProperty(managerProperty("hostname-for-clients"), + (String) annotationAttributes.get("hostnameForClients"))); + + gemfireProperties.setProperty("jmx-manager-password-file", + resolveProperty(managerProperty("password-file"), + (String) annotationAttributes.get("passwordFile"))); + gemfireProperties.setProperty("jmx-manager-port", - resolvePort((Integer) annotationAttributes.get("port"), DEFAULT_JMX_MANAGER_PORT)); - gemfireProperties.setProperty("jmx-manager-start", annotationAttributes.get("start")); - gemfireProperties.setProperty("jmx-manager-update-rate", annotationAttributes.get("updateRate")); + resolvePort(resolveProperty(managerProperty("port"), + (Integer) annotationAttributes.get("port")), DEFAULT_JMX_MANAGER_PORT)); + + gemfireProperties.setProperty("jmx-manager-start", + resolveProperty(managerProperty("start"), (Boolean) annotationAttributes.get("start"))); + + gemfireProperties.setProperty("jmx-manager-update-rate", + resolveProperty(managerProperty("update-rate"), + (Integer) annotationAttributes.get("updateRate"))); return gemfireProperties.build(); } diff --git a/src/main/java/org/springframework/data/gemfire/config/annotation/McastConfiguration.java b/src/main/java/org/springframework/data/gemfire/config/annotation/McastConfiguration.java index e0aff2dd..b4f62c48 100644 --- a/src/main/java/org/springframework/data/gemfire/config/annotation/McastConfiguration.java +++ b/src/main/java/org/springframework/data/gemfire/config/annotation/McastConfiguration.java @@ -44,35 +44,43 @@ public class McastConfiguration extends EmbeddedServiceConfigurationSupport { public static final String DEFAULT_MCAST_FLOW_CONTROL = "1048576,0.25,5000"; /** - * {@inheritDoc} + * Returns the {@link EnableMcast} {@link java.lang.annotation.Annotation} {@link Class} type. + * + * @return the {@link EnableMcast} {@link java.lang.annotation.Annotation} {@link Class} type. + * @see org.springframework.data.gemfire.config.annotation.EnableMcast */ @Override protected Class getAnnotationType() { return EnableMcast.class; } - /** - * {@inheritDoc} - */ + /* (non-Javadoc) */ @Override protected Properties toGemFireProperties(Map annotationAttributes) { + PropertiesBuilder gemfireProperties = PropertiesBuilder.create(); gemfireProperties.unsetProperty("locators"); gemfireProperties.setPropertyIfNotDefault("mcast-address", - annotationAttributes.get("address"), DEFAULT_MCAST_ADDRESS); + resolveProperty(propertyName("mcast.address"), + (String) annotationAttributes.get("address")), DEFAULT_MCAST_ADDRESS); gemfireProperties.setPropertyIfNotDefault("mcast-flow-control", - annotationAttributes.get("flowControl"), DEFAULT_MCAST_FLOW_CONTROL); + resolveProperty(propertyName("mcast.flow-control"), + (String) annotationAttributes.get("flowControl")), DEFAULT_MCAST_FLOW_CONTROL); - gemfireProperties.setPropertyIfNotDefault("mcast-port", annotationAttributes.get("port"), DEFAULT_MCAST_PORT); + gemfireProperties.setPropertyIfNotDefault("mcast-port", + resolveProperty(propertyName("mcast.port"), + (Integer) annotationAttributes.get("port")), DEFAULT_MCAST_PORT); gemfireProperties.setPropertyIfNotDefault("mcast-recv-buffer-size", - annotationAttributes.get("receiveBufferSize"), DEFAULT_MCAST_RECEIVE_BUFFER_SIZE); + resolveProperty(propertyName("mcast.receive-buffer-size"), + (Integer) annotationAttributes.get("receiveBufferSize")), DEFAULT_MCAST_RECEIVE_BUFFER_SIZE); gemfireProperties.setPropertyIfNotDefault("mcast-send-buffer-size", - annotationAttributes.get("sendBufferSize"), DEFAULT_MCAST_SEND_BUFFER_SIZE); + resolveProperty(propertyName("mcast.send-buffer-size"), + (Integer) annotationAttributes.get("sendBufferSize")), DEFAULT_MCAST_SEND_BUFFER_SIZE); return gemfireProperties.build(); } diff --git a/src/main/java/org/springframework/data/gemfire/config/annotation/MemcachedServerConfiguration.java b/src/main/java/org/springframework/data/gemfire/config/annotation/MemcachedServerConfiguration.java index e8b1723c..cd3104a9 100644 --- a/src/main/java/org/springframework/data/gemfire/config/annotation/MemcachedServerConfiguration.java +++ b/src/main/java/org/springframework/data/gemfire/config/annotation/MemcachedServerConfiguration.java @@ -18,17 +18,20 @@ package org.springframework.data.gemfire.config.annotation; import java.util.Map; +import java.util.Optional; import java.util.Properties; +import org.springframework.context.annotation.ImportBeanDefinitionRegistrar; import org.springframework.data.gemfire.config.annotation.support.EmbeddedServiceConfigurationSupport; import org.springframework.data.gemfire.util.PropertiesBuilder; /** - * The MemcachedServerConfiguration class is a Spring {@link org.springframework.context.annotation.ImportBeanDefinitionRegistrar} - * that applies additional GemFire configuration by way of GemFire System properties to configure - * an embedded Memcached server. + * The {@link MemcachedServerConfiguration} class is a Spring {@link ImportBeanDefinitionRegistrar} that applies + * additional configuration using Pivotal GemFire/Apache Geode {@link Properties} to configure + * an embedded Memcached server in this cluster member. * * @author John Blum + * @see org.springframework.context.annotation.ImportBeanDefinitionRegistrar * @see org.springframework.data.gemfire.config.annotation.EnableMemcachedServer * @see org.springframework.data.gemfire.config.annotation.support.EmbeddedServiceConfigurationSupport * @since 1.9.0 @@ -37,17 +40,35 @@ public class MemcachedServerConfiguration extends EmbeddedServiceConfigurationSu protected static final int DEFAULT_MEMCACHED_SERVER_PORT = 11211; + /** + * Returns the {@link EnableMemcachedServer} {@link java.lang.annotation.Annotation} {@link Class} type. + * + * @return the {@link EnableMemcachedServer} {@link java.lang.annotation.Annotation} {@link Class} type. + * @see org.springframework.data.gemfire.config.annotation.EnableMemcachedServer + */ @Override protected Class getAnnotationType() { return EnableMemcachedServer.class; } + /* (non-Javadoc) */ @Override protected Properties toGemFireProperties(Map annotationAttributes) { - return PropertiesBuilder.create() - .setProperty("memcached-port", resolvePort((Integer) annotationAttributes.get("port"), - DEFAULT_MEMCACHED_SERVER_PORT)) - .setProperty("memcached-protocol", annotationAttributes.get("protocol")) - .build(); + + return Optional.of(resolveProperty(memcachedServiceProperty("enabled"), Boolean.TRUE)) + .filter(Boolean.TRUE::equals) + .map(enabled -> + + PropertiesBuilder.create() + .setProperty("memcached-port", + resolvePort(resolveProperty(memcachedServiceProperty("port"), + (Integer) annotationAttributes.get("port")), DEFAULT_MEMCACHED_SERVER_PORT)) + .setProperty("memcached-protocol", + resolveProperty(memcachedServiceProperty("protocol"), + EnableMemcachedServer.MemcachedProtocol.class, + (EnableMemcachedServer.MemcachedProtocol) annotationAttributes.get("protocol"))) + .build() + + ).orElseGet(Properties::new); } } diff --git a/src/main/java/org/springframework/data/gemfire/config/annotation/OffHeapConfiguration.java b/src/main/java/org/springframework/data/gemfire/config/annotation/OffHeapConfiguration.java index 886a8e28..e1f239b4 100644 --- a/src/main/java/org/springframework/data/gemfire/config/annotation/OffHeapConfiguration.java +++ b/src/main/java/org/springframework/data/gemfire/config/annotation/OffHeapConfiguration.java @@ -17,10 +17,14 @@ package org.springframework.data.gemfire.config.annotation; +import static java.util.Arrays.stream; +import static org.springframework.data.gemfire.util.ArrayUtils.nullSafeArray; + import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.Map; +import java.util.Optional; import java.util.Properties; import java.util.Set; @@ -33,6 +37,7 @@ import org.springframework.beans.factory.config.BeanFactoryPostProcessor; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.support.BeanDefinitionRegistry; +import org.springframework.context.annotation.ImportBeanDefinitionRegistrar; import org.springframework.core.type.AnnotationMetadata; import org.springframework.data.gemfire.GenericRegionFactoryBean; import org.springframework.data.gemfire.LocalRegionFactoryBean; @@ -40,22 +45,27 @@ import org.springframework.data.gemfire.PartitionedRegionFactoryBean; import org.springframework.data.gemfire.ReplicatedRegionFactoryBean; import org.springframework.data.gemfire.client.ClientRegionFactoryBean; import org.springframework.data.gemfire.config.annotation.support.EmbeddedServiceConfigurationSupport; -import org.springframework.data.gemfire.util.ArrayUtils; import org.springframework.data.gemfire.util.CollectionUtils; import org.springframework.data.gemfire.util.PropertiesBuilder; /** - * The OffHeapConfiguration class is a Spring {@link org.springframework.context.annotation.ImportBeanDefinitionRegistrar} - * capable of enabling GemFire cache {@link Region Regions} to use Off-Heap memory for data storage. + * The {@link OffHeapConfiguration} class is a Spring {@link ImportBeanDefinitionRegistrar} capable of + * enabling Pivotal GemFire/Apache Geode cache {@link Region Regions} to use Off-Heap memory for data storage. * * @author John Blum + * @see org.springframework.context.annotation.ImportBeanDefinitionRegistrar * @see org.springframework.data.gemfire.config.annotation.EnableOffHeap * @see org.springframework.data.gemfire.config.annotation.support.EmbeddedServiceConfigurationSupport * @since 1.9.0 */ public class OffHeapConfiguration extends EmbeddedServiceConfigurationSupport { - /* (non-Javadoc) */ + /** + * Returns the {@link EnableOffHeap} {@link java.lang.annotation.Annotation} {@link Class} type. + * + * @return the {@link EnableOffHeap} {@link java.lang.annotation.Annotation} {@link Class} type. + * @see org.springframework.data.gemfire.config.annotation.EnableOffHeap + */ @Override protected Class getAnnotationType() { return EnableOffHeap.class; @@ -66,10 +76,11 @@ public class OffHeapConfiguration extends EmbeddedServiceConfigurationSupport { protected void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, Map annotationAttributes, BeanDefinitionRegistry registry) { - BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition( - OffHeapBeanFactoryPostProcessor.class); + BeanDefinitionBuilder builder = + BeanDefinitionBuilder.genericBeanDefinition(OffHeapBeanFactoryPostProcessor.class); - builder.addConstructorArgValue(annotationAttributes.get("regionNames")); + builder.addConstructorArgValue(resolveProperty(cacheProperty("region-names"), + String[].class, (String[]) annotationAttributes.get("regionNames"))); registry.registerBeanDefinition(generateBeanName(OffHeapBeanFactoryPostProcessor.class), builder.getBeanDefinition()); @@ -78,17 +89,19 @@ public class OffHeapConfiguration extends EmbeddedServiceConfigurationSupport { /* (non-Javadoc) */ @Override protected Properties toGemFireProperties(Map annotationAttributes) { - PropertiesBuilder gemfireProperties = PropertiesBuilder.create(); - gemfireProperties.setProperty("off-heap-memory-size", annotationAttributes.get("memorySize")); - - return gemfireProperties.build(); + return PropertiesBuilder.create() + .setProperty("off-heap-memory-size", + resolveProperty(cacheProperty("off-heap-memory-size"), + (String) annotationAttributes.get("memorySize"))) + .build(); } + /* (non-Javadoc) */ @SuppressWarnings("unused") protected static class OffHeapBeanFactoryPostProcessor implements BeanFactoryPostProcessor { - protected static final Set REGION_FACTORY_BEAN_TYPES = new HashSet(5); + protected static final Set REGION_FACTORY_BEAN_TYPES = new HashSet<>(5); static { REGION_FACTORY_BEAN_TYPES.add(ClientRegionFactoryBean.class.getName()); @@ -101,7 +114,7 @@ public class OffHeapConfiguration extends EmbeddedServiceConfigurationSupport { private final Set regionNames; protected OffHeapBeanFactoryPostProcessor(String[] regionNames) { - this(CollectionUtils.asSet(ArrayUtils.nullSafeArray(regionNames, String.class))); + this(CollectionUtils.asSet(nullSafeArray(regionNames, String.class))); } protected OffHeapBeanFactoryPostProcessor(Set regionNames) { @@ -110,13 +123,14 @@ public class OffHeapConfiguration extends EmbeddedServiceConfigurationSupport { @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { - for (String beanName : beanFactory.getBeanDefinitionNames()) { - BeanDefinition bean = beanFactory.getBeanDefinition(beanName); - if (isTargetedRegionBean(beanName, bean, beanFactory)) { - bean.getPropertyValues().addPropertyValue("offHeap", true); - } - } + stream(nullSafeArray(beanFactory.getBeanDefinitionNames(), String.class)).forEach(beanName -> { + + Optional.ofNullable(beanFactory.getBeanDefinition(beanName)) + .filter(bean -> isTargetedRegionBean(beanName, bean, beanFactory)) + .ifPresent(bean -> + bean.getPropertyValues().addPropertyValue("offHeap", true)); + }); } boolean isTargetedRegionBean(String beanName, BeanDefinition bean, @@ -135,14 +149,17 @@ public class OffHeapConfiguration extends EmbeddedServiceConfigurationSupport { } Collection getBeanNames(String beanName, BeanDefinition bean, BeanFactory beanFactory) { - Collection beanNames = new HashSet(); + + Collection beanNames = new HashSet<>(); beanNames.add(beanName); + Collections.addAll(beanNames, beanFactory.getAliases(beanName)); PropertyValue regionName = bean.getPropertyValues().getPropertyValue("regionName"); if (regionName != null) { + Object regionNameValue = regionName.getValue(); if (regionNameValue != null) { diff --git a/src/main/java/org/springframework/data/gemfire/config/annotation/PeerCacheApplication.java b/src/main/java/org/springframework/data/gemfire/config/annotation/PeerCacheApplication.java index 97ecac58..fe61435d 100644 --- a/src/main/java/org/springframework/data/gemfire/config/annotation/PeerCacheApplication.java +++ b/src/main/java/org/springframework/data/gemfire/config/annotation/PeerCacheApplication.java @@ -35,10 +35,12 @@ import org.springframework.data.gemfire.support.GemfireBeanFactoryLocator; * instance in a Spring Data GemFire based application. * * @author John Blum + * @see org.apache.geode.cache.control.ResourceManager + * @see org.springframework.beans.factory.BeanFactory * @see org.springframework.context.annotation.Configuration * @see org.springframework.context.annotation.Import * @see org.springframework.data.gemfire.config.annotation.PeerCacheConfiguration - * @see org.apache.geode.cache.control.ResourceManager + * @see org.springframework.data.gemfire.support.GemfireBeanFactoryLocator * @since 1.9.0 */ @Target({ ElementType.ANNOTATION_TYPE, ElementType.TYPE}) @@ -53,14 +55,18 @@ public @interface PeerCacheApplication { /** * Indicates whether the "copy on read" is enabled for this cache. * - * Default is {@literal false}. + * Defaults to {@literal false}. + * + * Use {@literal spring.data.gemfire.cache.copy-on-read} property in {@literal application.properties}. */ boolean copyOnRead() default false; /** * Configures the percentage of heap at or above which the cache is considered in danger of becoming inoperable. * - * @see org.apache.geode.cache.control.ResourceManager#DEFAULT_CRITICAL_PERCENTAGE + * Defaults to {@link ResourceManager#DEFAULT_CRITICAL_PERCENTAGE}. + * + * Use {@literal spring.data.gemfire.cache.critical-heap-percentage} property in {@literal application.properties}. */ float criticalHeapPercentage() default ResourceManager.DEFAULT_CRITICAL_PERCENTAGE; @@ -69,7 +75,10 @@ public @interface PeerCacheApplication { * after it has been forced out of the distributed system by a network partition event or has otherwise been * shunned by other members. Use this property to enable the auto-reconnect behavior. * - * Default is {@literal false}. + * Defaults to {@literal false}. + * + * Use {@literal spring.data.gemfire.cache.peer.enable-auto-reconnect} property + * in {@literal application.properties}. */ boolean enableAutoReconnect() default false; @@ -77,34 +86,43 @@ public @interface PeerCacheApplication { * Configures the percentage of heap at or above which the eviction should begin on Regions configured * for HeapLRU eviction. * - * @see org.apache.geode.cache.control.ResourceManager#DEFAULT_EVICTION_PERCENTAGE + * Defaults to {@link ResourceManager#DEFAULT_EVICTION_PERCENTAGE}. + * + * Use {@literal spring.data.gemfire.cache.eviction-heap-percentage} property in {@literal application.properties}. */ float evictionHeapPercentage() default ResourceManager.DEFAULT_EVICTION_PERCENTAGE; /** - * Configures the list of GemFire Locators defining the cluster to which this GemFire cache data node - * should connect. + * Configures the list of Locators defining the cluster to which this Spring cache application will connect. + * + * Use {@literal spring.data.gemfire.cache.peer.locators} property in {@literal application.properties}. */ String locators() default ""; /** * Configures the length, in seconds, of distributed lock leases obtained by this cache. * - * Default is {@literal 120} seconds. + * Defaults to {@literal 120} seconds. + * + * Use {@literal spring.data.gemfire.cache.peer.lock-lease} property in {@literal application.properties}. */ int lockLease() default 120; /** * Configures the number of seconds a cache operation will wait to obtain a distributed lock lease. * - * Default is {@literal 60} seconds. + * Defaults to {@literal 60} seconds. + * + * Use {@literal spring.data.gemfire.cache.peer.lock-timeout} property in {@literal application.properties}. */ int lockTimeout() default 60; /** * Configures the log level used to output log messages at GemFire cache runtime. * - * Default is {@literal config}. + * Defaults to {@literal config}. + * + * Use {@literal spring.data.gemfire.cache.log-level} property in {@literal application.properties}. */ String logLevel() default PeerCacheConfiguration.DEFAULT_LOG_LEVEL; @@ -112,21 +130,28 @@ public @interface PeerCacheApplication { * Configures the frequency (in seconds) at which a message will be sent by the primary cache-server to all * the secondary cache-server nodes to remove the events which have already been dispatched from the queue. * - * Default is {@literal 1} second. + * Defaults to {@literal 1} second. + * + * Use {@literal spring.data.gemfire.cache.peer.message-sync-interval} property + * in {@literal application.properties}. */ int messageSyncInterval() default 1; /** * Configures the name of this GemFire member in the cluster (distributed system). * - * Default is {@literal SpringBasedPeerCacheApplication}. + * Defaults to {@literal SpringBasedPeerCacheApplication}. + * + * Use {@literal spring.data.gemfire.cache.name} property in {@literal application.properties}. */ String name() default PeerCacheConfiguration.DEFAULT_NAME; /** * Configures the number of seconds a cache get operation can spend searching for a value before it times out. * - * Default is {@literal 300} seconds. + * Defaults to {@literal 300} seconds, or 5 minutes. + * + * Use {@literal spring.data.gemfire.cache.peer.search-timeout} property in {@literal application.properties}. */ int searchTimeout() default 300; @@ -136,6 +161,8 @@ public @interface PeerCacheApplication { * created in a non-Spring managed, GemFire context. * * Defaults to {@literal false}. + * + * Use {@literal spring.data.gemfire.use-bean-factory-locator} property in {@literal application.properties}. */ boolean useBeanFactoryLocator() default false; @@ -143,7 +170,10 @@ public @interface PeerCacheApplication { * Configures whether this GemFire cache member node would pull it's configuration meta-data * from the cluster-based Cluster Configuration service. * - * Default is {@literal false}. + * Defaults to {@literal false}. + * + * Use {@literal spring.data.gemfire.cache.peer.use-cluster-configuration} property + * in {@literal application.properties}. */ boolean useClusterConfiguration() default false; diff --git a/src/main/java/org/springframework/data/gemfire/config/annotation/PeerCacheConfiguration.java b/src/main/java/org/springframework/data/gemfire/config/annotation/PeerCacheConfiguration.java index e1e534c1..a1e767b8 100644 --- a/src/main/java/org/springframework/data/gemfire/config/annotation/PeerCacheConfiguration.java +++ b/src/main/java/org/springframework/data/gemfire/config/annotation/PeerCacheConfiguration.java @@ -32,6 +32,7 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.type.AnnotationMetadata; import org.springframework.data.gemfire.CacheFactoryBean; +import org.springframework.util.StringUtils; /** * Spring {@link Configuration} class used to construct, configure and initialize a peer {@link Cache} instance @@ -139,16 +140,31 @@ public class PeerCacheConfiguration extends AbstractCacheConfiguration { Map peerCacheApplicationAttributes = importMetadata.getAnnotationAttributes(getAnnotationTypeName()); - setEnableAutoReconnect(Boolean.TRUE.equals(peerCacheApplicationAttributes.get("enableAutoReconnect"))); - setLockLease((Integer) peerCacheApplicationAttributes.get("lockLease")); - setLockTimeout((Integer) peerCacheApplicationAttributes.get("lockTimeout")); - setMessageSyncInterval((Integer) peerCacheApplicationAttributes.get("messageSyncInterval")); - setSearchTimeout((Integer) peerCacheApplicationAttributes.get("searchTimeout")); - setUseClusterConfiguration(Boolean.TRUE.equals(peerCacheApplicationAttributes.get("useClusterConfiguration"))); + setEnableAutoReconnect(resolveProperty(cachePeerProperty("enable-auto-reconnect"), + Boolean.TRUE.equals(peerCacheApplicationAttributes.get("enableAutoReconnect")))); + + setLockLease(resolveProperty(cachePeerProperty("lock-lease"), + (Integer) peerCacheApplicationAttributes.get("lockLease"))); + + setLockTimeout(resolveProperty(cachePeerProperty("lock-timeout"), + (Integer) peerCacheApplicationAttributes.get("lockTimeout"))); + + setMessageSyncInterval(resolveProperty(cachePeerProperty("message-sync-interval"), + (Integer) peerCacheApplicationAttributes.get("messageSyncInterval"))); + + setSearchTimeout(resolveProperty(cachePeerProperty("search-timeout"), + (Integer) peerCacheApplicationAttributes.get("searchTimeout"))); + + setUseClusterConfiguration(resolveProperty(cachePeerProperty("use-cluster-configuration"), + Boolean.TRUE.equals(peerCacheApplicationAttributes.get("useClusterConfiguration")))); Optional.ofNullable((String) peerCacheApplicationAttributes.get("locators")) .filter(PeerCacheConfiguration::hasValue) .ifPresent(this::setLocators); + + Optional.ofNullable(resolveProperty(cachePeerProperty("locators"), (String) null)) + .filter(StringUtils::hasText) + .ifPresent(this::setLocators); } } diff --git a/src/main/java/org/springframework/data/gemfire/config/annotation/RedisServerConfiguration.java b/src/main/java/org/springframework/data/gemfire/config/annotation/RedisServerConfiguration.java index 2ab1f9c4..bfdaa298 100644 --- a/src/main/java/org/springframework/data/gemfire/config/annotation/RedisServerConfiguration.java +++ b/src/main/java/org/springframework/data/gemfire/config/annotation/RedisServerConfiguration.java @@ -18,17 +18,20 @@ package org.springframework.data.gemfire.config.annotation; import java.util.Map; +import java.util.Optional; import java.util.Properties; +import org.springframework.context.annotation.ImportBeanDefinitionRegistrar; import org.springframework.data.gemfire.config.annotation.support.EmbeddedServiceConfigurationSupport; import org.springframework.data.gemfire.util.PropertiesBuilder; /** - * The RedisServerConfiguration class is a Spring {@link org.springframework.context.annotation.ImportBeanDefinitionRegistrar} - * that applies additional GemFire configuration by way of GemFire System properties to configure + * The {@link RedisServerConfiguration} class is a Spring {@link ImportBeanDefinitionRegistrar} that applies + * additional configuration using Pivotal GemFire/Apache Geode {@link Properties} to configure * an embedded Redis server. * * @author John Blum + * @see org.springframework.context.annotation.ImportBeanDefinitionRegistrar * @see org.springframework.data.gemfire.config.annotation.EnableRedisServer * @see org.springframework.data.gemfire.config.annotation.support.EmbeddedServiceConfigurationSupport * @since 1.9.0 @@ -37,16 +40,34 @@ public class RedisServerConfiguration extends EmbeddedServiceConfigurationSuppor protected static final int DEFAULT_REDIS_PORT = 6379; + /** + * Returns the {@link EnableRedisServer} {@link java.lang.annotation.Annotation} {@link Class} type. + * + * @return the {@link EnableRedisServer} {@link java.lang.annotation.Annotation} {@link Class} type. + * @see org.springframework.data.gemfire.config.annotation.EnableRedisServer + */ @Override protected Class getAnnotationType() { return EnableRedisServer.class; } + /* (non-Javadoc) */ @Override protected Properties toGemFireProperties(Map annotationAttributes) { - return PropertiesBuilder.create() - .setProperty("redis-bind-address", annotationAttributes.get("bindAddress")) - .setProperty("redis-port", resolvePort((Integer)annotationAttributes.get("port"), DEFAULT_REDIS_PORT)) - .build(); + + return Optional.ofNullable(resolveProperty(redisServiceProperty("enabled"), Boolean.TRUE)) + .filter(Boolean.TRUE::equals) + .map(enabled -> + + PropertiesBuilder.create() + .setProperty("redis-bind-address", + resolveProperty(redisServiceProperty("bind-address"), + (String) annotationAttributes.get("bindAddress"))) + .setProperty("redis-port", + resolvePort(resolveProperty(redisServiceProperty("port"), + (Integer) annotationAttributes.get("port")), DEFAULT_REDIS_PORT)) + .build() + + ).orElseGet(Properties::new); } } diff --git a/src/main/java/org/springframework/data/gemfire/config/annotation/SslConfiguration.java b/src/main/java/org/springframework/data/gemfire/config/annotation/SslConfiguration.java index f2cc930f..770c95b6 100644 --- a/src/main/java/org/springframework/data/gemfire/config/annotation/SslConfiguration.java +++ b/src/main/java/org/springframework/data/gemfire/config/annotation/SslConfiguration.java @@ -17,48 +17,102 @@ package org.springframework.data.gemfire.config.annotation; +import static java.util.Arrays.stream; +import static org.springframework.data.gemfire.util.ArrayUtils.nullSafeArray; + +import java.util.Arrays; import java.util.Map; import java.util.Properties; +import org.springframework.context.annotation.ImportBeanDefinitionRegistrar; import org.springframework.data.gemfire.config.annotation.support.EmbeddedServiceConfigurationSupport; import org.springframework.data.gemfire.util.PropertiesBuilder; -import org.springframework.util.Assert; +import org.springframework.util.ObjectUtils; /** - * The SslConfiguration class... + * The {@link SslConfiguration} class is a Spring {@link ImportBeanDefinitionRegistrar} that applies + * additional configuration using Pivotal GemFire/Apache Geode {@link Properties} to configure SSL. * * @author John Blum - * @since 1.0.0 + * @see org.springframework.context.annotation.ImportBeanDefinitionRegistrar + * @see org.springframework.data.gemfire.config.annotation.EnableSsl + * @see org.springframework.data.gemfire.config.annotation.support.EmbeddedServiceConfigurationSupport + * @since 1.9.0 */ public class SslConfiguration extends EmbeddedServiceConfigurationSupport { + /** + * Returns the {@link EnableSsl} {@link java.lang.annotation.Annotation} {@link Class} type. + * + * @return the {@link EnableSsl} {@link java.lang.annotation.Annotation} {@link Class} type. + * @see org.springframework.data.gemfire.config.annotation.EnableSsl + */ @Override protected Class getAnnotationType() { return EnableSsl.class; } + /* (non-Javadoc) */ @Override protected Properties toGemFireProperties(Map annotationAttributes) { - PropertiesBuilder gemfireProperties = new PropertiesBuilder(); + + PropertiesBuilder gemfireProperties = PropertiesBuilder.create(); EnableSsl.Component[] components = (EnableSsl.Component[]) annotationAttributes.get("components"); - Assert.notNull(components, "GemFire SSL enabled components cannot be null"); - - for (EnableSsl.Component component : components) { - gemfireProperties - .setProperty(String.format("%s-ssl-ciphers", component), annotationAttributes.get("ciphers")) - .setProperty(String.format("%s-ssl-enabled", component), Boolean.TRUE.toString()) - .setProperty(String.format("%s-ssl-keystore", component), annotationAttributes.get("keystore")) - .setProperty(String.format("%s-ssl-keystore-password", component), annotationAttributes.get("keystorePassword")) - .setProperty(String.format("%s-ssl-keystore-type", component), annotationAttributes.get("keystoreType")) - .setProperty(String.format("%s-ssl-protocols", component), annotationAttributes.get("protocols")) - .setProperty(String.format("%s-ssl-require-authentication", component), - Boolean.TRUE.equals(annotationAttributes.get("requireAuthentication"))) - .setProperty(String.format("%s-ssl-truststore", component), annotationAttributes.get("truststore")) - .setProperty(String.format("%s-ssl-truststore-password", component), annotationAttributes.get("truststorePassword")); + if (ObjectUtils.isEmpty(components)) { + logWarning("SSL will not be configured; No SSL enabled Components %s were specified", + Arrays.toString(EnableSsl.Component.values())); } + stream(nullSafeArray(components, EnableSsl.Component.class)).forEach(component -> + + gemfireProperties.setProperty(String.format("%s-ssl-ciphers", component), + resolveProperty(componentSslProperty(component.toString(), "ciphers"), + resolveProperty(sslProperty("ciphers"), + (String) annotationAttributes.get("ciphers")))) + + .setProperty(String.format("%s-ssl-enabled", component), + resolveProperty(componentSslProperty(component.toString(), "enabled"), + resolveProperty(sslProperty("enabled"), true))) + + .setProperty(String.format("%s-ssl-keystore", component), + resolveProperty(componentSslProperty(component.toString(), "keystore"), + resolveProperty(sslProperty("keystore"), + (String) annotationAttributes.get("keystore")))) + + .setProperty(String.format("%s-ssl-keystore-password", component), + resolveProperty(componentSslProperty(component.toString(), "keystore-password"), + resolveProperty(sslProperty("keystore-password"), + (String) annotationAttributes.get("keystorePassword")))) + + .setProperty(String.format("%s-ssl-keystore-type", component), + resolveProperty(componentSslProperty(component.toString(), "keystore-type"), + resolveProperty(sslProperty("keystore-type"), + (String) annotationAttributes.get("keystoreType")))) + + .setProperty(String.format("%s-ssl-protocols", component), + resolveProperty(componentSslProperty(component.toString(), "protocols"), + resolveProperty(sslProperty("protocols"), + (String) annotationAttributes.get("protocols")))) + + .setProperty(String.format("%s-ssl-require-authentication", component), + resolveProperty(componentSslProperty(component.toString(), "require-authentication"), + resolveProperty(sslProperty("require-authentication"), + Boolean.TRUE.equals(annotationAttributes.get("requireAuthentication"))))) + + .setProperty(String.format("%s-ssl-truststore", component), + resolveProperty(componentSslProperty(component.toString(), "truststore"), + resolveProperty(sslProperty("truststore"), + (String) annotationAttributes.get("truststore")))) + + .setProperty(String.format("%s-ssl-truststore-password", component), + resolveProperty(componentSslProperty(component.toString(), "truststore-password"), + resolveProperty(sslProperty("truststore-password"), + (String) annotationAttributes.get("truststorePassword")))) + + ); + return gemfireProperties.build(); } } diff --git a/src/main/java/org/springframework/data/gemfire/config/annotation/StatisticsConfiguration.java b/src/main/java/org/springframework/data/gemfire/config/annotation/StatisticsConfiguration.java index cc1434eb..c90c3537 100644 --- a/src/main/java/org/springframework/data/gemfire/config/annotation/StatisticsConfiguration.java +++ b/src/main/java/org/springframework/data/gemfire/config/annotation/StatisticsConfiguration.java @@ -20,15 +20,17 @@ package org.springframework.data.gemfire.config.annotation; import java.util.Map; import java.util.Properties; +import org.springframework.context.annotation.ImportBeanDefinitionRegistrar; import org.springframework.data.gemfire.config.annotation.support.EmbeddedServiceConfigurationSupport; import org.springframework.data.gemfire.util.PropertiesBuilder; /** - * The StatisticsConfiguration class is a Spring {@link org.springframework.context.annotation.ImportBeanDefinitionRegistrar} - * that applies additional GemFire/Geode configuration by way of GemFire/Geode System properties to configure - * GemFire/Geode Statistics. + * The {@link StatisticsConfiguration} class is a Spring {@link ImportBeanDefinitionRegistrar} that applies + * additional configuration using Pivotal GemFire/Apache Geode {@link Properties} to configure + * Pivotal GemFire/Apache Geode Statistics. * * @author John Blum + * @see org.springframework.context.annotation.ImportBeanDefinitionRegistrar * @see org.springframework.data.gemfire.config.annotation.EnableStatistics * @see org.springframework.data.gemfire.config.annotation.support.EmbeddedServiceConfigurationSupport * @since 1.9.0 @@ -41,7 +43,12 @@ public class StatisticsConfiguration extends EmbeddedServiceConfigurationSupport public static final int DEFAULT_ARCHIVE_FILE_SIZE_LIMIT = 0; public static final int DEFAULT_STATISTIC_SAMPLE_RATE = 1000; - /* (non-Javadoc) */ + /** + * Returns the {@link EnableStatistics} {@link java.lang.annotation.Annotation} {@link Class} type. + * + * @return the {@link EnableStatistics} {@link java.lang.annotation.Annotation} {@link Class} type. + * @see org.springframework.data.gemfire.config.annotation.EnableStatistics + */ @Override protected Class getAnnotationType() { return EnableStatistics.class; @@ -50,23 +57,31 @@ public class StatisticsConfiguration extends EmbeddedServiceConfigurationSupport /* (non-Javadoc) */ @Override protected Properties toGemFireProperties(Map annotationAttributes) { + PropertiesBuilder gemfireProperties = new PropertiesBuilder(); - gemfireProperties.setProperty("statistic-sampling-enabled", true); + gemfireProperties.setProperty("statistic-sampling-enabled", + resolveProperty(statsProperty("sampling-enabled"), true)); gemfireProperties.setPropertyIfNotDefault("archive-disk-space-limit", - annotationAttributes.get("archiveDiskSpaceLimit"), DEFAULT_ARCHIVE_DISK_SPACE_LIMIT); + resolveProperty(statsProperty("archive-disk-space-limit"), + (Integer) annotationAttributes.get("archiveDiskSpaceLimit")), DEFAULT_ARCHIVE_DISK_SPACE_LIMIT); + + gemfireProperties.setProperty("statistic-archive-file", + resolveProperty(statsProperty("archive-file"), + (String) annotationAttributes.get("archiveFile"))); gemfireProperties.setPropertyIfNotDefault("archive-file-size-limit", - annotationAttributes.get("archiveFileSizeLimit"), DEFAULT_ARCHIVE_FILE_SIZE_LIMIT); + resolveProperty(statsProperty("archive-file-size-limit"), + (Integer) annotationAttributes.get("archiveFileSizeLimit")), DEFAULT_ARCHIVE_FILE_SIZE_LIMIT); gemfireProperties.setProperty("enable-time-statistics", - Boolean.TRUE.equals(annotationAttributes.get("enableTimeStatistics"))); - - gemfireProperties.setProperty("statistic-archive-file", annotationAttributes.get("archiveFile")); + resolveProperty(statsProperty("enable-time-statistics"), + Boolean.TRUE.equals(annotationAttributes.get("enableTimeStatistics")))); gemfireProperties.setPropertyIfNotDefault("statistic-sample-rate", - annotationAttributes.get("sampleRate"), DEFAULT_STATISTIC_SAMPLE_RATE); + resolveProperty(statsProperty("sample-rate"), + (Long) annotationAttributes.get("sampleRate")), DEFAULT_STATISTIC_SAMPLE_RATE); return gemfireProperties.build(); } diff --git a/src/main/java/org/springframework/data/gemfire/config/annotation/support/AbstractAnnotationConfigSupport.java b/src/main/java/org/springframework/data/gemfire/config/annotation/support/AbstractAnnotationConfigSupport.java index 7cff11c2..5bff35ec 100644 --- a/src/main/java/org/springframework/data/gemfire/config/annotation/support/AbstractAnnotationConfigSupport.java +++ b/src/main/java/org/springframework/data/gemfire/config/annotation/support/AbstractAnnotationConfigSupport.java @@ -17,22 +17,30 @@ package org.springframework.data.gemfire.config.annotation.support; +import static org.springframework.data.gemfire.util.RuntimeExceptionFactory.newIllegalArgumentException; import static org.springframework.data.gemfire.util.RuntimeExceptionFactory.newIllegalStateException; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; 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.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.EnvironmentAware; import org.springframework.context.expression.BeanFactoryAccessor; import org.springframework.context.expression.EnvironmentAccessor; import org.springframework.context.expression.MapAccessor; +import org.springframework.core.env.Environment; import org.springframework.expression.EvaluationContext; import org.springframework.expression.spel.support.StandardEvaluationContext; import org.springframework.expression.spel.support.StandardTypeConverter; @@ -49,22 +57,31 @@ import org.springframework.util.StringUtils; * @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.context.EnvironmentAware + * @see org.springframework.context.expression.BeanFactoryAccessor + * @see org.springframework.context.expression.EnvironmentAccessor + * @see org.springframework.core.env.Environment * @see org.springframework.expression.EvaluationContext * @since 1.9.0 */ @SuppressWarnings("unused") public abstract class AbstractAnnotationConfigSupport - implements BeanClassLoaderAware, BeanFactoryAware, InitializingBean { + implements BeanClassLoaderAware, BeanFactoryAware, EnvironmentAware { + + protected static final String SPRING_DATA_GEMFIRE_PROPERTY_PREFIX = "spring.data.gemfire."; private BeanFactory beanFactory; private ClassLoader beanClassLoader; - private EvaluationContext evaluationContext; + private Environment environment; + + private final EvaluationContext evaluationContext; + + private final Log log; /** * Determines whether the given {@link Object} has value. The {@link Object} is valuable @@ -99,19 +116,38 @@ public abstract class AbstractAnnotationConfigSupport return StringUtils.hasText(value); } - @Override - public void afterPropertiesSet() throws Exception { - this.evaluationContext = newEvaluationContext(); + /** + * Constructs a new instance of {@link AbstractAnnotationConfigSupport}. + * + * @see #AbstractAnnotationConfigSupport(BeanFactory) + */ + public AbstractAnnotationConfigSupport() { + this(null); + } + + /** + * Constructs a new instance of {@link AbstractAnnotationConfigSupport}. + * + * @param beanFactory reference to the Spring {@link BeanFactory}. + * @see org.springframework.beans.factory.BeanFactory + * @see #newEvaluationContext(BeanFactory) + */ + public AbstractAnnotationConfigSupport(BeanFactory beanFactory) { + this.evaluationContext = newEvaluationContext(beanFactory); + this.log = newLog(); } /** * Constructs, configures and initializes a new instance of an {@link EvaluationContext}. * + * @param beanFactory reference to the Spring {@link BeanFactory}. * @return a new {@link EvaluationContext}. + * @see org.springframework.beans.factory.BeanFactory * @see org.springframework.expression.EvaluationContext * @see #beanFactory() */ - protected EvaluationContext newEvaluationContext() { + protected EvaluationContext newEvaluationContext(BeanFactory beanFactory) { + StandardEvaluationContext evaluationContext = new StandardEvaluationContext(); evaluationContext.addPropertyAccessor(new BeanFactoryAccessor()); @@ -119,15 +155,37 @@ public abstract class AbstractAnnotationConfigSupport 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))); + configureTypeConverter(evaluationContext, beanFactory); return evaluationContext; } + /* (non-Javadoc) */ + private void configureTypeConverter(EvaluationContext evaluationContext, BeanFactory beanFactory) { + + Optional.ofNullable(evaluationContext) + .filter(evalContext -> evalContext instanceof StandardEvaluationContext) + .ifPresent(evalContext -> + Optional.ofNullable(beanFactory) + .filter(it -> it instanceof ConfigurableBeanFactory) + .map(it -> ((ConfigurableBeanFactory) it).getConversionService()) + .ifPresent(conversionService -> + ((StandardEvaluationContext) evalContext).setTypeConverter( + new StandardTypeConverter(conversionService))) + ); + } + + /** + * 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()); + } + /** * Returns the cache application {@link java.lang.annotation.Annotation} type pertaining to this configuration. * @@ -186,6 +244,7 @@ public abstract class AbstractAnnotationConfigSupport @Override public void setBeanFactory(BeanFactory beanFactory) throws BeansException { this.beanFactory = beanFactory; + configureTypeConverter(evaluationContext(), beanFactory); } /** @@ -200,6 +259,28 @@ public abstract class AbstractAnnotationConfigSupport .orElseThrow(() -> newIllegalStateException("BeanFactory is required")); } + /** + * Sets a reference to the Spring {@link Environment}. + * + * @param environment Spring {@link Environment}. + * @see org.springframework.context.EnvironmentAware#setEnvironment(Environment) + * @see org.springframework.core.env.Environment + */ + @Override + public void setEnvironment(Environment environment) { + this.environment = environment; + } + + /** + * Returns a reference to the Spring {@link Environment}. + * + * @return a reference to the Spring {@link Environment}. + * @see org.springframework.core.env.Environment + */ + protected Environment environment() { + return this.environment; + } + /** * * @return @@ -208,6 +289,116 @@ public abstract class AbstractAnnotationConfigSupport return this.evaluationContext; } + /** + * Returns a reference to the {@link Log} used by this class to log {@link String messages}. + * + * @return a reference to the {@link Log} used by this class to log {@link String messages}. + * @see org.apache.commons.logging.Log + */ + protected Log getLog() { + return this.log; + } + + /** + * 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 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 message) { + Optional.ofNullable(getLog()) + .filter(Log::isInfoEnabled) + .ifPresent(log -> log.info(message.get())); + } + + /** + * Logs the {@link String message} formatted with the array of {@link Object arguments} at warn level. + * + * @param message {@link String} containing the message to log. + * @param args array of {@link Object arguments} used to format the {@code message}. + * @see #logWarning(Supplier) + */ + protected void logWarning(String message, Object... args) { + logWarning(() -> String.format(message, args)); + } + + /** + * Logs the {@link String message} supplied by the given {@link Supplier} at warning level. + * + * @param message {@link Supplier} containing the {@link String message} and arguments to log. + * @see org.apache.commons.logging.Log#isWarnEnabled() + * @see org.apache.commons.logging.Log#warn(Object) + * @see #getLog() + */ + protected void logWarning(Supplier message) { + Optional.ofNullable(getLog()) + .filter(Log::isWarnEnabled) + .ifPresent(log -> log.info(message.get())); + } + + /** + * Logs the {@link String message} formatted with the array of {@link Object arguments} at error level. + * + * @param message {@link String} containing the message to log. + * @param args array of {@link Object arguments} used to format the {@code message}. + * @see #logError(Supplier) + */ + protected void logError(String message, Object... args) { + logError(() -> String.format(message, args)); + } + + /** + * Logs the {@link String message} supplied by the given {@link Supplier} at error level. + * + * @param message {@link Supplier} containing the {@link String message} and arguments to log. + * @see org.apache.commons.logging.Log#isErrorEnabled() + * @see org.apache.commons.logging.Log#error(Object) + * @see #getLog() + */ + protected void logError(Supplier message) { + Optional.ofNullable(getLog()) + .filter(Log::isWarnEnabled) + .ifPresent(log -> log.info(message.get())); + } + /** * Registers the {@link AbstractBeanDefinition} with the {@link BeanDefinitionRegistry} using a generated bean name. * @@ -246,4 +437,297 @@ public abstract class AbstractAnnotationConfigSupport return beanDefinition; } + + /* (non-Javadoc) */ + protected List arrayOfPropertyNamesFor(String propertyNamePrefix) { + return arrayOfPropertyNamesFor(propertyNamePrefix, null); + } + + /* (non-Javadoc) */ + protected List arrayOfPropertyNamesFor(String propertyNamePrefix, String propertyNameSuffix) { + + List propertyNames = new ArrayList<>(); + + boolean found = true; + + for (int index = 0; (found && index < Integer.MAX_VALUE); index++) { + + String propertyName = asArrayProperty(propertyNamePrefix, index, propertyNameSuffix); + + found = environment().containsProperty(propertyName); + + if (found) { + propertyNames.add(propertyName); + } + } + + return propertyNames; + } + + /* (non-Javadoc) */ + protected String asArrayProperty(String propertyNamePrefix, int index, String propertyNameSuffix) { + return String.format("%1$s[%2$d]%3$s", propertyNamePrefix, index, + Optional.ofNullable(propertyNamePrefix).filter(StringUtils::hasText).map("."::concat).orElse("")); + } + + /* (non-Javadoc) */ + protected String cacheProperty(String propertyNameSuffix) { + return String.format("%1$s%2$s", propertyName("cache."), propertyNameSuffix); + } + + /* (non-Javadoc) */ + protected String cacheClientProperty(String propertyNameSuffix) { + return String.format("%1$s%2$s", propertyName("cache.client."), propertyNameSuffix); + } + + /* (non-Javadoc) */ + protected String cachePeerProperty(String propertyNameSuffix) { + return String.format("%1$s%2$s", propertyName("cache.peer."), propertyNameSuffix); + } + + /* (non-Javadoc) */ + protected String cacheServerProperty(String propertyNameSuffix) { + return String.format("%1$s%2$s", propertyName("cache.server."), propertyNameSuffix); + } + + /* (non-Javadoc) */ + protected String namedCacheServerProperty(String name, String propertyNameSuffix) { + return String.format("%1$s%2$s.%3$s", propertyName("cache.server."), name, propertyNameSuffix); + } + + /* (non-Javadoc) */ + protected String diskStoreProperty(String propertyNameSuffix) { + return String.format("%1$s%2$s", propertyName("disk.store."), propertyNameSuffix); + } + + /* (non-Javadoc) */ + protected String namedDiskStoreProperty(String name, String propertyNameSuffix) { + return String.format("%1$s%2$s.%3$s", propertyName("disk.store."), name, propertyNameSuffix); + } + + /* (non-Javadoc) */ + protected String locatorProperty(String propertyNameSuffix) { + return String.format("%1$s%2$s", propertyName("locator."), propertyNameSuffix); + } + + /* (non-Javadoc) */ + protected String loggingProperty(String propertyNameSuffix) { + return String.format("%1$s%2$s", propertyName("logging."), propertyNameSuffix); + } + + /* (non-Javadoc) */ + protected String managerProperty(String propertyNameSuffix) { + return String.format("%1$s%2$s", propertyName("manager."), propertyNameSuffix); + } + + /* (non-Javadoc) */ + protected String pdxProperty(String propertyNameSuffix) { + return String.format("%1$s%2$s", propertyName("pdx."), propertyNameSuffix); + } + + /* (non-Javadoc) */ + protected String poolProperty(String propertyNameSuffix) { + return String.format("%1$s%2$s", propertyName("pool."), propertyNameSuffix); + } + + /* (non-Javadoc) */ + protected String namedPoolProperty(String name, String propertyNameSuffix) { + return String.format("%1$s%2$s.%3$s", propertyName("pool."), name, propertyNameSuffix); + } + + /* (non-Javadoc) */ + protected String securityProperty(String propertyNameSuffix) { + return String.format("%1$s%2$s", propertyName("security."), propertyNameSuffix); + } + + /* (non-Javadoc) */ + protected String sslProperty(String propertyNameSuffix) { + return String.format("%1$s%2$s", securityProperty("ssl."), propertyNameSuffix); + } + + /* (non-Javadoc) */ + protected String componentSslProperty(String component, String propertyNameSuffix) { + return String.format("%1$s%2$s.%3$s", securityProperty("ssl."), + component, propertyNameSuffix); + } + + /* (non-Javadoc) */ + protected String statsProperty(String propertyNameSuffix) { + return String.format("%1$s%2$s", propertyName("stats."), propertyNameSuffix); + } + + /* (non-Javadoc) */ + protected String serviceProperty(String propertyNameSuffix) { + return String.format("%1$s%2$s", propertyName("service."), propertyNameSuffix); + } + + /* (non-Javadoc) */ + protected String redisServiceProperty(String propertyNameSuffix) { + return String.format("%1$s%2$s", serviceProperty("redis."), propertyNameSuffix); + } + + /* (non-Javadoc) */ + protected String memcachedServiceProperty(String propertyNameSuffix) { + return String.format("%1$s%2$s", serviceProperty("memcached."), propertyNameSuffix); + } + + /* (non-Javadoc) */ + protected String httpServiceProperty(String propertyNameSuffix) { + return String.format("%1$s%2$s", serviceProperty("http."), propertyNameSuffix); + } + + /** + * Returns the fully-qualified {@link String property name}. + * + * The fully qualified {@link String property name} consists of the {@link String property name} + * concatenated with the {@code propertyNameSuffix}. + * + * @param propertyNameSuffix {@link String} containing the property name suffix + * concatenated with the {@link String base property name}. + * @return the fully-qualified {@link String property name}. + * @see java.lang.String + */ + protected String propertyName(String propertyNameSuffix) { + return String.format("%1$s%2$s", SPRING_DATA_GEMFIRE_PROPERTY_PREFIX, propertyNameSuffix); + } + + /** + * Resolves the value for the given property identified by {@link String name} from the Spring {@link Environment} + * as an instance of the specified {@link Class type}. + * + * @param {@link Class} type of the {@code propertyName property's} assigned value. + * @param propertyName {@link String} containing the name of the required property to resolve. + * @param type {@link Class} type of the property's assigned value. + * @return the assigned value of the {@link String named} property. + * @throws IllegalArgumentException if the property has not been assigned a value. + * For {@link String} values, this also means the value cannot be {@link String#isEmpty() empty}. + * For non-{@link String} values, this means the value must not be {@literal null}. + * @see #resolveProperty(String, Class, Object) + */ + protected T requireProperty(String propertyName, Class type) { + + return Optional.of(propertyName) + .map(it -> resolveProperty(propertyName, type, null)) + .filter(Objects::nonNull) + .filter(value -> !(value instanceof String) || StringUtils.hasText((String) value)) + .orElseThrow(() -> newIllegalArgumentException("Property [%s] is required", propertyName)); + } + + /** + * Attempts to resolve the property with the given {@link String name} from the Spring {@link Environment} + * as a {@link Boolean}. + * + * @param propertyName {@link String name} of the property to resolve. + * @param defaultValue default value to return if the property is not defined or not set. + * @return the value of the property identified by {@link String name} or default value if the property + * is not defined or not set. + * @see #resolveProperty(String, Class, Object) + */ + protected Boolean resolveProperty(String propertyName, Boolean defaultValue) { + return resolveProperty(propertyName, Boolean.class, defaultValue); + } + + /** + * Attempts to resolve the property with the given {@link String name} from the Spring {@link Environment} + * as an {@link Double}. + * + * @param propertyName {@link String name} of the property to resolve. + * @param defaultValue default value to return if the property is not defined or not set. + * @return the value of the property identified by {@link String name} or default value if the property + * is not defined or not set. + * @see #resolveProperty(String, Class, Object) + */ + protected Double resolveProperty(String propertyName, Double defaultValue) { + return resolveProperty(propertyName, Double.class, defaultValue); + } + + /** + * Attempts to resolve the property with the given {@link String name} from the Spring {@link Environment} + * as an {@link Float}. + * + * @param propertyName {@link String name} of the property to resolve. + * @param defaultValue default value to return if the property is not defined or not set. + * @return the value of the property identified by {@link String name} or default value if the property + * is not defined or not set. + * @see #resolveProperty(String, Class, Object) + */ + protected Float resolveProperty(String propertyName, Float defaultValue) { + return resolveProperty(propertyName, Float.class, defaultValue); + } + + /** + * Attempts to resolve the property with the given {@link String name} from the Spring {@link Environment} + * as an {@link Integer}. + * + * @param propertyName {@link String name} of the property to resolve. + * @param defaultValue default value to return if the property is not defined or not set. + * @return the value of the property identified by {@link String name} or default value if the property + * is not defined or not set. + * @see #resolveProperty(String, Class, Object) + */ + protected Integer resolveProperty(String propertyName, Integer defaultValue) { + return resolveProperty(propertyName, Integer.class, defaultValue); + } + + /** + * Attempts to resolve the property with the given {@link String name} from the Spring {@link Environment} + * as a {@link Long}. + * + * @param propertyName {@link String name} of the property to resolve. + * @param defaultValue default value to return if the property is not defined or not set. + * @return the value of the property identified by {@link String name} or default value if the property + * is not defined or not set. + * @see #resolveProperty(String, Class, Object) + */ + protected Long resolveProperty(String propertyName, Long defaultValue) { + return resolveProperty(propertyName, Long.class, defaultValue); + } + + /** + * Attempts to resolve the property with the given {@link String name} from the Spring {@link Environment} + * as a {@link String}. + * + * @param propertyName {@link String name} of the property to resolve. + * @param defaultValue default value to return if the property is not defined or not set. + * @return the value of the property identified by {@link String name} or default value if the property + * is not defined or not set. + * @see #resolveProperty(String, Class, Object) + */ + protected String resolveProperty(String propertyName, String defaultValue) { + return resolveProperty(propertyName, String.class, defaultValue); + } + + /** + * Attempts to resolve the property with the given {@link String name} from the Spring {@link Environment}. + * + * @param {@link Class} type of the property value. + * @param propertyName {@link String name} of the property to resolve. + * @param targetType {@link Class} type of the property's value. + * @return the value of the property identified by {@link String name} or {@literal null} if the property + * is not defined or not set. + * @see #resolveProperty(String, Class, Object) + */ + protected T resolveProperty(String propertyName, Class targetType) { + return resolveProperty(propertyName, targetType, null); + } + + /** + * Attempts to resolve the property with the given {@link String name} from the Spring {@link Environment}. + * + * @param {@link Class} type of the property value. + * @param propertyName {@link String name} of the property to resolve. + * @param targetType {@link Class} type of the property's value. + * @param defaultValue default value to return if the property is not defined or not set. + * @return the value of the property identified by {@link String name} or default value if the property + * is not defined or not set. + * @see #environment() + */ + protected T resolveProperty(String propertyName, Class targetType, T defaultValue) { + + return Optional.ofNullable(environment()) + .filter(environment -> environment.containsProperty(propertyName)) + .map(environment -> environment.getProperty(environment.resolveRequiredPlaceholders(propertyName), + targetType, defaultValue)) + .orElse(defaultValue); + } } diff --git a/src/main/java/org/springframework/data/gemfire/server/CacheServerFactoryBean.java b/src/main/java/org/springframework/data/gemfire/server/CacheServerFactoryBean.java index 4a2f822b..c46d758a 100644 --- a/src/main/java/org/springframework/data/gemfire/server/CacheServerFactoryBean.java +++ b/src/main/java/org/springframework/data/gemfire/server/CacheServerFactoryBean.java @@ -64,6 +64,7 @@ public class CacheServerFactoryBean extends AbstractFactoryBeanSupport implements FactoryBean, - BeanClassLoaderAware, BeanFactoryAware, BeanNameAware { +@SuppressWarnings("unused") +public abstract class AbstractFactoryBeanSupport + implements FactoryBean, BeanClassLoaderAware, BeanFactoryAware, BeanNameAware { protected static final boolean DEFAULT_SINGLETON = true; @@ -49,10 +52,19 @@ public abstract class AbstractFactoryBeanSupport implements FactoryBean, private BeanFactory beanFactory; - private final Log log = newLog(); + private final Log log; private String beanName; + /** + * Constructs a new instance of {@link AbstractFactoryBeanSupport} and initialized the logger. + * + * @see #newLog() + */ + protected AbstractFactoryBeanSupport() { + this.log = newLog(); + } + /** * Constructs a new instance of {@link Log} to log statements printed by Spring Data GemFire/Geode. * diff --git a/src/test/java/org/springframework/data/gemfire/GemfireTemplateQueriesOnGroupedPooledClientCacheRegionsIntegrationTests.java b/src/test/java/org/springframework/data/gemfire/GemfireTemplateQueriesOnGroupedPooledClientCacheRegionsIntegrationTests.java index ffed594d..bf13b3ce 100644 --- a/src/test/java/org/springframework/data/gemfire/GemfireTemplateQueriesOnGroupedPooledClientCacheRegionsIntegrationTests.java +++ b/src/test/java/org/springframework/data/gemfire/GemfireTemplateQueriesOnGroupedPooledClientCacheRegionsIntegrationTests.java @@ -54,7 +54,7 @@ import org.springframework.data.gemfire.support.ConnectionEndpointList; import org.springframework.data.gemfire.test.support.ClientServerIntegrationTestsSupport; import org.springframework.data.gemfire.util.PropertiesBuilder; import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.test.context.junit4.SpringRunner; import lombok.Data; import lombok.NonNull; @@ -75,11 +75,15 @@ import lombok.RequiredArgsConstructor; * with the data of interest are targeted. * * @author John Blum + * @see org.junit.Test + * @see org.junit.runner.RunWith * @see org.springframework.data.gemfire.GemfireTemplate + * @see org.springframework.test.context.ContextConfiguration + * @see org.springframework.test.context.junit4.SpringRunner * @see Repository queries on client Regions associated with a Pool configured with a specified server group can lead to a RegionNotFoundException. * @since 1.9.0 */ -@RunWith(SpringJUnit4ClassRunner.class) +@RunWith(SpringRunner.class) @ContextConfiguration(classes = GemfireTemplateQueriesOnGroupedPooledClientCacheRegionsIntegrationTests.GemFireClientCacheConfiguration.class) @SuppressWarnings("unused") @@ -147,6 +151,7 @@ public class GemfireTemplateQueriesOnGroupedPooledClientCacheRegionsIntegrationT static class GemFireClientCacheConfiguration { Properties gemfireProperties() { + return PropertiesBuilder.create() .setProperty("name", applicationName()) .setProperty("log-level", logLevel()) @@ -163,6 +168,7 @@ public class GemfireTemplateQueriesOnGroupedPooledClientCacheRegionsIntegrationT @Bean ClientCacheFactoryBean gemfireCache() { + ClientCacheFactoryBean gemfireCache = new ClientCacheFactoryBean(); gemfireCache.setClose(true); @@ -174,6 +180,7 @@ public class GemfireTemplateQueriesOnGroupedPooledClientCacheRegionsIntegrationT @Bean(name = "ServerOnePool") PoolFactoryBean serverOnePool() { + PoolFactoryBean serverOnePool = new PoolFactoryBean(); serverOnePool.setMaxConnections(2); @@ -188,6 +195,7 @@ public class GemfireTemplateQueriesOnGroupedPooledClientCacheRegionsIntegrationT @Bean(name = "ServerTwoPool") PoolFactoryBean serverTwoPool() { + PoolFactoryBean serverOnePool = new PoolFactoryBean(); serverOnePool.setMaxConnections(2); @@ -248,6 +256,7 @@ public class GemfireTemplateQueriesOnGroupedPooledClientCacheRegionsIntegrationT static abstract class AbstractGemFireCacheServerConfiguration { Properties gemfireProperties() { + return PropertiesBuilder.create() .setProperty("name", applicationName()) .setProperty("mcast-port", "0") @@ -275,6 +284,7 @@ public class GemfireTemplateQueriesOnGroupedPooledClientCacheRegionsIntegrationT @Bean CacheFactoryBean gemfireCache() { + CacheFactoryBean gemfireCache = new CacheFactoryBean(); gemfireCache.setClose(true); @@ -284,11 +294,12 @@ public class GemfireTemplateQueriesOnGroupedPooledClientCacheRegionsIntegrationT } @Bean - CacheServerFactoryBean gemfireCacheServer(Cache gemfireCache) { + CacheServerFactoryBean gemfireCacheServer(GemFireCache gemfireCache) { + CacheServerFactoryBean gemfireCacheServer = new CacheServerFactoryBean(); gemfireCacheServer.setAutoStartup(true); - gemfireCacheServer.setCache(gemfireCache); + gemfireCacheServer.setCache((Cache) gemfireCache); gemfireCacheServer.setMaxTimeBetweenPings(Long.valueOf(TimeUnit.SECONDS.toMillis(60)).intValue()); gemfireCacheServer.setPort(cacheServerPort()); @@ -336,7 +347,8 @@ public class GemfireTemplateQueriesOnGroupedPooledClientCacheRegionsIntegrationT } @Bean(name = "Cats") - LocalRegionFactoryBean catsRegion(Cache gemfireCache) { + LocalRegionFactoryBean catsRegion(GemFireCache gemfireCache) { + LocalRegionFactoryBean catsRegion = new LocalRegionFactoryBean(); catsRegion.setCache(gemfireCache); @@ -381,7 +393,8 @@ public class GemfireTemplateQueriesOnGroupedPooledClientCacheRegionsIntegrationT } @Bean(name = "Dogs") - LocalRegionFactoryBean dogsRegion(Cache gemfireCache) { + LocalRegionFactoryBean dogsRegion(GemFireCache gemfireCache) { + LocalRegionFactoryBean dogsRegion = new LocalRegionFactoryBean(); dogsRegion.setCache(gemfireCache); diff --git a/src/test/java/org/springframework/data/gemfire/config/annotation/AbstractCacheConfigurationUnitTests.java b/src/test/java/org/springframework/data/gemfire/config/annotation/AbstractCacheConfigurationUnitTests.java index d843fe74..80844876 100644 --- a/src/test/java/org/springframework/data/gemfire/config/annotation/AbstractCacheConfigurationUnitTests.java +++ b/src/test/java/org/springframework/data/gemfire/config/annotation/AbstractCacheConfigurationUnitTests.java @@ -76,20 +76,24 @@ public class AbstractCacheConfigurationUnitTests { } @SuppressWarnings("unchecked") - protected T invokeMethod(Object obj, String methodName) throws Exception { + private T invokeMethod(Object obj, String methodName) throws Exception { + MethodInvoker methodInvoker = new MethodInvoker(); + methodInvoker.setTargetObject(obj); methodInvoker.setTargetMethod(methodName); methodInvoker.prepare(); + return (T) methodInvoker.invoke(); } @Test public void configurePdxWhenEnablePdxIsConfigured() { + AnnotationMetadata mockAnnotationMetadata = mock(AnnotationMetadata.class); PdxSerializer mockPdxSerializer = mock(PdxSerializer.class); - Map annotationAttributes = new HashMap(5); + Map annotationAttributes = new HashMap<>(5); annotationAttributes.put("diskStoreName", "BlockDiskStore"); annotationAttributes.put("ignoreUnreadFields", Boolean.FALSE); @@ -98,19 +102,18 @@ public class AbstractCacheConfigurationUnitTests { annotationAttributes.put("serializerBeanName", "MockPdxSerializer"); when(mockAnnotationMetadata.hasAnnotation(eq(EnablePdx.class.getName()))).thenReturn(true); - when(mockAnnotationMetadata.getAnnotationAttributes(eq(EnablePdx.class.getName()))) - .thenReturn(annotationAttributes); + when(mockAnnotationMetadata.getAnnotationAttributes(eq(EnablePdx.class.getName()))).thenReturn(annotationAttributes); when(mockBeanFactory.containsBean(eq("MockPdxSerializer"))).thenReturn(true); when(mockBeanFactory.getBean(eq("MockPdxSerializer"), eq(PdxSerializer.class))).thenReturn(mockPdxSerializer); cacheConfiguration.setBeanFactory(mockBeanFactory); cacheConfiguration.configurePdx(mockAnnotationMetadata); - assertThat(cacheConfiguration.pdxDiskStoreName()).isEqualTo("BlockDiskStore"); - assertThat(cacheConfiguration.pdxIgnoreUnreadFields()).isFalse(); - assertThat(cacheConfiguration.pdxPersistent()).isTrue(); - assertThat(cacheConfiguration.pdxReadSerialized()).isTrue(); - assertThat(cacheConfiguration.pdxSerializer()).isEqualTo(mockPdxSerializer); + assertThat(cacheConfiguration.getPdxDiskStoreName()).isEqualTo("BlockDiskStore"); + assertThat(cacheConfiguration.getPdxIgnoreUnreadFields()).isFalse(); + assertThat(cacheConfiguration.getPdxPersistent()).isTrue(); + assertThat(cacheConfiguration.getPdxReadSerialized()).isTrue(); + assertThat(cacheConfiguration.getPdxSerializer()).isEqualTo(mockPdxSerializer); verify(mockAnnotationMetadata, times(1)).hasAnnotation(eq(EnablePdx.class.getName())); verify(mockAnnotationMetadata, times(1)).getAnnotationAttributes(eq(EnablePdx.class.getName())); @@ -120,17 +123,18 @@ public class AbstractCacheConfigurationUnitTests { @Test public void configurePdxWhenEnablePdxIsNotConfigured() { + AnnotationMetadata mockAnnotationMetadata = mock(AnnotationMetadata.class); when(mockAnnotationMetadata.hasAnnotation(anyString())).thenReturn(false); cacheConfiguration.configurePdx(mockAnnotationMetadata); - assertThat(cacheConfiguration.pdxDiskStoreName()).isNull(); - assertThat(cacheConfiguration.pdxIgnoreUnreadFields()).isNull(); - assertThat(cacheConfiguration.pdxPersistent()).isNull(); - assertThat(cacheConfiguration.pdxReadSerialized()).isNull(); - assertThat(cacheConfiguration.pdxSerializer()).isNull(); + assertThat(cacheConfiguration.getPdxDiskStoreName()).isNull(); + assertThat(cacheConfiguration.getPdxIgnoreUnreadFields()).isNull(); + assertThat(cacheConfiguration.getPdxPersistent()).isNull(); + assertThat(cacheConfiguration.getPdxReadSerialized()).isNull(); + assertThat(cacheConfiguration.getPdxSerializer()).isNull(); verify(mockAnnotationMetadata, times(1)).hasAnnotation(eq(EnablePdx.class.getName())); verifyNoMoreInteractions(mockAnnotationMetadata); @@ -138,6 +142,7 @@ public class AbstractCacheConfigurationUnitTests { @Test public void resolvePdxSerializerUsesPdxSerializerBean() { + PdxSerializer mockPdxSerializer = mock(PdxSerializer.class); when(mockBeanFactory.containsBean(anyString())).thenReturn(true); @@ -155,6 +160,7 @@ public class AbstractCacheConfigurationUnitTests { @Test public void resolvePdxSerializerUsesConfiguredPdxSerializer() { + PdxSerializer mockPdxSerializer = mock(PdxSerializer.class); when(mockBeanFactory.containsBean(anyString())).thenReturn(false); @@ -173,6 +179,7 @@ public class AbstractCacheConfigurationUnitTests { @Test public void resolvePdxSerializerCallsNewMappingPdxSerializer() { + AbstractCacheConfiguration cacheConfigurationSpy = spy(this.cacheConfiguration); MappingPdxSerializer mockPdxSerializer = mock(MappingPdxSerializer.class); @@ -192,6 +199,7 @@ public class AbstractCacheConfigurationUnitTests { @Test public void newPdxSerializerUsesConfiguredConversionServiceAndMappingContext() throws Exception { + ConfigurableBeanFactory mockBeanFactory = mock(ConfigurableBeanFactory.class); ConversionService mockConversionService = mock(ConversionService.class); GemfireMappingContext mockMappingContext = mock(GemfireMappingContext.class); @@ -207,13 +215,14 @@ public class AbstractCacheConfigurationUnitTests { assertThat((Object) invokeMethod(pdxSerializer, "getConversionService")).isEqualTo(mockConversionService); assertThat((Object) invokeMethod(pdxSerializer, "getMappingContext")).isEqualTo(mockMappingContext); - verify(mockBeanFactory, times(1)).getConversionService(); + verify(mockBeanFactory, times(2)).getConversionService(); verifyZeroInteractions(mockConversionService); verifyZeroInteractions(mockMappingContext); } @Test public void newPdxSerializerDefaultsConversionServiceAndMappingContextWhenNotConfigured() throws Exception { + cacheConfiguration.setBeanFactory(mockBeanFactory); MappingPdxSerializer pdxSerializer = cacheConfiguration.newPdxSerializer(); diff --git a/src/test/java/org/springframework/data/gemfire/config/annotation/CacheServerPropertiesIntegrationTests.java b/src/test/java/org/springframework/data/gemfire/config/annotation/CacheServerPropertiesIntegrationTests.java new file mode 100644 index 00000000..f9dbfdf5 --- /dev/null +++ b/src/test/java/org/springframework/data/gemfire/config/annotation/CacheServerPropertiesIntegrationTests.java @@ -0,0 +1,132 @@ +/* + * 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.Optional; + +import org.apache.geode.cache.GemFireCache; +import org.apache.geode.cache.server.CacheServer; +import org.apache.geode.cache.server.ClientSubscriptionConfig; +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.Configuration; +import org.springframework.core.env.MutablePropertySources; +import org.springframework.core.env.PropertySource; +import org.springframework.data.gemfire.server.SubscriptionEvictionPolicy; +import org.springframework.data.gemfire.test.mock.MockGemFireObjectsSupport; +import org.springframework.mock.env.MockPropertySource; + +/** + * The CacheServerPropertiesIntegrationTests class... + * + * @author John Blum + * @since 1.0.0 + */ +public class CacheServerPropertiesIntegrationTests { + + private ConfigurableApplicationContext applicationContext; + + @After + public void tearDown() { + Optional.ofNullable(this.applicationContext).ifPresent(ConfigurableApplicationContext::close); + } + + private ConfigurableApplicationContext newApplicationContext(PropertySource testPropertySource, + Class... annotatedClasses) { + + AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(); + + MutablePropertySources propertySources = applicationContext.getEnvironment().getPropertySources(); + + propertySources.addFirst(testPropertySource); + + applicationContext.registerShutdownHook(); + applicationContext.register(annotatedClasses); + applicationContext.refresh(); + + return applicationContext; + } + + @Test + public void cacheServerConfigurationIsCorrect() { + + MockPropertySource testPropertySource = new MockPropertySource() + .withProperty("gemfire.cache.server.port", "12480") + .withProperty("spring.data.gemfire.cache.server.bind-address", "10.120.12.1") + .withProperty("spring.data.gemfire.cache.server.max-connections", 500) + .withProperty("spring.data.gemfire.cache.server.max-time-between-pings", 30000) + .withProperty("spring.data.gemfire.cache.server.TestCacheServer.max-time-between-pings", 15000) + .withProperty("spring.data.gemfire.cache.server.NonExistingCacheServer.max-time-between-pings", 5000) + .withProperty("spring.data.gemfire.cache.server.TestCacheServer.subscription-capacity", 200) + .withProperty("spring.data.gemfire.cache.server.port", "${gemfire.cache.server.port:12345}") + .withProperty("spring.data.gemfire.cache.server.TestCacheServer.subscription-eviction-policy", "MEM"); + + this.applicationContext = newApplicationContext(testPropertySource, TestCacheServerConfiguration.class); + + assertThat(this.applicationContext).isNotNull(); + assertThat(this.applicationContext.containsBean("TestCacheServer")).isTrue(); + + CacheServer testCacheServer = this.applicationContext.getBean("TestCacheServer", CacheServer.class); + + assertThat(testCacheServer).isNotNull(); + assertThat(testCacheServer.getBindAddress()).isEqualTo("10.120.12.1"); + assertThat(testCacheServer.getHostnameForClients()).isEqualTo("skullbox"); + assertThat(testCacheServer.getLoadPollInterval()).isEqualTo(CacheServer.DEFAULT_LOAD_POLL_INTERVAL); + assertThat(testCacheServer.getMaxConnections()).isEqualTo(1200); + assertThat(testCacheServer.getMaximumMessageCount()).isEqualTo(400000); + assertThat(testCacheServer.getMaxThreads()).isEqualTo(8); + assertThat(testCacheServer.getMessageTimeToLive()).isEqualTo(600); + assertThat(testCacheServer.getPort()).isEqualTo(12480); + assertThat(testCacheServer.getSocketBufferSize()).isEqualTo(CacheServer.DEFAULT_SOCKET_BUFFER_SIZE); + assertThat(testCacheServer.getTcpNoDelay()).isEqualTo(CacheServer.DEFAULT_TCP_NO_DELAY); + + ClientSubscriptionConfig testClientSubscriptionConfig = testCacheServer.getClientSubscriptionConfig(); + + assertThat(testClientSubscriptionConfig).isNotNull(); + assertThat(testClientSubscriptionConfig.getCapacity()).isEqualTo(200); + assertThat(testClientSubscriptionConfig.getDiskStoreName()).isEmpty(); + assertThat(testClientSubscriptionConfig.getEvictionPolicy()).isEqualTo("mem"); + } + + // TODO add more tests! + + @Configuration + @EnableCacheServer(name = "TestCacheServer", bindAddress = "192.16.0.22", hostnameForClients = "skullbox", + maxConnections = 100, maxThreads = 8, messageTimeToLive = 300, port = 11235, subscriptionCapacity = 100, + subscriptionEvictionPolicy = SubscriptionEvictionPolicy.ENTRY) + static class TestCacheServerConfiguration { + + @Bean("gemfireCache") + GemFireCache mockGemFireCache() { + return MockGemFireObjectsSupport.mockPeerCache(); + } + + @Bean + CacheServerConfigurer testCacheServerConfigurer() { + return (beanName, beanFactory) -> { + beanFactory.setMaxConnections(1200); + beanFactory.setMaxMessageCount(400000); + beanFactory.setMessageTimeToLive(600); + }; + } + } +} diff --git a/src/test/java/org/springframework/data/gemfire/config/annotation/ClientCachePropertiesIntegrationTests.java b/src/test/java/org/springframework/data/gemfire/config/annotation/ClientCachePropertiesIntegrationTests.java new file mode 100644 index 00000000..a77f2959 --- /dev/null +++ b/src/test/java/org/springframework/data/gemfire/config/annotation/ClientCachePropertiesIntegrationTests.java @@ -0,0 +1,162 @@ +/* + * 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.Optional; + +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.control.ResourceManager; +import org.apache.geode.pdx.PdxSerializer; +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.core.env.MutablePropertySources; +import org.springframework.core.env.PropertySource; +import org.springframework.data.gemfire.test.mock.annotation.EnableGemFireMocking; +import org.springframework.mock.env.MockPropertySource; + +/** + * The ClientCachePropertiesIntegrationTests class... + * + * @author John Blum + * @since 1.0.0 + */ +public class ClientCachePropertiesIntegrationTests { + + private ConfigurableApplicationContext applicationContext; + + @After + public void tearDown() { + Optional.ofNullable(this.applicationContext).ifPresent(ConfigurableApplicationContext::close); + } + + private ConfigurableApplicationContext newApplicationContext(PropertySource testPropertySource, + Class... annotatedClasses) { + + AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(); + + MutablePropertySources propertySources = applicationContext.getEnvironment().getPropertySources(); + + propertySources.addFirst(testPropertySource); + + applicationContext.registerShutdownHook(); + applicationContext.register(annotatedClasses); + applicationContext.refresh(); + + return applicationContext; + } + + @Test + public void clientCacheConfiguration() { + + MockPropertySource testPropertySource = new MockPropertySource() + .withProperty("spring.data.gemfire.cache.critical-heap-percentage", 90.0f) + .withProperty("spring.data.gemfire.cache.eviction-heap-percentage", 85.0f) + .withProperty("spring.data.gemfire.pdx.ignore-unread-fields", false) + .withProperty("spring.data.gemfire.pdx.persistent", true) + .withProperty("spring.data.gemfire.pool.free-connection-timeout", 20000L) + .withProperty("spring.data.gemfire.pool.max-connections", 250) + .withProperty("spring.data.gemfire.pool.ping-interval", 5000L) + .withProperty("spring.data.gemfire.pool.pr-single-hop-enabled", false) + .withProperty("spring.data.gemfire.pool.default.read-timeout", 5000L) + .withProperty("spring.data.gemfire.pool.read-timeout", 20000L) + .withProperty("spring.data.gemfire.pool.retry-attempts", 2) + .withProperty("spring.data.gemfire.pool.server-group", "testGroup") + .withProperty("spring.data.gemfire.pool.default.subscription-redundancy", 2); + + this.applicationContext = newApplicationContext(testPropertySource, TestClientCacheConfiguration.class); + + assertThat(this.applicationContext).isNotNull(); + assertThat(this.applicationContext.containsBean("gemfireCache")).isTrue(); + assertThat(this.applicationContext.containsBean("mockPdxSerializer")).isTrue(); + + ClientCache testClientCache = this.applicationContext.getBean("gemfireCache", ClientCache.class); + + PdxSerializer mockPdxSerializer = this.applicationContext.getBean("mockPdxSerializer", PdxSerializer.class); + + assertThat(mockPdxSerializer).isNotNull(); + assertThat(testClientCache).isNotNull(); + assertThat(testClientCache.getCopyOnRead()).isTrue(); + assertThat(testClientCache.getPdxDiskStore()).isNull(); + assertThat(testClientCache.getPdxIgnoreUnreadFields()).isFalse(); + assertThat(testClientCache.getPdxPersistent()).isTrue(); + assertThat(testClientCache.getPdxReadSerialized()).isFalse(); + assertThat(testClientCache.getPdxSerializer()).isSameAs(mockPdxSerializer); + + Pool defaultPool = testClientCache.getDefaultPool(); + + assertThat(defaultPool).isNotNull(); + assertThat(defaultPool.getFreeConnectionTimeout()).isEqualTo(20000); + assertThat(defaultPool.getIdleTimeout()).isEqualTo(15000L); + assertThat(defaultPool.getLoadConditioningInterval()).isEqualTo(180000); + assertThat(defaultPool.getMaxConnections()).isEqualTo(250); + assertThat(defaultPool.getMinConnections()).isEqualTo(50); + assertThat(defaultPool.getMultiuserAuthentication()).isFalse(); + assertThat(defaultPool.getName()).isEqualTo("DEFAULT"); + assertThat(defaultPool.getPingInterval()).isEqualTo(5000L); + assertThat(defaultPool.getPRSingleHopEnabled()).isFalse(); + assertThat(defaultPool.getReadTimeout()).isEqualTo(5000); + assertThat(defaultPool.getRetryAttempts()).isEqualTo(2); + assertThat(defaultPool.getServerGroup()).isEqualTo("testGroup"); + assertThat(defaultPool.getSocketBufferSize()).isEqualTo(PoolFactory.DEFAULT_SOCKET_BUFFER_SIZE); + assertThat(defaultPool.getStatisticInterval()).isEqualTo(500); + assertThat(defaultPool.getSubscriptionAckInterval()).isEqualTo(PoolFactory.DEFAULT_SUBSCRIPTION_ACK_INTERVAL); + assertThat(defaultPool.getSubscriptionEnabled()).isTrue(); + assertThat(defaultPool.getSubscriptionMessageTrackingTimeout()).isEqualTo(PoolFactory.DEFAULT_SUBSCRIPTION_MESSAGE_TRACKING_TIMEOUT); + assertThat(defaultPool.getSubscriptionRedundancy()).isEqualTo(2); + + ResourceManager resourceManager = testClientCache.getResourceManager(); + + assertThat(resourceManager).isNotNull(); + assertThat(resourceManager.getCriticalHeapPercentage()).isEqualTo(90.0f); + assertThat(resourceManager.getEvictionHeapPercentage()).isEqualTo(90.0f); + } + + // TODO add more tests! + + @EnableGemFireMocking + @EnablePdx(ignoreUnreadFields = true, readSerialized = true, serializerBeanName = "mockPdxSerializer") + @ClientCacheApplication(name = "TestClientCache", copyOnRead = true, + criticalHeapPercentage = 95.0f, evictionHeapPercentage = 80.0f, idleTimeout = 15000L, + maxConnections = 100, minConnections = 10, pingInterval = 15000L, readTimeout = 15000, retryAttempts = 1, + subscriptionEnabled = true, subscriptionRedundancy = 1) + static class TestClientCacheConfiguration { + + @Bean + ClientCacheConfigurer testClientCacheConfigurer() { + return (beanName, factoryBean) -> { + factoryBean.setEvictionHeapPercentage(90.0f); + factoryBean.setPdxReadSerialized(false); + factoryBean.setLoadConditioningInterval(180000); + factoryBean.setMinConnections(50); + factoryBean.setStatisticsInterval(500); + }; + } + + @Bean + PdxSerializer mockPdxSerializer() { + return mock(PdxSerializer.class); + } + } +} diff --git a/src/test/java/org/springframework/data/gemfire/config/annotation/ClientServerCacheApplicationIntegrationTests.java b/src/test/java/org/springframework/data/gemfire/config/annotation/ClientServerCacheApplicationIntegrationTests.java index 70611630..f8c82129 100644 --- a/src/test/java/org/springframework/data/gemfire/config/annotation/ClientServerCacheApplicationIntegrationTests.java +++ b/src/test/java/org/springframework/data/gemfire/config/annotation/ClientServerCacheApplicationIntegrationTests.java @@ -67,6 +67,7 @@ public class ClientServerCacheApplicationIntegrationTests extends ClientServerIn @BeforeClass public static void setupGemFireServer() throws Exception { + gemfireServerProcess = run(CacheServerApplicationConfiguration.class, String.format("-Dgemfire.name=%1$s", asApplicationName(ClientServerCacheApplicationIntegrationTests.class))); @@ -99,6 +100,7 @@ public class ClientServerCacheApplicationIntegrationTests extends ClientServerIn @Bean("Echo") public PartitionedRegionFactoryBean echoRegion(Cache gemfireCache) { + PartitionedRegionFactoryBean echoRegion = new PartitionedRegionFactoryBean(); @@ -111,6 +113,7 @@ public class ClientServerCacheApplicationIntegrationTests extends ClientServerIn } CacheLoader echoCacheLoader() { + return new CacheLoader() { @Override public String load(LoaderHelper helper) throws CacheLoaderException { @@ -129,6 +132,7 @@ public class ClientServerCacheApplicationIntegrationTests extends ClientServerIn @Bean(name = "Echo") ClientRegionFactoryBean echoRegion(ClientCache gemfireCache) { + ClientRegionFactoryBean echoRegion = new ClientRegionFactoryBean(); echoRegion.setCache(gemfireCache); diff --git a/src/test/java/org/springframework/data/gemfire/config/annotation/DiskStorePropertiesIntegrationTests.java b/src/test/java/org/springframework/data/gemfire/config/annotation/DiskStorePropertiesIntegrationTests.java new file mode 100644 index 00000000..25cd3522 --- /dev/null +++ b/src/test/java/org/springframework/data/gemfire/config/annotation/DiskStorePropertiesIntegrationTests.java @@ -0,0 +1,121 @@ +/* + * 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.Optional; + +import org.apache.geode.cache.DiskStore; +import org.apache.geode.cache.DiskStoreFactory; +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.Configuration; +import org.springframework.core.env.MutablePropertySources; +import org.springframework.core.env.PropertySource; +import org.springframework.data.gemfire.test.mock.MockGemFireObjectsSupport; +import org.springframework.mock.env.MockPropertySource; + +/** + * The DiskStorePropertiesIntegrationTests class... + * + * @author John Blum + * @since 1.0.0 + */ +public class DiskStorePropertiesIntegrationTests { + + private ConfigurableApplicationContext applicationContext; + + @After + public void tearDown() { + Optional.ofNullable(this.applicationContext).ifPresent(ConfigurableApplicationContext::close); + } + + private ConfigurableApplicationContext newApplicationContext(PropertySource testPropertySource, + Class... annotatedClasses) { + + AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(); + + MutablePropertySources propertySources = applicationContext.getEnvironment().getPropertySources(); + + propertySources.addFirst(testPropertySource); + + applicationContext.registerShutdownHook(); + applicationContext.register(annotatedClasses); + applicationContext.refresh(); + + return applicationContext; + } + + @Test + public void diskStoreConfigurationIsCorrect() { + + MockPropertySource testPropertySource = new MockPropertySource() + .withProperty("spring.data.gemfire.disk.store.compaction-threshold", 85) + .withProperty("spring.data.gemfire.disk.store.disk-usage-critical-percentage", 90.0f) + .withProperty("spring.data.gemfire.disk.store.disk-usage-warning-percentage", 80.0f) + .withProperty("spring.data.gemfire.disk.store.TestDiskStore.disk-usage-warning-percentage", 85.0f) + .withProperty("spring.data.gemfire.disk.store.time-interval", 500L) + .withProperty("spring.data.gemfire.disk.store.NonExistingDiskStore.time-interval", 30000L); + + this.applicationContext = newApplicationContext(testPropertySource, TestDiskStoreConfiguration.class); + + assertThat(this.applicationContext).isNotNull(); + assertThat(this.applicationContext.containsBean("TestDiskStore")).isTrue(); + + DiskStore testDiskStore = this.applicationContext.getBean("TestDiskStore", DiskStore.class); + + assertThat(testDiskStore).isNotNull(); + assertThat(testDiskStore.getName()).isEqualTo("TestDiskStore"); + assertThat(testDiskStore.getAllowForceCompaction()).isTrue(); + assertThat(testDiskStore.getAutoCompact()).isTrue(); + assertThat(testDiskStore.getCompactionThreshold()).isEqualTo(75); + assertThat(testDiskStore.getDiskUsageCriticalPercentage()).isEqualTo(90.0f); + assertThat(testDiskStore.getDiskUsageWarningPercentage()).isEqualTo(85.0f); + assertThat(testDiskStore.getMaxOplogSize()).isEqualTo(512L); + assertThat(testDiskStore.getQueueSize()).isEqualTo(DiskStoreFactory.DEFAULT_QUEUE_SIZE); + assertThat(testDiskStore.getTimeInterval()).isEqualTo(500L); + assertThat(testDiskStore.getWriteBufferSize()).isEqualTo(DiskStoreFactory.DEFAULT_WRITE_BUFFER_SIZE); + } + + // TODO add more tests! + + @Configuration + @EnableDiskStore(name = "TestDiskStore", allowForceCompaction = true, compactionThreshold = 65, + diskUsageCriticalPercentage = 95.0f, diskUsageWarningPercentage = 75.0f, maxOplogSize = 2048L) + @SuppressWarnings("unused") + static class TestDiskStoreConfiguration { + + @Bean("gemfireCache") + GemFireCache mockGemFireCache() { + return MockGemFireObjectsSupport.mockGemFireCache(); + } + + @Bean + DiskStoreConfigurer testDiskStoreConfigurer() { + return (beanName, factoryBean) -> { + factoryBean.setCompactionThreshold(75); + //factoryBean.setDiskUsageWarningPercentage(95.0f); + factoryBean.setMaxOplogSize(512L); + }; + } + } +} diff --git a/src/test/java/org/springframework/data/gemfire/config/annotation/EnableDiskStoresConfigurationUnitTests.java b/src/test/java/org/springframework/data/gemfire/config/annotation/EnableDiskStoresConfigurationUnitTests.java index 619037b9..a860df6b 100644 --- a/src/test/java/org/springframework/data/gemfire/config/annotation/EnableDiskStoresConfigurationUnitTests.java +++ b/src/test/java/org/springframework/data/gemfire/config/annotation/EnableDiskStoresConfigurationUnitTests.java @@ -18,30 +18,19 @@ package org.springframework.data.gemfire.config.annotation; import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Matchers.any; -import static org.mockito.Matchers.anyBoolean; -import static org.mockito.Matchers.anyFloat; -import static org.mockito.Matchers.anyInt; -import static org.mockito.Matchers.anyLong; -import static org.mockito.Matchers.anyString; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; import java.io.File; +import java.util.Optional; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; -import org.apache.geode.cache.Cache; import org.apache.geode.cache.DiskStore; -import org.apache.geode.cache.DiskStoreFactory; import org.junit.After; import org.junit.Test; -import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; +import org.springframework.data.gemfire.test.mock.annotation.EnableGemFireMocking; /** * Unit tests for the {@link EnableDiskStore} and {@link EnableDiskStores} annotations as well as @@ -49,7 +38,12 @@ import org.springframework.context.annotation.Configuration; * * @author John Blum * @see org.junit.Test - * @see org.mockito.Mockito + * @see org.apache.geode.cache.DiskStore + * @see org.springframework.context.ConfigurableApplicationContext + * @see org.springframework.data.gemfire.config.annotation.EnableDiskStore + * @see org.springframework.data.gemfire.config.annotation.EnableDiskStores + * @see org.springframework.data.gemfire.config.annotation.DiskStoreConfiguration + * @see org.springframework.data.gemfire.config.annotation.DiskStoresConfiguration * @since 1.9.0 */ public class EnableDiskStoresConfigurationUnitTests { @@ -60,13 +54,11 @@ public class EnableDiskStoresConfigurationUnitTests { @After public void tearDown() { - if (applicationContext != null) { - applicationContext.close(); - } + Optional.ofNullable(this.applicationContext).ifPresent(ConfigurableApplicationContext::close); } /* (non-Javadoc) */ - protected void assertDiskStore(DiskStore diskStore, String name, boolean allowForceCompaction, boolean autoCompact, + private void assertDiskStore(DiskStore diskStore, String name, boolean allowForceCompaction, boolean autoCompact, int compactionThreshold, float diskUsageCriticalPercentage, float diskUsageWarningPercentage, long maxOplogSize, int queueSize, long timeInterval, int writeBufferSize) { @@ -84,7 +76,8 @@ public class EnableDiskStoresConfigurationUnitTests { } /* (non-Javadoc) */ - protected void assertDiskStoreDirectoryLocations(DiskStore diskStore, File... diskDirectories) { + private void assertDiskStoreDirectoryLocations(DiskStore diskStore, File... diskDirectories) { + assertThat(diskStore).isNotNull(); File[] diskStoreDirectories = diskStore.getDiskDirs(); @@ -100,7 +93,8 @@ public class EnableDiskStoresConfigurationUnitTests { } /* (non-Javadoc) */ - protected void assertDiskStoreDirectorySizes(DiskStore diskStore, int... diskDirectorySizes) { + private void assertDiskStoreDirectorySizes(DiskStore diskStore, int... diskDirectorySizes) { + assertThat(diskStore).isNotNull(); int[] diskStoreDirectorySizes = diskStore.getDiskDirSizes(); @@ -116,22 +110,23 @@ public class EnableDiskStoresConfigurationUnitTests { } /* (non-Javadoc) */ - protected File newFile(String location) { - return new File(location); - } - - /* (non-Javadoc) */ - protected ConfigurableApplicationContext newApplicationContext(Class... annotatedClasses) { + private ConfigurableApplicationContext newApplicationContext(Class... annotatedClasses) { ConfigurableApplicationContext applicationContext = new AnnotationConfigApplicationContext(annotatedClasses); applicationContext.registerShutdownHook(); return applicationContext; } + /* (non-Javadoc) */ + private File newFile(String location) { + return new File(location); + } + @Test public void enableSingleDiskStore() { - applicationContext = newApplicationContext(SingleDiskStoreConfiguration.class); - DiskStore testDiskStore = applicationContext.getBean("TestDiskStore", DiskStore.class); + this.applicationContext = newApplicationContext(SingleDiskStoreConfiguration.class); + + DiskStore testDiskStore = this.applicationContext.getBean("TestDiskStore", DiskStore.class); assertDiskStore(testDiskStore, "TestDiskStore", true, true, 75, 95.0f, 75.0f, 8192L, 100, 2000L, 65536); assertDiskStoreDirectoryLocations(testDiskStore, newFile("/absolute/path/to/gemfire/disk/directory"), @@ -140,14 +135,15 @@ public class EnableDiskStoresConfigurationUnitTests { } @Test - public void enablesMultipleDiskStores() { - applicationContext = newApplicationContext(MultipleDiskStoresConfiguration.class); + public void enableMultipleDiskStores() { - DiskStore testDiskStoreOne = applicationContext.getBean("TestDiskStoreOne", DiskStore.class); + this.applicationContext = newApplicationContext(MultipleDiskStoresConfiguration.class); + + DiskStore testDiskStoreOne = this.applicationContext.getBean("TestDiskStoreOne", DiskStore.class); assertDiskStore(testDiskStoreOne, "TestDiskStoreOne", false, true, 75, 99.0f, 90.0f, 2048L, 100, 1000L, 32768); - DiskStore testDiskStoreTwo = applicationContext.getBean("TestDiskStoreTwo", DiskStore.class); + DiskStore testDiskStoreTwo = this.applicationContext.getBean("TestDiskStoreTwo", DiskStore.class); assertDiskStore(testDiskStoreTwo, "TestDiskStoreTwo", true, true, 85, 99.0f, 90.0f, 4096L, 0, 1000L, 32768); } @@ -169,121 +165,26 @@ public class EnableDiskStoresConfigurationUnitTests { }; } - @Configuration - @SuppressWarnings("unused") - static class CacheConfiguration { - - @Bean - Cache gemfireCache() { - Cache mockCache = mock(Cache.class); - - when(mockCache.createDiskStoreFactory()).thenAnswer(new Answer() { - @Override - public DiskStoreFactory answer(InvocationOnMock invocation) throws Throwable { - final DiskStoreFactory mockDiskStoreFactory = - mock(DiskStoreFactory.class, mockName("MockDiskStoreFactory")); - - final AtomicReference allowForceCompaction = new AtomicReference<>(false); - final AtomicReference autoCompact = new AtomicReference<>(false); - final AtomicReference compactionThreshold = new AtomicReference<>(50); - final AtomicReference diskDirectories = new AtomicReference<>(new File[0]); - final AtomicReference diskDirectorySizes = new AtomicReference<>(new int[0]); - final AtomicReference diskUsageCriticalPercentage = new AtomicReference<>(99.0f); - final AtomicReference diskUsageWarningPercentage = new AtomicReference<>(90.0f); - final AtomicReference maxOplogSize = new AtomicReference<>(1024L); - final AtomicReference queueSize = new AtomicReference<>(0); - final AtomicReference timeInterval = new AtomicReference<>(1000L); - final AtomicReference writeBufferSize = new AtomicReference<>(32768); - - when(mockDiskStoreFactory.setAllowForceCompaction(anyBoolean())).thenAnswer( - newSetter(Boolean.TYPE, allowForceCompaction, mockDiskStoreFactory)); - - when(mockDiskStoreFactory.setAutoCompact(anyBoolean())).thenAnswer( - newSetter(Boolean.TYPE, autoCompact, mockDiskStoreFactory)); - - when(mockDiskStoreFactory.setCompactionThreshold(anyInt())).thenAnswer( - newSetter(Integer.TYPE, compactionThreshold, mockDiskStoreFactory)); - - when(mockDiskStoreFactory.setDiskDirsAndSizes(any(File[].class), any(int[].class))).thenAnswer( - new Answer() { - @Override public DiskStoreFactory answer(InvocationOnMock invocation) throws Throwable { - File[] localDiskDirectories = invocation.getArgument(0); - int[] localDiskDirectorySizes = invocation.getArgument(1); - - diskDirectories.set(localDiskDirectories); - diskDirectorySizes.set(localDiskDirectorySizes); - - return mockDiskStoreFactory; - } - } - ); - - when(mockDiskStoreFactory.setDiskUsageCriticalPercentage(anyFloat())).thenAnswer( - newSetter(Float.TYPE, diskUsageCriticalPercentage, mockDiskStoreFactory)); - - when(mockDiskStoreFactory.setDiskUsageWarningPercentage(anyFloat())).thenAnswer( - newSetter(Float.TYPE, diskUsageWarningPercentage, mockDiskStoreFactory)); - - when(mockDiskStoreFactory.setMaxOplogSize(anyLong())).thenAnswer( - newSetter(Long.TYPE, maxOplogSize, mockDiskStoreFactory)); - - when(mockDiskStoreFactory.setQueueSize(anyInt())).thenAnswer( - newSetter(Integer.TYPE, queueSize, mockDiskStoreFactory)); - - when(mockDiskStoreFactory.setTimeInterval(anyLong())).thenAnswer( - newSetter(Long.TYPE, timeInterval, mockDiskStoreFactory)); - - when(mockDiskStoreFactory.setWriteBufferSize(anyInt())).thenAnswer( - newSetter(Integer.TYPE, writeBufferSize, mockDiskStoreFactory)); - - when(mockDiskStoreFactory.create(anyString())).thenAnswer(new Answer() { - @Override - public DiskStore answer(InvocationOnMock invocation) throws Throwable { - String diskStoreName = invocation.getArgument(0); - - DiskStore mockDiskStore = mock(DiskStore.class, diskStoreName); - - when(mockDiskStore.getAllowForceCompaction()).thenAnswer(newGetter(allowForceCompaction)); - when(mockDiskStore.getAutoCompact()).thenAnswer(newGetter(autoCompact)); - when(mockDiskStore.getCompactionThreshold()).thenAnswer(newGetter(compactionThreshold)); - when(mockDiskStore.getDiskDirs()).thenAnswer(newGetter(diskDirectories)); - when(mockDiskStore.getDiskDirSizes()).thenAnswer(newGetter(diskDirectorySizes)); - when(mockDiskStore.getDiskUsageCriticalPercentage()).thenAnswer(newGetter(diskUsageCriticalPercentage)); - when(mockDiskStore.getDiskUsageWarningPercentage()).thenAnswer(newGetter(diskUsageWarningPercentage)); - when(mockDiskStore.getMaxOplogSize()).thenAnswer(newGetter(maxOplogSize)); - when(mockDiskStore.getName()).thenReturn(diskStoreName); - when(mockDiskStore.getQueueSize()).thenAnswer(newGetter(queueSize)); - when(mockDiskStore.getTimeInterval()).thenAnswer(newGetter(timeInterval)); - when(mockDiskStore.getWriteBufferSize()).thenAnswer(newGetter(writeBufferSize)); - - return mockDiskStore; - } - }); - - return mockDiskStoreFactory; - } - }); - - return mockCache; - } - } - + @PeerCacheApplication + @EnableGemFireMocking @EnableDiskStore(name = "TestDiskStore", allowForceCompaction = true, autoCompact = true, compactionThreshold = 75, diskUsageCriticalPercentage = 95.0f, diskUsageWarningPercentage = 75.0f, maxOplogSize = 8192L, queueSize = 100, timeInterval = 2000L, writeBufferSize = 65536, diskDirectories = { @EnableDiskStore.DiskDirectory(location = "/absolute/path/to/gemfire/disk/directory", maxSize = 1024), @EnableDiskStore.DiskDirectory(location = "relative/path/to/gemfire/disk/directory", maxSize = 4096) }) - static class SingleDiskStoreConfiguration extends CacheConfiguration { + static class SingleDiskStoreConfiguration { } + @PeerCacheApplication + @EnableGemFireMocking @EnableDiskStores(autoCompact = true, compactionThreshold = 75, maxOplogSize = 2048L, diskStores = { @EnableDiskStore(name = "TestDiskStoreOne", queueSize = 100), @EnableDiskStore(name = "TestDiskStoreTwo", allowForceCompaction = true, compactionThreshold = 85, maxOplogSize = 4096) }) - static class MultipleDiskStoresConfiguration extends CacheConfiguration { + static class MultipleDiskStoresConfiguration { } } diff --git a/src/test/java/org/springframework/data/gemfire/config/annotation/PeerCachePropertiesIntegrationTests.java b/src/test/java/org/springframework/data/gemfire/config/annotation/PeerCachePropertiesIntegrationTests.java new file mode 100644 index 00000000..15c45504 --- /dev/null +++ b/src/test/java/org/springframework/data/gemfire/config/annotation/PeerCachePropertiesIntegrationTests.java @@ -0,0 +1,129 @@ +/* + * 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.Optional; + +import org.apache.geode.cache.Cache; +import org.apache.geode.cache.control.ResourceManager; +import org.apache.geode.pdx.PdxSerializer; +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.core.env.MutablePropertySources; +import org.springframework.core.env.PropertySource; +import org.springframework.data.gemfire.test.mock.annotation.EnableGemFireMocking; +import org.springframework.mock.env.MockPropertySource; + +/** + * The PeerCachePropertiesIntegrationTests class... + * + * @author John Blum + * @since 1.0.0 + */ +public class PeerCachePropertiesIntegrationTests { + + private ConfigurableApplicationContext applicationContext; + + @After + public void tearDown() { + Optional.ofNullable(this.applicationContext).ifPresent(ConfigurableApplicationContext::close); + } + + private ConfigurableApplicationContext newApplicationContext(PropertySource testPropertySource, + Class... annotatedClasses) { + + AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(); + + MutablePropertySources propertySources = applicationContext.getEnvironment().getPropertySources(); + + propertySources.addFirst(testPropertySource); + + applicationContext.registerShutdownHook(); + applicationContext.register(annotatedClasses); + applicationContext.refresh(); + + return applicationContext; + } + + @Test + public void peerCacheConfiguration() { + + MockPropertySource testPropertySource = new MockPropertySource() + .withProperty("spring.data.gemfire.cache.copy-on-read", true) + .withProperty("spring.data.gemfire.cache.critical-heap-percentage", 95.0f) + .withProperty("spring.data.gemfire.cache.eviction-heap-percentage", 85.0f) + .withProperty("spring.data.gemfire.cache.peer.lock-lease", 180) + .withProperty("spring.data.gemfire.cache.peer.lock-timeout", 30) + .withProperty("spring.data.gemfire.cache.peer.search-timeout", 120) + .withProperty("spring.data.gemfire.pdx.ignore-unread-fields", false) + .withProperty("spring.data.gemfire.pdx.persistent", true); + + this.applicationContext = newApplicationContext(testPropertySource, TestPeerCacheConfiguration.class); + + assertThat(this.applicationContext).isNotNull(); + assertThat(this.applicationContext.containsBean("gemfireCache")).isTrue(); + assertThat(this.applicationContext.containsBean("mockPdxSerializer")).isTrue(); + + Cache testPeerCache = this.applicationContext.getBean("gemfireCache", Cache.class); + + PdxSerializer mockPdxSerializer = this.applicationContext.getBean("mockPdxSerializer", PdxSerializer.class); + + assertThat(testPeerCache).isNotNull(); + assertThat(mockPdxSerializer).isNotNull(); + assertThat(testPeerCache.getLockLease()).isEqualTo(180); + assertThat(testPeerCache.getLockTimeout()).isEqualTo(30); + assertThat(testPeerCache.getPdxDiskStore()).isNull(); + assertThat(testPeerCache.getPdxIgnoreUnreadFields()).isFalse(); + assertThat(testPeerCache.getPdxPersistent()).isTrue(); + assertThat(testPeerCache.getPdxReadSerialized()).isTrue(); + assertThat(testPeerCache.getPdxSerializer()).isSameAs(mockPdxSerializer); + assertThat(testPeerCache.getSearchTimeout()).isEqualTo(60); + + ResourceManager resourceManager = testPeerCache.getResourceManager(); + + assertThat(resourceManager).isNotNull(); + assertThat(resourceManager.getCriticalHeapPercentage()).isEqualTo(95.0f); + assertThat(resourceManager.getEvictionHeapPercentage()).isEqualTo(85.0f); + } + + //TODO add more tests + + @EnableGemFireMocking + @EnablePdx(ignoreUnreadFields = true, readSerialized = true, serializerBeanName = "mockPdxSerializer") + @PeerCacheApplication(name = "TestPeerCache", criticalHeapPercentage = 90.0f, evictionHeapPercentage = 75.0f, + lockLease = 300, lockTimeout = 120) + static class TestPeerCacheConfiguration { + + @Bean + PeerCacheConfigurer testPeerCacheConfigurer() { + return (beanName, beanFactory) -> { + beanFactory.setSearchTimeout(60); + }; + } + + @Bean + PdxSerializer mockPdxSerializer() { + return mock(PdxSerializer.class); + } + } +} diff --git a/src/test/java/org/springframework/data/gemfire/config/annotation/support/AbstractAnnotationConfigSupportTests.java b/src/test/java/org/springframework/data/gemfire/config/annotation/support/AbstractAnnotationConfigSupportTests.java new file mode 100644 index 00000000..a2a594eb --- /dev/null +++ b/src/test/java/org/springframework/data/gemfire/config/annotation/support/AbstractAnnotationConfigSupportTests.java @@ -0,0 +1,111 @@ +/* + * 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.support; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; + +/** + * Unit tests for {@link AbstractAnnotationConfigSupport}. + * + * @author John Blum + * @see org.junit.Test + * @see org.junit.runner.RunWith + * @see org.mockito.Mock + * @see org.mockito.Mockito + * @see org.mockito.junit.MockitoJUnitRunner + * @see org.springframework.data.gemfire.config.annotation.support.AbstractAnnotationConfigSupport + * @since 1.1.0 + */ +@RunWith(MockitoJUnitRunner.class) +public class AbstractAnnotationConfigSupportTests { + + @Mock + private AbstractAnnotationConfigSupport support; + + @Test + public void requirePropertyWithNonStringValueIsSuccessful() { + when(support.requireProperty(anyString(), any())).thenCallRealMethod(); + when(support.resolveProperty(anyString(), eq(Integer.class), eq(null))).thenReturn(1); + + assertThat(support.requireProperty("key", Integer.class)).isEqualTo(1); + + verify(support, times(1)) + .resolveProperty(eq("key"), eq(Integer.class), eq(null)); + } + + @Test + public void requirePropertyWithStringValueIsSuccessful() { + when(support.requireProperty(anyString(), any())).thenCallRealMethod(); + when(support.resolveProperty(anyString(), eq(String.class), eq(null))).thenReturn("test"); + + assertThat(support.requireProperty("key", String.class)).isEqualTo("test"); + + verify(support, times(1)) + .resolveProperty(eq("key"), eq(String.class), eq(null)); + } + + @Test(expected = IllegalArgumentException.class) + public void requirePropertyWithEmptyStringThrowsIllegalArgumentException() { + when(support.requireProperty(anyString(), any())).thenCallRealMethod(); + when(support.resolveProperty(anyString(), eq(String.class), eq(null))).thenReturn(" "); + + try { + support.requireProperty("key", String.class); + } + catch (IllegalArgumentException expected) { + assertThat(expected).hasMessage("Property [key] is required"); + assertThat(expected).hasNoCause(); + + throw expected; + } + finally { + verify(support, times(1)) + .resolveProperty(eq("key"), eq(String.class), eq(null)); + } + } + + @Test(expected = IllegalArgumentException.class) + public void requirePropertyWithNullValueThrowsIllegalArgumentException() { + when(support.requireProperty(anyString(), any())).thenCallRealMethod(); + when(support.resolveProperty(anyString(), any(), eq(null))).thenReturn(null); + + try { + support.requireProperty("key", Integer.class); + } + catch (IllegalArgumentException expected) { + assertThat(expected).hasMessage("Property [key] is required"); + assertThat(expected).hasNoCause(); + + throw expected; + } + finally { + verify(support, times(1)) + .resolveProperty(eq("key"), eq(Integer.class), eq(null)); + } + } +} diff --git a/src/test/java/org/springframework/data/gemfire/config/support/DiskStoreDirectoryBeanPostProcessorIntegrationTests.java b/src/test/java/org/springframework/data/gemfire/config/support/DiskStoreDirectoryBeanPostProcessorIntegrationTests.java index 2c605408..76442852 100644 --- a/src/test/java/org/springframework/data/gemfire/config/support/DiskStoreDirectoryBeanPostProcessorIntegrationTests.java +++ b/src/test/java/org/springframework/data/gemfire/config/support/DiskStoreDirectoryBeanPostProcessorIntegrationTests.java @@ -30,19 +30,23 @@ import org.junit.runner.RunWith; import org.springframework.context.annotation.Bean; import org.springframework.data.gemfire.DiskStoreFactoryBean; import org.springframework.data.gemfire.config.annotation.PeerCacheApplication; +import org.springframework.data.gemfire.test.support.FileSystemUtils; import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -import org.springframework.util.FileSystemUtils; +import org.springframework.test.context.junit4.SpringRunner; /** * Integration tests for {@link DiskStoreDirectoryBeanPostProcessor}. * * @author John Blum * @see org.junit.Test + * @see org.junit.runner.RunWith + * @see org.springframework.data.gemfire.DiskStoreFactoryBean * @see org.springframework.data.gemfire.config.support.DiskStoreDirectoryBeanPostProcessor + * @see org.springframework.test.context.ContextConfiguration + * @see org.springframework.test.context.junit4.SpringRunner * @since 1.5.0 */ -@RunWith(SpringJUnit4ClassRunner.class) +@RunWith(SpringRunner.class) @ContextConfiguration public class DiskStoreDirectoryBeanPostProcessorIntegrationTests { @@ -53,8 +57,8 @@ public class DiskStoreDirectoryBeanPostProcessorIntegrationTests { @AfterClass public static void testSuiteTearDown() { - assertThat(FileSystemUtils.deleteRecursively(new File("./gemfire"))).isTrue(); - assertThat(FileSystemUtils.deleteRecursively(new File("./gfe"))).isTrue(); + assertThat(FileSystemUtils.deleteRecursive(new File("./gemfire"))).isTrue(); + assertThat(FileSystemUtils.deleteRecursive(new File("./gfe"))).isTrue(); } @Test diff --git a/src/test/java/org/springframework/data/gemfire/test/MockCacheFactoryBean.java b/src/test/java/org/springframework/data/gemfire/test/MockCacheFactoryBean.java index 5a1580d7..b9b4a2c7 100644 --- a/src/test/java/org/springframework/data/gemfire/test/MockCacheFactoryBean.java +++ b/src/test/java/org/springframework/data/gemfire/test/MockCacheFactoryBean.java @@ -24,10 +24,6 @@ import org.springframework.data.gemfire.CacheFactoryBean; */ public class MockCacheFactoryBean extends CacheFactoryBean { - public MockCacheFactoryBean() { - this(null); - } - public MockCacheFactoryBean(CacheFactoryBean cacheFactoryBean) { setUseBeanFactoryLocator(false); diff --git a/src/test/java/org/springframework/data/gemfire/test/mock/MockGemFireObjectsSupport.java b/src/test/java/org/springframework/data/gemfire/test/mock/MockGemFireObjectsSupport.java index c6bc3d06..779fcd16 100644 --- a/src/test/java/org/springframework/data/gemfire/test/mock/MockGemFireObjectsSupport.java +++ b/src/test/java/org/springframework/data/gemfire/test/mock/MockGemFireObjectsSupport.java @@ -51,7 +51,9 @@ import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Function; +import org.apache.commons.lang.StringUtils; import org.apache.geode.cache.Cache; import org.apache.geode.cache.CacheFactory; import org.apache.geode.cache.DiskStore; @@ -77,7 +79,6 @@ import org.springframework.data.gemfire.test.support.FileSystemUtils; * Mock GemFire Objects (e.g. {@link Cache}, {@link ClientCache}, {@link Region}, etc). * * @author John Blum - * @see org.mockito.Mockito * @see org.apache.geode.cache.Cache * @see org.apache.geode.cache.CacheFactory * @see org.apache.geode.cache.DiskStore @@ -89,10 +90,12 @@ import org.springframework.data.gemfire.test.support.FileSystemUtils; * @see org.apache.geode.cache.server.CacheServer * @see org.apache.geode.cache.server.ClientSubscriptionConfig * @see org.apache.geode.distributed.DistributedSystem + * @see org.mockito.Mockito + * @see org.springframework.data.gemfire.test.mock.MockObjectsSupport * @since 2.0.0 */ @SuppressWarnings("unused") -public abstract class MockGemFireObjectsSupport { +public abstract class MockGemFireObjectsSupport extends MockObjectsSupport { private static final Map diskStores = new ConcurrentHashMap<>(); @@ -110,6 +113,11 @@ public abstract class MockGemFireObjectsSupport { return (regionPath.lastIndexOf(Region.SEPARATOR) <= 0); } + private static String toRegionPath(String regionPath) { + return (StringUtils.startsWith(regionPath, Region.SEPARATOR) ? regionPath + : String.format("%1$s%2$s", Region.SEPARATOR, regionPath)); + } + /* (non-Javadoc) */ @SuppressWarnings("unchecked") private static T mockCacheApi(T mockGemFireCache) { @@ -120,17 +128,12 @@ public abstract class MockGemFireObjectsSupport { ResourceManager mockResourceManager = mockResourceManager(); - doAnswer(invocation -> { - copyOnRead.set(invocation.getArgument(0)); - return null; - }).when(mockGemFireCache).setCopyOnRead(anyBoolean()); + doAnswer(newSetter(copyOnRead, null)).when(mockGemFireCache).setCopyOnRead(anyBoolean()); - doAnswer(invocation -> { - regionAttributes.put(invocation.getArgument(0), invocation.getArgument(1)); - return null; - }).when(mockGemFireCache).setRegionAttributes(anyString(), any(RegionAttributes.class)); + doAnswer(newSetter(regionAttributes, null)) + .when(mockGemFireCache).setRegionAttributes(anyString(), any(RegionAttributes.class)); - when(mockGemFireCache.getCopyOnRead()).thenAnswer(invocation -> copyOnRead.get()); + when(mockGemFireCache.getCopyOnRead()).thenAnswer(newGetter(copyOnRead)); when(mockGemFireCache.getDistributedSystem()).thenReturn(mockDistributedSystem); @@ -155,14 +158,11 @@ public abstract class MockGemFireObjectsSupport { /* (non-Javadoc) */ private static T mockRegionServiceApi(T mockRegionService) { - AtomicBoolean close = new AtomicBoolean(false); + AtomicBoolean closed = new AtomicBoolean(false); - doAnswer(invocation -> { - close.set(true); - return null; - }).when(mockRegionService).close(); + doAnswer(newSetter(closed, true, null)).when(mockRegionService).close(); - when(mockRegionService.isClosed()).thenAnswer(invocation -> close.get()); + when(mockRegionService.isClosed()).thenAnswer(newGetter(closed)); when(mockRegionService.getCancelCriterion()).thenThrow(newUnsupportedOperationException(NOT_SUPPORTED)); @@ -171,7 +171,7 @@ public abstract class MockGemFireObjectsSupport { String regionPath = invocation.getArgument(0); Optional.ofNullable(regionPath).map(String::trim).filter(it -> !it.isEmpty()) - .map(it -> it.startsWith(Region.SEPARATOR) ? it : String.format("%1$s%2$s", Region.SEPARATOR, it)) + .map(MockGemFireObjectsSupport::toRegionPath) .orElseThrow(() -> newIllegalArgumentException("Region path [%s] is not valid", regionPath)); return regions.get(regionPath); @@ -233,33 +233,18 @@ public abstract class MockGemFireObjectsSupport { return mockCacheServer; }); - doAnswer(invocation -> { - lockLease.set(invocation.getArgument(0)); - return null; - }).when(mockCache).setLockLease(anyInt()); - - doAnswer(invocation -> { - lockTimeout.set(invocation.getArgument(0)); - return null; - }).when(mockCache).setLockTimeout(anyInt()); - - doAnswer(invocation -> { - messageSyncInterval.set(invocation.getArgument(0)); - return null; - }).when(mockCache).setMessageSyncInterval(anyInt()); - - doAnswer(invocation -> { - searchTimeout.set(invocation.getArgument(0)); - return null; - }).when(mockCache).setSearchTimeout(anyInt()); + doAnswer(newSetter(lockLease, null)).when(mockCache).setLockLease(anyInt()); + doAnswer(newSetter(lockTimeout, null)).when(mockCache).setLockTimeout(anyInt()); + doAnswer(newSetter(messageSyncInterval, null)).when(mockCache).setMessageSyncInterval(anyInt()); + doAnswer(newSetter(searchTimeout, null)).when(mockCache).setSearchTimeout(anyInt()); when(mockCache.isServer()).thenReturn(true); when(mockCache.getCacheServers()).thenAnswer(invocation -> Collections.unmodifiableList(cacheServers)); - when(mockCache.getLockLease()).thenAnswer(invocation -> lockLease.get()); - when(mockCache.getLockTimeout()).thenAnswer(invocation -> lockTimeout.get()); - when(mockCache.getMessageSyncInterval()).thenAnswer(invocation -> messageSyncInterval.get()); + when(mockCache.getLockLease()).thenAnswer(newGetter(lockLease)); + when(mockCache.getLockTimeout()).thenAnswer(newGetter(lockTimeout)); + when(mockCache.getMessageSyncInterval()).thenAnswer(newGetter(messageSyncInterval)); when(mockCache.getReconnectedCache()).thenAnswer(invocation -> mockPeerCache()); - when(mockCache.getSearchTimeout()).thenAnswer(invocation -> searchTimeout.get()); + when(mockCache.getSearchTimeout()).thenAnswer(newGetter(searchTimeout)); return mockCacheApi(mockCache); } @@ -283,72 +268,50 @@ public abstract class MockGemFireObjectsSupport { AtomicReference bindAddress = new AtomicReference<>(CacheServer.DEFAULT_BIND_ADDRESS); AtomicReference hostnameForClients = new AtomicReference<>(CacheServer.DEFAULT_HOSTNAME_FOR_CLIENTS); - doAnswer(invocation -> { - bindAddress.set(invocation.getArgument(0)); - return null; - }).when(mockCacheServer).setBindAddress(anyString()); + doAnswer(newSetter(bindAddress, null)) + .when(mockCacheServer).setBindAddress(anyString()); - doAnswer(invocation -> { - hostnameForClients.set(invocation.getArgument(0)); - return null; - }).when(mockCacheServer).setHostnameForClients(anyString()); + doAnswer(newSetter(hostnameForClients, null)) + .when(mockCacheServer).setHostnameForClients(anyString()); - doAnswer(invocation -> { - loadPollInterval.set(invocation.getArgument(0)); - return null; - }).when(mockCacheServer).setLoadPollInterval(anyLong()); + doAnswer(newSetter(loadPollInterval, null)) + .when(mockCacheServer).setLoadPollInterval(anyLong()); - doAnswer(invocation -> { - maxConnections.set(invocation.getArgument(0)); - return null; - }).when(mockCacheServer).setMaxConnections(anyInt()); + doAnswer(newSetter(maxConnections, null)) + .when(mockCacheServer).setMaxConnections(anyInt()); - doAnswer(invocation -> { - maxMessageCount.set(invocation.getArgument(0)); - return null; - }).when(mockCacheServer).setMaximumMessageCount(anyInt()); + doAnswer(newSetter(maxMessageCount, null)) + .when(mockCacheServer).setMaximumMessageCount(anyInt()); - doAnswer(invocation -> { - maxThreads.set(invocation.getArgument(0)); - return null; - }).when(mockCacheServer).setMaxThreads(anyInt()); + doAnswer(newSetter(maxThreads, null)) + .when(mockCacheServer).setMaxThreads(anyInt()); - doAnswer(invocation -> { - maxTimeBetweenPings.set(invocation.getArgument(0)); - return null; - }).when(mockCacheServer).setMaximumTimeBetweenPings(anyInt()); + doAnswer(newSetter(maxTimeBetweenPings, null)) + .when(mockCacheServer).setMaximumTimeBetweenPings(anyInt()); - doAnswer(invocation -> { - messageTimeToLive.set(invocation.getArgument(0)); - return null; - }).when(mockCacheServer).setMessageTimeToLive(anyInt()); + doAnswer(newSetter(messageTimeToLive, null)) + .when(mockCacheServer).setMessageTimeToLive(anyInt()); - doAnswer(invocation -> { - port.set(invocation.getArgument(0)); - return null; - }).when(mockCacheServer).setPort(anyInt()); + doAnswer(newSetter(port, null)) + .when(mockCacheServer).setPort(anyInt()); - doAnswer(invocation -> { - socketBufferSize.set(invocation.getArgument(0)); - return null; - }).when(mockCacheServer).setSocketBufferSize(anyInt()); + doAnswer(newSetter(socketBufferSize, null)) + .when(mockCacheServer).setSocketBufferSize(anyInt()); - doAnswer(invocation -> { - tcpNoDelay.set(invocation.getArgument(0)); - return null; - }).when(mockCacheServer).setTcpNoDelay(anyBoolean()); + doAnswer(newSetter(tcpNoDelay, null)) + .when(mockCacheServer).setTcpNoDelay(anyBoolean()); - when(mockCacheServer.getBindAddress()).thenAnswer(invocation -> bindAddress.get()); - when(mockCacheServer.getHostnameForClients()).thenAnswer(invocation -> hostnameForClients.get()); - when(mockCacheServer.getLoadPollInterval()).thenAnswer(invocation -> loadPollInterval.get()); - when(mockCacheServer.getMaxConnections()).thenAnswer(invocation -> maxConnections.get()); - when(mockCacheServer.getMaximumMessageCount()).thenAnswer(invocation -> maxMessageCount.get()); - when(mockCacheServer.getMaxThreads()).thenAnswer(invocation -> maxThreads.get()); - when(mockCacheServer.getMaximumTimeBetweenPings()).thenAnswer(invocation -> maxTimeBetweenPings.get()); - when(mockCacheServer.getMessageTimeToLive()).thenAnswer(invocation -> messageTimeToLive.get()); - when(mockCacheServer.getPort()).thenAnswer(invocation -> port.get()); - when(mockCacheServer.getSocketBufferSize()).thenAnswer(invocation -> socketBufferSize.get()); - when(mockCacheServer.getTcpNoDelay()).thenAnswer(invocation -> tcpNoDelay.get()); + when(mockCacheServer.getBindAddress()).thenAnswer(newGetter(bindAddress)); + when(mockCacheServer.getHostnameForClients()).thenAnswer(newGetter(hostnameForClients)); + when(mockCacheServer.getLoadPollInterval()).thenAnswer(newGetter(loadPollInterval)); + when(mockCacheServer.getMaxConnections()).thenAnswer(newGetter(maxConnections)); + when(mockCacheServer.getMaximumMessageCount()).thenAnswer(newGetter(maxMessageCount)); + when(mockCacheServer.getMaxThreads()).thenAnswer(newGetter(maxThreads)); + when(mockCacheServer.getMaximumTimeBetweenPings()).thenAnswer(newGetter(maxTimeBetweenPings)); + when(mockCacheServer.getMessageTimeToLive()).thenAnswer(newGetter(messageTimeToLive)); + when(mockCacheServer.getPort()).thenAnswer(newGetter(port)); + when(mockCacheServer.getSocketBufferSize()).thenAnswer(newGetter(socketBufferSize)); + when(mockCacheServer.getTcpNoDelay()).thenAnswer(newGetter(tcpNoDelay)); ClientSubscriptionConfig mockClientSubsriptionConfig = mockClientSubscriptionConfig(); @@ -368,26 +331,25 @@ public abstract class MockGemFireObjectsSupport { AtomicReference subscriptionEvictionPolicy = new AtomicReference<>(SubscriptionEvictionPolicy.DEFAULT); - doAnswer(invocation -> { - subscriptionCapacity.set(invocation.getArgument(0)); - return null; - }).when(mockClientSubscriptionConfig).setCapacity(anyInt()); + Function stringToSubscriptionEvictionPolicyConverter = + arg -> SubscriptionEvictionPolicy.valueOfIgnoreCase(String.valueOf(arg)); - doAnswer(invocation -> { - subscriptionDiskStoreName.set(invocation.getArgument(0)); - return null; - }).when(mockClientSubscriptionConfig).setDiskStoreName(anyString()); + Function subscriptionEvictionPolicyToStringConverter = + arg -> Optional.ofNullable(arg).map(Object::toString).map(String::toLowerCase).orElse(null); - doAnswer(invocation -> { - subscriptionEvictionPolicy.set(SubscriptionEvictionPolicy.valueOfIgnoreCase(invocation.getArgument(0))); - return null; - }).when(mockClientSubscriptionConfig).setEvictionPolicy(anyString()); + doAnswer(newSetter(subscriptionCapacity, null)) + .when(mockClientSubscriptionConfig).setCapacity(anyInt()); - when(mockClientSubscriptionConfig.getCapacity()).thenAnswer(invocation -> subscriptionCapacity.get()); - when(mockClientSubscriptionConfig.getDiskStoreName()).thenAnswer(invocation -> subscriptionDiskStoreName.get()); - when(mockClientSubscriptionConfig.getEvictionPolicy()).thenAnswer(invocation -> - Optional.ofNullable(subscriptionEvictionPolicy.get()).map(Object::toString).map(String::toLowerCase) - .orElse(null)); + doAnswer(newSetter(subscriptionDiskStoreName, null)) + .when(mockClientSubscriptionConfig).setDiskStoreName(anyString()); + + doAnswer(newSetter(subscriptionEvictionPolicy, stringToSubscriptionEvictionPolicyConverter, null)) + .when(mockClientSubscriptionConfig).setEvictionPolicy(anyString()); + + when(mockClientSubscriptionConfig.getCapacity()).thenAnswer(newGetter(subscriptionCapacity)); + when(mockClientSubscriptionConfig.getDiskStoreName()).thenAnswer(newGetter(subscriptionDiskStoreName)); + when(mockClientSubscriptionConfig.getEvictionPolicy()).thenAnswer(newGetter(subscriptionEvictionPolicy, + subscriptionEvictionPolicyToStringConverter)); return mockClientSubscriptionConfig; } @@ -417,20 +379,14 @@ public abstract class MockGemFireObjectsSupport { AtomicReference diskUsageWarningPercentage = new AtomicReference<>(DiskStoreFactory.DEFAULT_DISK_USAGE_WARNING_PERCENTAGE); - when(mockDiskStoreFactory.setAllowForceCompaction(anyBoolean())).thenAnswer(invocation -> { - allowForceCompaction.set(invocation.getArgument(0)); - return mockDiskStoreFactory; - }); + when(mockDiskStoreFactory.setAllowForceCompaction(anyBoolean())) + .thenAnswer(newSetter(allowForceCompaction, mockDiskStoreFactory)); - when(mockDiskStoreFactory.setAutoCompact(anyBoolean())).thenAnswer(invocation -> { - autoCompact.set(invocation.getArgument(0)); - return mockDiskStoreFactory; - }); + when(mockDiskStoreFactory.setAutoCompact(anyBoolean())) + .thenAnswer(newSetter(autoCompact, mockDiskStoreFactory)); - when(mockDiskStoreFactory.setCompactionThreshold(anyInt())).thenAnswer(invocation -> { - compactionThreshold.set(invocation.getArgument(0)); - return mockDiskStoreFactory; - }); + when(mockDiskStoreFactory.setCompactionThreshold(anyInt())) + .thenAnswer(newSetter(compactionThreshold, mockDiskStoreFactory)); when(mockDiskStoreFactory.setDiskDirs(any(File[].class))).thenAnswer(invocation -> { @@ -454,35 +410,23 @@ public abstract class MockGemFireObjectsSupport { return mockDiskStoreFactory; }); - when(mockDiskStoreFactory.setDiskUsageCriticalPercentage(anyFloat())).thenAnswer(invocation -> { - diskUsageCriticalPercentage.set(invocation.getArgument(0)); - return mockDiskStoreFactory; - }); + when(mockDiskStoreFactory.setDiskUsageCriticalPercentage(anyFloat())) + .thenAnswer(newSetter(diskUsageCriticalPercentage, mockDiskStoreFactory)); - when(mockDiskStoreFactory.setDiskUsageWarningPercentage(anyFloat())).thenAnswer(invocation -> { - diskUsageWarningPercentage.set(invocation.getArgument(0)); - return mockDiskStoreFactory; - }); + when(mockDiskStoreFactory.setDiskUsageWarningPercentage(anyFloat())) + .thenAnswer(newSetter(diskUsageWarningPercentage, mockDiskStoreFactory)); - when(mockDiskStoreFactory.setMaxOplogSize(anyLong())).thenAnswer(invocation -> { - maxOplogSize.set(invocation.getArgument(0)); - return mockDiskStoreFactory; - }); + when(mockDiskStoreFactory.setMaxOplogSize(anyLong())) + .thenAnswer(newSetter(maxOplogSize, mockDiskStoreFactory)); - when(mockDiskStoreFactory.setQueueSize(anyInt())).thenAnswer(invocation -> { - queueSize.set(invocation.getArgument(0)); - return mockDiskStoreFactory; - }); + when(mockDiskStoreFactory.setQueueSize(anyInt())) + .thenAnswer(newSetter(queueSize, mockDiskStoreFactory)); - when(mockDiskStoreFactory.setTimeInterval(anyLong())).thenAnswer(invocation -> { - timeInterval.set(invocation.getArgument(0)); - return mockDiskStoreFactory; - }); + when(mockDiskStoreFactory.setTimeInterval(anyLong())) + .thenAnswer(newSetter(timeInterval, mockDiskStoreFactory)); - when(mockDiskStoreFactory.setWriteBufferSize(anyInt())).thenAnswer(invocation -> { - writeBufferSize.set(invocation.getArgument(0)); - return mockDiskStoreFactory; - }); + when(mockDiskStoreFactory.setWriteBufferSize(anyInt())) + .thenAnswer(newSetter(writeBufferSize, mockDiskStoreFactory)); when(mockDiskStoreFactory.create(anyString())).thenAnswer(invocation -> { @@ -561,95 +505,59 @@ public abstract class MockGemFireObjectsSupport { return mockPoolFactory; }); - when(mockPoolFactory.setFreeConnectionTimeout(anyInt())).thenAnswer(invocation -> { - freeConnectionTimeout.set(invocation.getArgument(0)); - return mockPoolFactory; - }); + when(mockPoolFactory.setFreeConnectionTimeout(anyInt())) + .thenAnswer(newSetter(freeConnectionTimeout, mockPoolFactory)); - when(mockPoolFactory.setIdleTimeout(anyLong())).thenAnswer(invocation -> { - idleTimeout.set(invocation.getArgument(0)); - return mockPoolFactory; - }); + when(mockPoolFactory.setIdleTimeout(anyLong())) + .thenAnswer(newSetter(idleTimeout, mockPoolFactory)); - when(mockPoolFactory.setLoadConditioningInterval(anyInt())).thenAnswer(invocation -> { - loadConditioningInterval.set(invocation.getArgument(0)); - return mockPoolFactory; - }); + when(mockPoolFactory.setLoadConditioningInterval(anyInt())) + .thenAnswer(newSetter(loadConditioningInterval, mockPoolFactory)); - when(mockPoolFactory.setMaxConnections(anyInt())).thenAnswer(invocation -> { - maxConnections.set(invocation.getArgument(0)); - return mockPoolFactory; - }); + when(mockPoolFactory.setMaxConnections(anyInt())) + .thenAnswer(newSetter(maxConnections, mockPoolFactory)); - when(mockPoolFactory.setMinConnections(anyInt())).thenAnswer(invocation -> { - minConnections.set(invocation.getArgument(0)); - return mockPoolFactory; - }); + when(mockPoolFactory.setMinConnections(anyInt())) + .thenAnswer(newSetter(minConnections, mockPoolFactory)); - when(mockPoolFactory.setMultiuserAuthentication(anyBoolean())).thenAnswer(invocation -> { - multiuserAuthentication.set(invocation.getArgument(0)); - return mockPoolFactory; - }); + when(mockPoolFactory.setMultiuserAuthentication(anyBoolean())) + .thenAnswer(newSetter(multiuserAuthentication, mockPoolFactory)); - when(mockPoolFactory.setPingInterval(anyLong())).thenAnswer(invocation -> { - pingInterval.set(invocation.getArgument(0)); - return mockPoolFactory; - }); + when(mockPoolFactory.setPingInterval(anyLong())) + .thenAnswer(newSetter(pingInterval, mockPoolFactory)); - when(mockPoolFactory.setPRSingleHopEnabled(anyBoolean())).thenAnswer(invocation -> { - prSingleHopEnabled.set(invocation.getArgument(0)); - return mockPoolFactory; - }); + when(mockPoolFactory.setPRSingleHopEnabled(anyBoolean())) + .thenAnswer(newSetter(prSingleHopEnabled, mockPoolFactory)); - when(mockPoolFactory.setReadTimeout(anyInt())).thenAnswer(invocation -> { - readTimeout.set(invocation.getArgument(0)); - return mockPoolFactory; - }); + when(mockPoolFactory.setReadTimeout(anyInt())) + .thenAnswer(newSetter(readTimeout, mockPoolFactory)); - when(mockPoolFactory.setRetryAttempts(anyInt())).thenAnswer(invocation -> { - retryAttempts.set(invocation.getArgument(0)); - return mockPoolFactory; - }); + when(mockPoolFactory.setRetryAttempts(anyInt())) + .thenAnswer(newSetter(retryAttempts, mockPoolFactory)); - when(mockPoolFactory.setServerGroup(anyString())).thenAnswer(invocation -> { - serverGroup.set(invocation.getArgument(0)); - return mockPoolFactory; - }); + when(mockPoolFactory.setServerGroup(anyString())) + .thenAnswer(newSetter(serverGroup, mockPoolFactory)); - when(mockPoolFactory.setSocketBufferSize(anyInt())).thenAnswer(invocation -> { - socketBufferSize.set(invocation.getArgument(0)); - return mockPoolFactory; - }); + when(mockPoolFactory.setSocketBufferSize(anyInt())) + .thenAnswer(newSetter(socketBufferSize, mockPoolFactory)); - when(mockPoolFactory.setStatisticInterval(anyInt())).thenAnswer(invocation -> { - statisticInterval.set(invocation.getArgument(0)); - return mockPoolFactory; - }); + when(mockPoolFactory.setStatisticInterval(anyInt())) + .thenAnswer(newSetter(statisticInterval, mockPoolFactory)); - when(mockPoolFactory.setSubscriptionAckInterval(anyInt())).thenAnswer(invocation -> { - subscriptionAckInterval.set(invocation.getArgument(0)); - return mockPoolFactory; - }); + when(mockPoolFactory.setSubscriptionAckInterval(anyInt())) + .thenAnswer(newSetter(subscriptionAckInterval, mockPoolFactory)); - when(mockPoolFactory.setSubscriptionEnabled(anyBoolean())).thenAnswer(invocation -> { - subscriptionEnabled.set(invocation.getArgument(0)); - return mockPoolFactory; - }); + when(mockPoolFactory.setSubscriptionEnabled(anyBoolean())) + .thenAnswer(newSetter(subscriptionEnabled, mockPoolFactory)); - when(mockPoolFactory.setSubscriptionMessageTrackingTimeout(anyInt())).thenAnswer(invocation -> { - subscriptionMessageTrackingTimeout.set(invocation.getArgument(0)); - return mockPoolFactory; - }); + when(mockPoolFactory.setSubscriptionMessageTrackingTimeout(anyInt())) + .thenAnswer(newSetter(subscriptionMessageTrackingTimeout, mockPoolFactory)); - when(mockPoolFactory.setSubscriptionRedundancy(anyInt())).thenAnswer(invocation -> { - subscriptionRedundancy.set(invocation.getArgument(0)); - return mockPoolFactory; - }); + when(mockPoolFactory.setSubscriptionRedundancy(anyInt())) + .thenAnswer(newSetter(subscriptionRedundancy, mockPoolFactory)); - when(mockPoolFactory.setThreadLocalConnections(anyBoolean())).thenAnswer(invocation -> { - threadLocalConnections.set(invocation.getArgument(0)); - return mockPoolFactory; - }); + when(mockPoolFactory.setThreadLocalConnections(anyBoolean())) + .thenAnswer(newSetter(threadLocalConnections, mockPoolFactory)); when(mockPoolFactory.create(anyString())).thenAnswer(invocation -> { @@ -669,7 +577,7 @@ public abstract class MockGemFireObjectsSupport { return null; }).when(mockPool).destroy(anyBoolean()); - when(mockPool.isDestroyed()).thenAnswer(invocationOnMock -> destroyed.get()); + when(mockPool.isDestroyed()).thenAnswer(newGetter(destroyed)); when(mockPool.getFreeConnectionTimeout()).thenReturn(freeConnectionTimeout.get()); when(mockPool.getIdleTimeout()).thenReturn(idleTimeout.get()); when(mockPool.getLoadConditioningInterval()).thenReturn(loadConditioningInterval.get()); @@ -715,30 +623,22 @@ public abstract class MockGemFireObjectsSupport { AtomicReference evictionOffHeapPercentage = new AtomicReference<>(ResourceManager.DEFAULT_EVICTION_PERCENTAGE); - doAnswer(invocation -> { - criticalHeapPercentage.set(invocation.getArgument(0)); - return null; - }).when(mockResourceManager).setCriticalHeapPercentage(anyFloat()); + doAnswer(newSetter(criticalHeapPercentage, null)) + .when(mockResourceManager).setCriticalHeapPercentage(anyFloat()); - doAnswer(invocation -> { - criticalOffHeapPercentage.set(invocation.getArgument(0)); - return null; - }).when(mockResourceManager).setCriticalOffHeapPercentage(anyFloat()); + doAnswer(newSetter(criticalOffHeapPercentage, null)) + .when(mockResourceManager).setCriticalOffHeapPercentage(anyFloat()); - doAnswer(invocation -> { - evictionHeapPercentage.set(invocation.getArgument(0)); - return null; - }).when(mockResourceManager).setEvictionHeapPercentage(anyFloat()); + doAnswer(newSetter(evictionHeapPercentage, null)) + .when(mockResourceManager).setEvictionHeapPercentage(anyFloat()); - doAnswer(invocation -> { - evictionOffHeapPercentage.set(invocation.getArgument(0)); - return null; - }).when(mockResourceManager).setEvictionOffHeapPercentage(anyFloat()); + doAnswer(newSetter(evictionOffHeapPercentage, null)) + .when(mockResourceManager).setEvictionOffHeapPercentage(anyFloat()); - when(mockResourceManager.getCriticalHeapPercentage()).thenAnswer(invocation -> criticalHeapPercentage.get()); - when(mockResourceManager.getCriticalOffHeapPercentage()).thenAnswer(invocation -> criticalOffHeapPercentage.get()); - when(mockResourceManager.getEvictionHeapPercentage()).thenAnswer(invocation -> evictionHeapPercentage.get()); - when(mockResourceManager.getEvictionOffHeapPercentage()).thenAnswer(invocation -> evictionOffHeapPercentage.get()); + when(mockResourceManager.getCriticalHeapPercentage()).thenAnswer(newGetter(criticalHeapPercentage)); + when(mockResourceManager.getCriticalOffHeapPercentage()).thenAnswer(newGetter(criticalOffHeapPercentage)); + when(mockResourceManager.getEvictionHeapPercentage()).thenAnswer(newGetter(evictionHeapPercentage)); + when(mockResourceManager.getEvictionOffHeapPercentage()).thenAnswer(newGetter(evictionOffHeapPercentage)); when(mockResourceManager.getRebalanceOperations()).thenReturn(Collections.emptySet()); return mockResourceManager; @@ -757,38 +657,28 @@ public abstract class MockGemFireObjectsSupport { AtomicReference pdxDiskStoreName = new AtomicReference<>(null); AtomicReference pdxSerializer = new AtomicReference<>(null); - doAnswer(invocation -> { - pdxDiskStoreName.set(invocation.getArgument(0)); - return cacheFactorySpy; - }).when(cacheFactorySpy.setPdxDiskStore(anyString())); + doAnswer(newSetter(pdxDiskStoreName, cacheFactorySpy)) + .when(cacheFactorySpy).setPdxDiskStore(anyString()); - doAnswer(invocation -> { - pdxIgnoreUnreadFields.set(invocation.getArgument(0)); - return cacheFactorySpy; - }).when(cacheFactorySpy.setPdxIgnoreUnreadFields(anyBoolean())); + doAnswer(newSetter(pdxIgnoreUnreadFields, cacheFactorySpy)) + .when(cacheFactorySpy).setPdxIgnoreUnreadFields(anyBoolean()); - doAnswer(invocation -> { - pdxPersistent.set(invocation.getArgument(0)); - return cacheFactorySpy; - }).when(cacheFactorySpy.setPdxPersistent(anyBoolean())); + doAnswer(newSetter(pdxPersistent, cacheFactorySpy)) + .when(cacheFactorySpy).setPdxPersistent(anyBoolean()); - doAnswer(invocation -> { - pdxReadSerialized.set(invocation.getArgument(0)); - return cacheFactorySpy; - }).when(cacheFactorySpy.setPdxReadSerialized(anyBoolean())); + doAnswer(newSetter(pdxReadSerialized, cacheFactorySpy)) + .when(cacheFactorySpy).setPdxReadSerialized(anyBoolean()); - doAnswer(invocation -> { - pdxSerializer.set(invocation.getArgument(0)); - return cacheFactorySpy; - }).when(cacheFactorySpy.setPdxSerializer(any(PdxSerializer.class))); + doAnswer(newSetter(pdxSerializer, cacheFactorySpy)) + .when(cacheFactorySpy).setPdxSerializer(any(PdxSerializer.class)); - doReturn(mockCache).when(cacheFactorySpy.create()); + doReturn(mockCache).when(cacheFactorySpy).create(); - when(mockCache.getPdxDiskStore()).thenAnswer(invocation -> pdxDiskStoreName.get()); - when(mockCache.getPdxIgnoreUnreadFields()).thenAnswer(invocation -> pdxIgnoreUnreadFields.get()); - when(mockCache.getPdxPersistent()).thenAnswer(invocation -> pdxPersistent.get()); - when(mockCache.getPdxReadSerialized()).thenAnswer(invocation -> pdxReadSerialized.get()); - when(mockCache.getPdxSerializer()).thenAnswer(invocation -> pdxSerializer.get()); + when(mockCache.getPdxDiskStore()).thenAnswer(newGetter(pdxDiskStoreName)); + when(mockCache.getPdxIgnoreUnreadFields()).thenAnswer(newGetter(pdxIgnoreUnreadFields)); + when(mockCache.getPdxPersistent()).thenAnswer(newGetter(pdxPersistent)); + when(mockCache.getPdxReadSerialized()).thenAnswer(newGetter(pdxReadSerialized)); + when(mockCache.getPdxSerializer()).thenAnswer(newGetter(pdxSerializer)); return cacheFactorySpy; } @@ -799,8 +689,6 @@ public abstract class MockGemFireObjectsSupport { ClientCache mockClientCache = mockClientCache(); - PoolFactory mockPoolFactory = mockPoolFactory(); - AtomicBoolean pdxIgnoreUnreadFields = new AtomicBoolean(false); AtomicBoolean pdxPersistent = new AtomicBoolean(false); AtomicBoolean pdxReadSerialized = new AtomicBoolean(false); @@ -809,132 +697,124 @@ public abstract class MockGemFireObjectsSupport { AtomicReference pdxSerializer = new AtomicReference<>(null); AtomicReference defaultPool = new AtomicReference<>(null); - doAnswer(invocation -> { - pdxDiskStoreName.set(invocation.getArgument(0)); - return clientCacheFactorySpy; - }).when(clientCacheFactorySpy.setPdxDiskStore(anyString())); + doAnswer(newSetter(pdxDiskStoreName, clientCacheFactorySpy)) + .when(clientCacheFactorySpy).setPdxDiskStore(anyString()); - doAnswer(invocation -> { - pdxIgnoreUnreadFields.set(invocation.getArgument(0)); - return clientCacheFactorySpy; - }).when(clientCacheFactorySpy.setPdxIgnoreUnreadFields(anyBoolean())); + doAnswer(newSetter(pdxIgnoreUnreadFields, clientCacheFactorySpy)) + .when(clientCacheFactorySpy).setPdxIgnoreUnreadFields(anyBoolean()); - doAnswer(invocation -> { - pdxPersistent.set(invocation.getArgument(0)); - return clientCacheFactorySpy; - }).when(clientCacheFactorySpy.setPdxPersistent(anyBoolean())); + doAnswer(newSetter(pdxPersistent, clientCacheFactorySpy)) + .when(clientCacheFactorySpy).setPdxPersistent(anyBoolean()); - doAnswer(invocation -> { - pdxReadSerialized.set(invocation.getArgument(0)); - return clientCacheFactorySpy; - }).when(clientCacheFactorySpy.setPdxReadSerialized(anyBoolean())); + doAnswer(newSetter(pdxReadSerialized, clientCacheFactorySpy)) + .when(clientCacheFactorySpy).setPdxReadSerialized(anyBoolean()); - doAnswer(invocation -> { - pdxSerializer.set(invocation.getArgument(0)); - return clientCacheFactorySpy; - }).when(clientCacheFactorySpy.setPdxSerializer(any(PdxSerializer.class))); + doAnswer(newSetter(pdxSerializer, clientCacheFactorySpy)) + .when(clientCacheFactorySpy).setPdxSerializer(any(PdxSerializer.class)); + + PoolFactory mockPoolFactory = mockPoolFactory(); doAnswer(invocation -> { mockPoolFactory.addLocator(invocation.getArgument(0), invocation.getArgument(1)); return clientCacheFactorySpy; - }).when(clientCacheFactorySpy.addPoolLocator(anyString(), anyInt())); + }).when(clientCacheFactorySpy).addPoolLocator(anyString(), anyInt()); doAnswer(invocation -> { mockPoolFactory.addServer(invocation.getArgument(0), invocation.getArgument(1)); return clientCacheFactorySpy; - }).when(clientCacheFactorySpy.addPoolServer(anyString(), anyInt())); + }).when(clientCacheFactorySpy).addPoolServer(anyString(), anyInt()); doAnswer(invocation -> { mockPoolFactory.setFreeConnectionTimeout(invocation.getArgument(0)); return clientCacheFactorySpy; - }).when(clientCacheFactorySpy.setPoolFreeConnectionTimeout(anyInt())); + }).when(clientCacheFactorySpy).setPoolFreeConnectionTimeout(anyInt()); doAnswer(invocation -> { mockPoolFactory.setIdleTimeout(invocation.getArgument(0)); return clientCacheFactorySpy; - }).when(clientCacheFactorySpy.setPoolIdleTimeout(anyLong())); + }).when(clientCacheFactorySpy).setPoolIdleTimeout(anyLong()); doAnswer(invocation -> { mockPoolFactory.setLoadConditioningInterval(invocation.getArgument(0)); return clientCacheFactorySpy; - }).when(clientCacheFactorySpy.setPoolLoadConditioningInterval(anyInt())); + }).when(clientCacheFactorySpy).setPoolLoadConditioningInterval(anyInt()); doAnswer(invocation -> { mockPoolFactory.setMaxConnections(invocation.getArgument(0)); return clientCacheFactorySpy; - }).when(clientCacheFactorySpy.setPoolMaxConnections(anyInt())); + }).when(clientCacheFactorySpy).setPoolMaxConnections(anyInt()); doAnswer(invocation -> { mockPoolFactory.setMinConnections(invocation.getArgument(0)); return clientCacheFactorySpy; - }).when(clientCacheFactorySpy.setPoolMinConnections(anyInt())); + }).when(clientCacheFactorySpy).setPoolMinConnections(anyInt()); doAnswer(invocation -> { mockPoolFactory.setMultiuserAuthentication(invocation.getArgument(0)); return clientCacheFactorySpy; - }).when(clientCacheFactorySpy.setPoolMultiuserAuthentication(anyBoolean())); + }).when(clientCacheFactorySpy).setPoolMultiuserAuthentication(anyBoolean()); doAnswer(invocation -> { mockPoolFactory.setPingInterval(invocation.getArgument(0)); return clientCacheFactorySpy; - }).when(clientCacheFactorySpy.setPoolPingInterval(anyLong())); + }).when(clientCacheFactorySpy).setPoolPingInterval(anyLong()); doAnswer(invocation -> { mockPoolFactory.setPRSingleHopEnabled(invocation.getArgument(0)); return clientCacheFactorySpy; - }).when(clientCacheFactorySpy.setPoolPRSingleHopEnabled(anyBoolean())); + }).when(clientCacheFactorySpy).setPoolPRSingleHopEnabled(anyBoolean()); doAnswer(invocation -> { mockPoolFactory.setReadTimeout(invocation.getArgument(0)); return clientCacheFactorySpy; - }).when(clientCacheFactorySpy.setPoolReadTimeout(anyInt())); + }).when(clientCacheFactorySpy).setPoolReadTimeout(anyInt()); doAnswer(invocation -> { mockPoolFactory.setRetryAttempts(invocation.getArgument(0)); return clientCacheFactorySpy; - }).when(clientCacheFactorySpy.setPoolRetryAttempts(anyInt())); + }).when(clientCacheFactorySpy).setPoolRetryAttempts(anyInt()); doAnswer(invocation -> { mockPoolFactory.setServerGroup(invocation.getArgument(0)); return clientCacheFactorySpy; - }).when(clientCacheFactorySpy.setPoolServerGroup(anyString())); + }).when(clientCacheFactorySpy).setPoolServerGroup(anyString()); doAnswer(invocation -> { mockPoolFactory.setSocketBufferSize(invocation.getArgument(0)); return clientCacheFactorySpy; - }).when(clientCacheFactorySpy.setPoolSocketBufferSize(anyInt())); + }).when(clientCacheFactorySpy).setPoolSocketBufferSize(anyInt()); doAnswer(invocation -> { mockPoolFactory.setStatisticInterval(invocation.getArgument(0)); return clientCacheFactorySpy; - }).when(clientCacheFactorySpy.setPoolStatisticInterval(anyInt())); + }).when(clientCacheFactorySpy).setPoolStatisticInterval(anyInt()); doAnswer(invocation -> { mockPoolFactory.setSubscriptionAckInterval(invocation.getArgument(0)); return clientCacheFactorySpy; - }).when(clientCacheFactorySpy.setPoolSubscriptionAckInterval(anyInt())); + }).when(clientCacheFactorySpy).setPoolSubscriptionAckInterval(anyInt()); doAnswer(invocation -> { mockPoolFactory.setSubscriptionEnabled(invocation.getArgument(0)); return clientCacheFactorySpy; - }).when(clientCacheFactorySpy.setPoolSubscriptionEnabled(anyBoolean())); + }).when(clientCacheFactorySpy).setPoolSubscriptionEnabled(anyBoolean()); doAnswer(invocation -> { mockPoolFactory.setSubscriptionMessageTrackingTimeout(invocation.getArgument(0)); return clientCacheFactorySpy; - }).when(clientCacheFactorySpy.setPoolSubscriptionMessageTrackingTimeout(anyInt())); + }).when(clientCacheFactorySpy).setPoolSubscriptionMessageTrackingTimeout(anyInt()); doAnswer(invocation -> { mockPoolFactory.setSubscriptionRedundancy(invocation.getArgument(0)); return clientCacheFactorySpy; - }).when(clientCacheFactorySpy.setPoolSubscriptionRedundancy(anyInt())); + }).when(clientCacheFactorySpy).setPoolSubscriptionRedundancy(anyInt()); doAnswer(invocation -> { mockPoolFactory.setThreadLocalConnections(invocation.getArgument(0)); return clientCacheFactorySpy; - }).when(clientCacheFactorySpy.setPoolThreadLocalConnections(anyBoolean())); + }).when(clientCacheFactorySpy).setPoolThreadLocalConnections(anyBoolean()); - doReturn(mockClientCache).when(clientCacheFactorySpy.create()); + doReturn(mockClientCache).when(clientCacheFactorySpy).create(); when(mockClientCache.getCurrentServers()).thenAnswer(invocation -> Collections.unmodifiableSet(new HashSet<>(defaultPool.get().getServers()))); @@ -948,11 +828,11 @@ public abstract class MockGemFireObjectsSupport { return defaultPool.get(); }); - when(mockClientCache.getPdxDiskStore()).thenAnswer(invocation -> pdxDiskStoreName.get()); - when(mockClientCache.getPdxIgnoreUnreadFields()).thenAnswer(invocation -> pdxIgnoreUnreadFields.get()); - when(mockClientCache.getPdxPersistent()).thenAnswer(invocation -> pdxPersistent.get()); - when(mockClientCache.getPdxReadSerialized()).thenAnswer(invocation -> pdxReadSerialized.get()); - when(mockClientCache.getPdxSerializer()).thenAnswer(invocation -> pdxSerializer.get()); + when(mockClientCache.getPdxDiskStore()).thenAnswer(newGetter(pdxDiskStoreName)); + when(mockClientCache.getPdxIgnoreUnreadFields()).thenAnswer(newGetter(pdxIgnoreUnreadFields)); + when(mockClientCache.getPdxPersistent()).thenAnswer(newGetter(pdxPersistent)); + when(mockClientCache.getPdxReadSerialized()).thenAnswer(newGetter(pdxReadSerialized)); + when(mockClientCache.getPdxSerializer()).thenAnswer(newGetter(pdxSerializer)); return clientCacheFactorySpy; } diff --git a/src/test/java/org/springframework/data/gemfire/test/mock/MockObjectsSupport.java b/src/test/java/org/springframework/data/gemfire/test/mock/MockObjectsSupport.java new file mode 100644 index 00000000..1f57fc89 --- /dev/null +++ b/src/test/java/org/springframework/data/gemfire/test/mock/MockObjectsSupport.java @@ -0,0 +1,142 @@ +/* + * 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.test.mock; + +import java.util.Map; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Function; + +import org.mockito.stubbing.Answer; + +/** + * The {@link MockObjectsSupport} class is an abstract base class encapsulating common operations and utilities + * used in mocking using Mockito. + * + * @author John Blum + * @since 2.0.0 + */ +@SuppressWarnings("unused") +public abstract class MockObjectsSupport { + + /* (non-Javadoc) */ + protected static Answer newGetter(AtomicBoolean returnValue) { + return invocation -> returnValue.get(); + } + + /* (non-Javadoc) */ + protected static Answer newGetter(AtomicInteger returnValue) { + return invocation -> returnValue.get(); + } + + /* (non-Javadoc) */ + protected static Answer newGetter(AtomicLong returnValue) { + return invocation -> returnValue.get(); + } + + /* (non-Javadoc) */ + protected static Answer newGetter(AtomicReference returnValue) { + return invocation -> returnValue.get(); + } + + /* (non-Javadoc) */ + protected static Answer newGetter(AtomicReference returnValue, Function converter) { + return invocation -> converter.apply(returnValue.get()); + } + + /* (non-Javadoc) */ + protected static Answer newSetter(AtomicBoolean argument, R returnValue) { + return invocation -> { + argument.set(invocation.getArgument(0)); + return returnValue; + }; + } + + /* (non-Javadoc) */ + protected static Answer newSetter(AtomicBoolean argument, Boolean value, R returnValue) { + return invocation -> { + argument.set(value); + return returnValue; + }; + } + + /* (non-Javadoc) */ + protected static Answer newSetter(AtomicInteger argument, R returnValue) { + return invocation -> { + argument.set(invocation.getArgument(0)); + return returnValue; + }; + } + + /* (non-Javadoc) */ + protected static Answer newSetter(AtomicInteger argument, Integer value, R returnValue) { + return invocation -> { + argument.set(value); + return returnValue; + }; + } + + /* (non-Javadoc) */ + protected static Answer newSetter(AtomicLong argument, R returnValue) { + return invocation -> { + argument.set(invocation.getArgument(0)); + return returnValue; + }; + } + + /* (non-Javadoc) */ + protected static Answer newSetter(AtomicLong argument, Long value, R returnValue) { + return invocation -> { + argument.set(value); + return returnValue; + }; + } + + /* (non-Javadoc) */ + protected static Answer newSetter(AtomicReference argument, R returnValue) { + return invocation -> { + argument.set(invocation.getArgument(0)); + return returnValue; + }; + } + + /* (non-Javadoc) */ + protected static Answer newSetter(AtomicReference argument, T value, R returnValue) { + return invocation -> { + argument.set(value); + return returnValue; + }; + } + + /* (non-Javadoc) */ + protected static Answer newSetter(AtomicReference argument, Function converter, R returnValue) { + return invocation -> { + argument.set(converter.apply(invocation.getArgument(0))); + return returnValue; + }; + } + + /* (non-Javadoc) */ + protected static Answer newSetter(Map argument, R returnValue) { + return invocation -> { + argument.put(invocation.getArgument(0), invocation.getArgument(1)); + return returnValue; + }; + } +}