From 0dfbfdf443a171c3ea4fc0ebbfaef51c7bc6c6cd Mon Sep 17 00:00:00 2001 From: John Blum Date: Mon, 1 Aug 2016 23:03:23 -0700 Subject: [PATCH] SGF-508 - Fix embedded Locator and Manager service configuration using Java-based configuration meta-data with @Enable annotations. --- .../AbstractCacheConfiguration.java | 150 +++++++++++++----- .../annotation/CacheServerApplication.java | 8 +- .../annotation/ClientCacheApplication.java | 8 +- .../EmbeddedLocatorConfiguration.java | 20 ++- .../EmbeddedManagerConfiguration.java | 34 ++-- .../annotation/EnableEmbeddedLocator.java | 33 ++-- .../annotation/EnableEmbeddedManager.java | 41 ++--- .../annotation/EnableMemcachedServer.java | 13 +- .../gemfire/config/annotation/EnablePdx.java | 31 +++- .../MemcachedServerConfiguration.java | 14 +- .../annotation/PeerCacheApplication.java | 6 +- .../EmbeddedServiceConfigurationSupport.java | 104 +++++++----- .../data/gemfire/util/ArrayUtils.java | 7 +- .../data/gemfire/util/CacheUtils.java | 1 - .../data/gemfire/util/CollectionUtils.java | 7 +- .../gemfire/util/DistributedSystemUtils.java | 6 +- .../data/gemfire/util/PropertiesBuilder.java | 119 ++++++++++++++ .../gemfire/util/CollectionUtilsTest.java | 5 +- 18 files changed, 428 insertions(+), 179 deletions(-) create mode 100644 src/main/java/org/springframework/data/gemfire/util/PropertiesBuilder.java 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 75ef85ea..ddfcda84 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 @@ -20,6 +20,7 @@ package org.springframework.data.gemfire.config.annotation; import static org.springframework.data.gemfire.CacheFactoryBean.DynamicRegionSupport; import static org.springframework.data.gemfire.CacheFactoryBean.JndiDataSource; +import java.lang.annotation.Annotation; import java.util.Collections; import java.util.List; import java.util.Map; @@ -40,6 +41,7 @@ import org.springframework.context.annotation.ImportAware; import org.springframework.core.io.Resource; import org.springframework.core.type.AnnotationMetadata; import org.springframework.data.gemfire.CacheFactoryBean; +import org.springframework.data.gemfire.util.PropertiesBuilder; import org.springframework.util.Assert; import org.springframework.util.StringUtils; @@ -57,6 +59,7 @@ import org.springframework.util.StringUtils; * @see org.springframework.beans.factory.BeanFactoryAware * @see org.springframework.context.annotation.Bean * @see org.springframework.context.annotation.ImportAware + * @see org.springframework.core.type.AnnotationMetadata * @since 1.9.0 */ @SuppressWarnings("unused") @@ -66,6 +69,8 @@ public abstract class AbstractCacheConfiguration implements BeanFactoryAware, Be protected static final boolean DEFAULT_COPY_ON_READ = false; protected static final boolean DEFAULT_USE_BEAN_FACTORY_LOCATOR = false; + protected static final int DEFAULT_MCAST_PORT = 0; + protected static final String DEFAULT_LOG_LEVEL = "config"; protected static final String DEFAULT_NAME = "SpringDataGemFireApplication"; @@ -83,6 +88,8 @@ public abstract class AbstractCacheConfiguration implements BeanFactoryAware, Be private DynamicRegionSupport dynamicRegionSupport; + private Integer mcastPort = 0; + private Float criticalHeapPercentage; private Float evictionHeapPercentage; @@ -93,12 +100,15 @@ public abstract class AbstractCacheConfiguration implements BeanFactoryAware, Be private PdxSerializer pdxSerializer; + private PropertiesBuilder customGemFireProperties = new PropertiesBuilder(); + private Resource cacheXml; private String locators = ""; private String logLevel = DEFAULT_LOG_LEVEL; private String name; private String pdxDiskStoreName; + private String startLocator; private TransactionWriter transactionWriter; @@ -174,19 +184,18 @@ public abstract class AbstractCacheConfiguration implements BeanFactoryAware, Be } /** - * Returns a {@link Properties} object containing GemFire System properties used to configure - * the GemFire cache. + * Returns a {@link Properties} object containing GemFire System properties used to configure the GemFire cache. * - * The name of the GemFire member/node is set to a pre-dined, descriptive default value depending - * on the type configuraiton applied. + * The name of the GemFire member/node in the cluster is set to a default, pre-defined, descriptive value + * depending on the type of configuration meta-data applied. * * Both 'mcast-port' and 'locators' are to set 0 and empty String respectively, which is necessary - * for {@link com.gemstone.gemfire.cache.client.ClientCache cache client}-based applications. + * for {@link com.gemstone.gemfire.cache.client.ClientCache cache client}-based applications. These values + * can be changed for peer cache and cache server applications. * - * Finally GemFire's "log-level" System property defaults to "config". + * Finally, GemFire's {@literal log-level} System property defaults to {@literal config}. * - * @return a {@link Properties} object containing GemFire System properties used to configure - * the GemFire cache. + * @return a {@link Properties} object containing GemFire System properties used to configure the GemFire cache. * @see GemFire Properties * @see java.util.Properties * @see #name() @@ -195,12 +204,16 @@ public abstract class AbstractCacheConfiguration implements BeanFactoryAware, Be */ @Bean protected Properties gemfireProperties() { - Properties gemfireProperties = new Properties(); + PropertiesBuilder gemfireProperties = new PropertiesBuilder(); + gemfireProperties.setProperty("name", name()); - gemfireProperties.setProperty("mcast-port", "0"); + gemfireProperties.setProperty("mcast-port", mcastPort()); gemfireProperties.setProperty("log-level", logLevel()); gemfireProperties.setProperty("locators", locators()); - return gemfireProperties; + gemfireProperties.setProperty("start-locator", startLocator()); + gemfireProperties.add(customGemFireProperties); + + return gemfireProperties.build(); } /* @@ -213,7 +226,7 @@ public abstract class AbstractCacheConfiguration implements BeanFactoryAware, Be } /** - * Gets a reference to the {@link ClassLoader} use by the Spring {@link BeanFactory} to load classes + * Returns a reference to the {@link ClassLoader} use by the Spring {@link BeanFactory} to load classes * for bean definitions. * * @return the {@link ClassLoader} used by the Spring {@link BeanFactory} to load classes for bean definitions. @@ -233,7 +246,7 @@ public abstract class AbstractCacheConfiguration implements BeanFactoryAware, Be } /** - * Gets a reference to the Spring {@link BeanFactory} in the current application context. + * Returns a reference to the Spring {@link BeanFactory} in the current application context. * * @return a reference to the Spring {@link BeanFactory}. * @throws IllegalStateException if the Spring {@link BeanFactory} was not properly initialized. @@ -252,6 +265,7 @@ public abstract class AbstractCacheConfiguration implements BeanFactoryAware, Be @Override public void setImportMetadata(AnnotationMetadata importMetadata) { configureCache(importMetadata); + configureMemcachedServer(importMetadata); configurePdx(importMetadata); configureOther(importMetadata); } @@ -287,6 +301,32 @@ public abstract class AbstractCacheConfiguration implements BeanFactoryAware, Be } } + /** + * Configures the embedded GemFire Memcached Server (Gemcached) service in a GemFire server/data node. + * + * @param importMetadata {@link AnnotationMetadata} containing the Gemcached meta-data used to configure + * the embedded GemFire Memcached Server (Gemcached) service. + * @see org.springframework.core.type.AnnotationMetadata + */ + protected void configureMemcachedServer(AnnotationMetadata importMetadata) { + if (isCacheServerApplication(importMetadata) || isPeerCacheApplication(importMetadata)) { + if (importMetadata.hasAnnotation(EnableMemcachedServer.class.getName())) { + Map enableMemcachedServerAttributes = + importMetadata.getAnnotationAttributes(EnableMemcachedServer.class.getName()); + + Properties gemfireMemcachedProperties = new Properties(); + + gemfireMemcachedProperties.setProperty("memcached-port", + String.valueOf(enableMemcachedServerAttributes.get("port"))); + + gemfireMemcachedProperties.setProperty("memcached-protocol", + String.valueOf(enableMemcachedServerAttributes.get("protocol"))); + + add(gemfireMemcachedProperties); + } + } + } + /** * Configures GemFire's PDX Serialization feature. * @@ -367,12 +407,10 @@ public abstract class AbstractCacheConfiguration implements BeanFactoryAware, Be * from the annotations used to configure the Spring application. * @return a boolean value indicating whether this is a GemFire cache server application. * @see org.springframework.data.gemfire.config.annotation.CacheServerApplication - * @see #getAnnotationTypeName() - * @see #getAnnotationType() + * @see #isTypedCacheApplication(Class, AnnotationMetadata) */ protected boolean isCacheServerApplication(AnnotationMetadata importMetadata) { - return (CacheServerApplication.class.equals(getAnnotationType()) - && importMetadata.hasAnnotation(getAnnotationTypeName())); + return isTypedCacheApplication(CacheServerApplication.class, importMetadata); } /** @@ -384,12 +422,10 @@ public abstract class AbstractCacheConfiguration implements BeanFactoryAware, Be * from the annotations used to configure the Spring application. * @return a boolean value indicating whether this is a GemFire cache client application. * @see org.springframework.data.gemfire.config.annotation.ClientCacheApplication - * @see #getAnnotationTypeName() - * @see #getAnnotationType() + * @see #isTypedCacheApplication(Class, AnnotationMetadata) */ protected boolean isClientCacheApplication(AnnotationMetadata importMetadata) { - return (ClientCacheApplication.class.equals(getAnnotationType()) - && importMetadata.hasAnnotation(getAnnotationTypeName())); + return isTypedCacheApplication(ClientCacheApplication.class, importMetadata); } /** @@ -401,21 +437,38 @@ public abstract class AbstractCacheConfiguration implements BeanFactoryAware, Be * from the annotations used to configure the Spring application. * @return a boolean value indicating whether this is a GemFire peer cache application. * @see org.springframework.data.gemfire.config.annotation.PeerCacheApplication + * @see #isTypedCacheApplication(Class, AnnotationMetadata) + */ + protected boolean isPeerCacheApplication(AnnotationMetadata importMetadata) { + return isTypedCacheApplication(PeerCacheApplication.class, importMetadata); + } + + /** + * Determines whether this Spring application is annotated with the given GemFire cache type annotation. + * + * @param annotationType {@link Annotation} cache type. + * @param importMetadata {@link AnnotationMetadata} containing application configuration meta-data + * from the annotations used to configure the Spring application. + * @return a boolean value indicating if this Spring application is annotated with the given GemFire + * cache type annotation. + * @see org.springframework.core.type.AnnotationMetadata + * @see java.lang.annotation.Annotation * @see #getAnnotationTypeName() * @see #getAnnotationType() */ - protected boolean isPeerCacheApplication(AnnotationMetadata importMetadata) { - return (PeerCacheApplication.class.equals(getAnnotationType()) - && importMetadata.hasAnnotation(getAnnotationTypeName())); + protected boolean isTypedCacheApplication(Class annotationType, + AnnotationMetadata importMetadata) { + + return (annotationType.equals(getAnnotationType()) && importMetadata.hasAnnotation(getAnnotationTypeName())); } /** * Determine whether this Spring application is a {@link com.gemstone.gemfire.cache.server.CacheServer}, - * {@link com.gemstone.gemfire.cache.client.ClientCache} or a {@link com.gemstone.gemfire.cache.Cache} application + * {@link com.gemstone.gemfire.cache.client.ClientCache} or a {@link com.gemstone.gemfire.cache.Cache} application. * * @param importMetadata {@link AnnotationMetadata} containing application configuration meta-data - * from the annotations used to configure the Spring application. - * @return a boolean value indicating whether this is a GemFire cache server, client cache or peer cache, + * from the class type-level annotations used to configure the Spring application. + * @return a boolean value indicating whether this is a GemFire cache server, client cache or peer cache * Spring application. * @see #isCacheServerApplication(AnnotationMetadata) * @see #isClientCacheApplication(AnnotationMetadata) @@ -427,12 +480,13 @@ public abstract class AbstractCacheConfiguration implements BeanFactoryAware, Be } /** - * Constructs a new, initialized instance of the {@link CacheFactoryBean} based on the application - * GemFire cache type (i.e. client or peer). + * Constructs a new, initialized instance of the {@link CacheFactoryBean} based on the Spring application's + * GemFire cache type (i.e. client or peer) preference specified via annotation. * * @param Class type of the {@link CacheFactoryBean}. - * @return a new instance of the {@link CacheFactoryBean} for the particular application GemFire cache type - * (i.e client or peer). + * @return a new instance of an appropriate {@link CacheFactoryBean} given the Spring application's + * GemFire cache type preference (i.e client or peer) specified with the corresponding annotation + * (e.g. {@link ClientCacheApplication} or {@link PeerCacheApplication}); * @see org.springframework.data.gemfire.client.ClientCacheFactoryBean * @see org.springframework.data.gemfire.CacheFactoryBean * @see #setCommonCacheConfiguration(CacheFactoryBean) @@ -443,12 +497,13 @@ public abstract class AbstractCacheConfiguration implements BeanFactoryAware, Be } /** - * Constructs a new, uninitialized instance of the {@link CacheFactoryBean} based on the application - * GemFire cache type (i.e. client or peer). + * Constructs a new, uninitialized instance of the {@link CacheFactoryBean} based on the Spring application's + * GemFire cache type (i.e. client or peer) preference specified via annotation. * * @param Class type of the {@link CacheFactoryBean}. - * @return a new instance of the {@link CacheFactoryBean} for the particular application GemFire cache type - * (i.e client or peer). + * @return a new instance of an appropriate {@link CacheFactoryBean} given the Spring application's + * GemFire cache type preference (i.e client or peer) specified with the corresponding annotation + * (e.g. {@link ClientCacheApplication} or {@link PeerCacheApplication}). * @see org.springframework.data.gemfire.client.ClientCacheFactoryBean * @see org.springframework.data.gemfire.CacheFactoryBean */ @@ -458,7 +513,7 @@ public abstract class AbstractCacheConfiguration implements BeanFactoryAware, Be * Configures common GemFire cache configuration settings. * * @param Class type of the {@link CacheFactoryBean}. - * @param gemfireCache specific {@link CacheFactoryBean} instance to configure. + * @param gemfireCache {@link CacheFactoryBean} instance to configure. * @return the given {@link CacheFactoryBean} after common configuration settings have been applied. * @see org.springframework.data.gemfire.client.ClientCacheFactoryBean * @see org.springframework.data.gemfire.CacheFactoryBean @@ -558,6 +613,7 @@ public abstract class AbstractCacheConfiguration implements BeanFactoryAware, Be return nullSafeList(this.jndiDataSources); } + /* (non-Javadoc) */ void setLocators(String locators) { this.locators = locators; } @@ -575,6 +631,15 @@ public abstract class AbstractCacheConfiguration implements BeanFactoryAware, Be return nullSafeValue(this.logLevel, DEFAULT_LOG_LEVEL); } + void setMcastPort(Integer mcastPort) { + this.mcastPort = mcastPort; + } + + protected Integer mcastPort() { + return (mcastPort != null ? mcastPort : DEFAULT_MCAST_PORT); + } + + /* (non-Javadoc) */ void setName(String name) { this.name = name; } @@ -628,6 +693,15 @@ public abstract class AbstractCacheConfiguration implements BeanFactoryAware, Be return this.pdxSerializer; } + /* (non-Javadoc) */ + void setStartLocator(String startLocator) { + this.startLocator = startLocator; + } + + protected String startLocator() { + return this.startLocator; + } + /* (non-Javadoc) */ void setTransactionListeners(List transactionListeners) { this.transactionListeners = transactionListeners; @@ -655,6 +729,10 @@ public abstract class AbstractCacheConfiguration implements BeanFactoryAware, Be return this.useBeanFactoryLocator; } + public void add(Properties gemfireProperties) { + customGemFireProperties.add(gemfireProperties); + } + @Override public String toString() { return DEFAULT_NAME; 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 f4782fb3..e07087b8 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 @@ -60,7 +60,7 @@ public @interface CacheServerApplication { /** * Configures whether the {@link CacheServer} should start automatically at runtime. * - * Default is {@code true). + * Default is {@literal true). */ boolean autoStartup() default true; @@ -74,7 +74,7 @@ public @interface CacheServerApplication { /** * Indicates whether the "copy on read" is enabled for this cache. * - * Default is {@code false}. + * Default is {@literal false}. */ boolean copyOnRead() default false; @@ -90,7 +90,7 @@ 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 {@code false}. + * Default is {@literal false}. */ boolean enableAutoReconnect() default false; @@ -238,7 +238,7 @@ 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 {@code false}. + * Default is {@literal false}. */ boolean useClusterConfiguration() default false; 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 d5e28b6b..d97b1b6b 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 @@ -55,7 +55,7 @@ public @interface ClientCacheApplication { /** * Indicates whether the "copy on read" is enabled for this cache. * - * Default is {@code false}. + * Default is {@literal false}. */ boolean copyOnRead() default false; @@ -104,7 +104,7 @@ public @interface ClientCacheApplication { /** * Configures whether to keep the client queues alive on the server when the client is disconnected * - * Default is {@code false}. + * Default is {@literal false}. */ boolean keepAlive() default false; @@ -164,7 +164,7 @@ public @interface ClientCacheApplication { long pingInterval() default PoolFactory.DEFAULT_PING_INTERVAL; /** - * By default {@code prSingleHopEnabled} is {@code true} in which case the client is aware of the location + * 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 com.gemstone.gemfire.cache.DataPolicy#PARTITION}. * * @see com.gemstone.gemfire.cache.client.PoolFactory#DEFAULT_PR_SINGLE_HOP_ENABLED @@ -182,7 +182,7 @@ public @interface ClientCacheApplication { /** * Notifies the server that this durable client is ready to receive updates. * - * Default is {@code false}. + * Default is {@literal false}. */ boolean readyForEvents() default false; diff --git a/src/main/java/org/springframework/data/gemfire/config/annotation/EmbeddedLocatorConfiguration.java b/src/main/java/org/springframework/data/gemfire/config/annotation/EmbeddedLocatorConfiguration.java index eae66619..36576bdb 100644 --- a/src/main/java/org/springframework/data/gemfire/config/annotation/EmbeddedLocatorConfiguration.java +++ b/src/main/java/org/springframework/data/gemfire/config/annotation/EmbeddedLocatorConfiguration.java @@ -20,19 +20,26 @@ package org.springframework.data.gemfire.config.annotation; import java.util.Map; import java.util.Properties; +import org.springframework.data.gemfire.GemfireUtils; import org.springframework.data.gemfire.config.annotation.support.EmbeddedServiceConfigurationSupport; +import org.springframework.data.gemfire.util.PropertiesBuilder; /** - * The EmbeddedManagerConfiguration class is a Spring {@link org.springframework.context.annotation.ImportBeanDefinitionRegistrar} + * The EmbeddedLocatorConfiguration 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. * * @author John Blum - * @see EmbeddedServiceConfigurationSupport + * @see org.springframework.data.gemfire.config.annotation.EnableEmbeddedLocator + * @see org.springframework.data.gemfire.config.annotation.support.EmbeddedServiceConfigurationSupport * @since 1.9.0 */ public class EmbeddedLocatorConfiguration 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"; + @Override protected Class getAnnotationType() { return EnableEmbeddedLocator.class; @@ -40,10 +47,11 @@ public class EmbeddedLocatorConfiguration extends EmbeddedServiceConfigurationSu @Override protected Properties toGemFireProperties(Map annotationAttributes) { - Properties gemfireProperties = new Properties(); + String host = resolveHost((String) annotationAttributes.get("host")); + int port = resolvePort((Integer) annotationAttributes.get("port"), DEFAULT_LOCATOR_PORT); - setProperty(gemfireProperties, "start-locator", annotationAttributes.get("startLocator")); - - return gemfireProperties; + return new PropertiesBuilder() + .setProperty(START_LOCATOR_GEMFIRE_SYSTEM_PROPERTY_NAME, String.format("%s[%d]", host, port)) + .build(); } } diff --git a/src/main/java/org/springframework/data/gemfire/config/annotation/EmbeddedManagerConfiguration.java b/src/main/java/org/springframework/data/gemfire/config/annotation/EmbeddedManagerConfiguration.java index c49e9cc1..a2937c03 100644 --- a/src/main/java/org/springframework/data/gemfire/config/annotation/EmbeddedManagerConfiguration.java +++ b/src/main/java/org/springframework/data/gemfire/config/annotation/EmbeddedManagerConfiguration.java @@ -21,6 +21,7 @@ import java.util.Map; import java.util.Properties; import org.springframework.data.gemfire.config.annotation.support.EmbeddedServiceConfigurationSupport; +import org.springframework.data.gemfire.util.PropertiesBuilder; /** * The EmbeddedManagerConfiguration class is a Spring {@link org.springframework.context.annotation.ImportBeanDefinitionRegistrar} @@ -28,11 +29,14 @@ import org.springframework.data.gemfire.config.annotation.support.EmbeddedServic * an embedded GemFire Manager. * * @author John Blum - * @see EmbeddedServiceConfigurationSupport + * @see org.springframework.data.gemfire.config.annotation.EnableEmbeddedManager + * @see org.springframework.data.gemfire.config.annotation.support.EmbeddedServiceConfigurationSupport * @since 1.9.0 */ public class EmbeddedManagerConfiguration extends EmbeddedServiceConfigurationSupport { + protected static final int DEFAULT_JMX_MANAGER_PORT = 1099; + @Override protected Class getAnnotationType() { return EnableEmbeddedManager.class; @@ -40,30 +44,30 @@ public class EmbeddedManagerConfiguration extends EmbeddedServiceConfigurationSu @Override protected Properties toGemFireProperties(Map annotationAttributes) { - Properties gemfireProperties = new Properties(); + PropertiesBuilder gemfireProperties = new PropertiesBuilder(); boolean jmxManager = Boolean.valueOf(String.valueOf(annotationAttributes.get("jmxManager"))); if (jmxManager) { - setProperty(gemfireProperties, "jmx-manager", Boolean.TRUE.toString()); - setProperty(gemfireProperties, "jmx-manager-access-file", annotationAttributes.get("jmxManagerAccessFile")); - setProperty(gemfireProperties, "jmx-manager-bind-address", annotationAttributes.get("jmxManagerBindAddress")); - setProperty(gemfireProperties, "jmx-manager-hostname-for-clients", annotationAttributes.get("jmxManagerHostnameForClients")); - setProperty(gemfireProperties, "jmx-manager-password-file", annotationAttributes.get("jmxManagerPasswordFile")); - setProperty(gemfireProperties, "jmx-manager-port", annotationAttributes.get("jmxManagerPort")); - setProperty(gemfireProperties, "jmx-manager-start", annotationAttributes.get("jmxManagerStart")); - setProperty(gemfireProperties, "jmx-manager-update-rate", annotationAttributes.get("jmxManagerUpdateRate")); + gemfireProperties.setProperty("jmx-manager", Boolean.TRUE.toString()); + gemfireProperties.setProperty("jmx-manager-access-file", annotationAttributes.get("jmxManagerAccessFile")); + gemfireProperties.setProperty("jmx-manager-bind-address", annotationAttributes.get("jmxManagerBindAddress")); + gemfireProperties.setProperty("jmx-manager-hostname-for-clients", annotationAttributes.get("jmxManagerHostnameForClients")); + gemfireProperties.setProperty("jmx-manager-password-file", annotationAttributes.get("jmxManagerPasswordFile")); + gemfireProperties.setProperty("jmx-manager-port", resolvePort((Integer) annotationAttributes.get("jmxManagerPort"), DEFAULT_JMX_MANAGER_PORT)); + gemfireProperties.setProperty("jmx-manager-start", annotationAttributes.get("jmxManagerStart")); + gemfireProperties.setProperty("jmx-manager-update-rate", annotationAttributes.get("jmxManagerUpdateRate")); boolean jmxManagerSslEnabled = Boolean.valueOf(String.valueOf(annotationAttributes.get("jmxManagerSslEnabled"))); if (jmxManagerSslEnabled) { - setProperty(gemfireProperties, "jmx-manager-ssl-enabled", Boolean.TRUE.toString()); - setProperty(gemfireProperties, "jmx-manager-ssl-ciphers", annotationAttributes.get("jmxManagerSslCiphers")); - setProperty(gemfireProperties, "jmx-manager-ssl-protocols", annotationAttributes.get("jmxManagerSslProtocols")); - setProperty(gemfireProperties, "jmx-manager-ssl-require-authentication", annotationAttributes.get("jmxManagerSslRequireAuthentication")); + gemfireProperties.setProperty("jmx-manager-ssl-enabled", Boolean.TRUE.toString()); + gemfireProperties.setProperty("jmx-manager-ssl-ciphers", annotationAttributes.get("jmxManagerSslCiphers")); + gemfireProperties.setProperty("jmx-manager-ssl-protocols", annotationAttributes.get("jmxManagerSslProtocols")); + gemfireProperties.setProperty("jmx-manager-ssl-require-authentication", annotationAttributes.get("jmxManagerSslRequireAuthentication")); } } - return gemfireProperties; + return gemfireProperties.build(); } } diff --git a/src/main/java/org/springframework/data/gemfire/config/annotation/EnableEmbeddedLocator.java b/src/main/java/org/springframework/data/gemfire/config/annotation/EnableEmbeddedLocator.java index d5652d8f..3109cf2c 100644 --- a/src/main/java/org/springframework/data/gemfire/config/annotation/EnableEmbeddedLocator.java +++ b/src/main/java/org/springframework/data/gemfire/config/annotation/EnableEmbeddedLocator.java @@ -27,37 +27,36 @@ import java.lang.annotation.Target; import org.springframework.context.annotation.Import; /** - * The EnableEmbeddedLocator annotation marks a Spring {@link org.springframework.context.annotation.Configuration} - * class to embed a GemFire Locator service in the GemFire server-side data member node. + * The EnableEmbeddedLocator annotation marks a Spring {@link org.springframework.context.annotation.Configuration @Configuration} + * annotated class to start an embedded GemFire Locator service in this GemFire server/data node. * * @author John Blum + * @see org.springframework.context.annotation.Import * @see org.springframework.data.gemfire.config.annotation.EmbeddedLocatorConfiguration * @since 1.9.0 */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) -@Documented @Inherited +@Documented @Import(EmbeddedLocatorConfiguration.class) @SuppressWarnings("unused") public @interface EnableEmbeddedLocator { /** - * If set, automatically starts a Locator in the current process when the member connects to the distributed system - * and stops the Locator when the member disconnects. - * To use, specify the Locator with an optional address or host specification and a required port number, in one of - * these formats: + * Configures the host/IP address on which the embedded Locator service will bind to for accepting connections + * from clients sending Locator requests. * - * start-locator=address[port1] - * - * start-locator=port1 - * - * If you only specify the port, the address assigned to the member is used for the Locator. - * If not already there, this locator is automatically added to the list of Locators in this - * set of GemFire Properties. - * - * Defaults to {@literal 10334} (The default GemFire Locator port). + * Default is {@literal localhost}. */ - String startLocator() default "localhost[10334]"; + String host() default EmbeddedLocatorConfiguration.DEFAULT_HOST; + + /** + * Configures the port on which the embedded Locator service will bind to listening for client connections + * sending Locator requests. + * + * Default is {@literal 10334}. + */ + int port() default EmbeddedLocatorConfiguration.DEFAULT_LOCATOR_PORT; } diff --git a/src/main/java/org/springframework/data/gemfire/config/annotation/EnableEmbeddedManager.java b/src/main/java/org/springframework/data/gemfire/config/annotation/EnableEmbeddedManager.java index 41f18a21..b9c215d7 100644 --- a/src/main/java/org/springframework/data/gemfire/config/annotation/EnableEmbeddedManager.java +++ b/src/main/java/org/springframework/data/gemfire/config/annotation/EnableEmbeddedManager.java @@ -27,27 +27,28 @@ import java.lang.annotation.Target; import org.springframework.context.annotation.Import; /** - * The EnableEmbeddedLocator annotation marks a Spring {@link org.springframework.context.annotation.Configuration} - * class to embed a GemFire Manager service in the GemFire server-side data member node. + * The EnableEmbeddedManager annotation marks a Spring {@link org.springframework.context.annotation.Configuration @Configuration} + * annotated class to embed and start a GemFire Manager service in the GemFire server/data node. * * @author John Blum + * @see org.springframework.context.annotation.Import * @see org.springframework.data.gemfire.config.annotation.EmbeddedManagerConfiguration * @since 1.9.0 */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) -@Documented @Inherited +@Documented @Import(EmbeddedManagerConfiguration.class) @SuppressWarnings("unused") public @interface EnableEmbeddedManager { /** - * If {@code true} then this member is willing to be a JMX Manager. All the other JMX Manager properties will be - * used when it does become a manager. If this property is {@code false} then all other jmx-manager-* properties + * If {@literal true} then this member is willing to be a JMX Manager. All the other JMX Manager properties will be + * used when it does become a manager. If this property is {@literal false} then all other jmx-manager-* properties * are ignored. * - * Defaults to {@code true}. + * Defaults to {@literal true}. */ boolean jmxManager() default true; @@ -64,46 +65,46 @@ public @interface EnableEmbeddedManager { /** * By default, the JMX Manager (when configured with a port) will listen on all the local host's addresses. * You can use this property to configure what IP address or host name the JMX Manager will listen on for - * non-HTTP connections. Ignored if JMX Manager is {@code false} or {@literal jmx-manager-port} is zero. + * non-HTTP connections. Ignored if JMX Manager is {@literal false} or {@literal jmx-manager-port} is zero. * * Defaults to {@literal localhost}. */ - String jmxManagerBindAddress() default "localhost"; + String jmxManagerBindAddress() default ""; /** * Lets you control what hostname will be given to clients that ask the Locator for the location of a JMX Manager. * By default, the IP address that the JMX Manager reports is used. But for clients on a different network * this property allows you to configure a different hostname that will be given to clients. Ignored if - * {@literal jmx-manager} is {@code false} or {@literal jmx-manager-port} is zero. + * {@literal jmx-manager} is {@literal false} or {@literal jmx-manager-port} is zero. * * Defaults to {@literal localhost}. */ - String jmxManagerHostnameForClients() default "localhost"; + String jmxManagerHostnameForClients() default ""; /** * By default, the JMX Manager will allow clients without credentials to connect. If this property is set to * the name of a file then only clients that connect with credentials that match an entry in this file will * be allowed. Most JVMs require that the file is only readable by the owner. For more information about the * format of this file see Oracle's documentation of the {@literal com.sun.management.jmxremote.password.file} - * System property. Ignored if {@literal jmx-manager} is {@code false} or {@literal jmx-manager-port} is zero. + * System property. Ignored if {@literal jmx-manager} is {@literal false} or {@literal jmx-manager-port} is zero. */ String jmxManagerPasswordFile() default ""; /** * The port this JMX Manager will listen to for client connections. If this property is set to zero then GemFire * will not allow remote client connections but you can alternatively use the standard System properties supported - * by the JVM for configuring access from remote JMX clients. Ignored if {@literal jmx-manager} is {@code false}. + * by the JVM for configuring access from remote JMX clients. Ignored if {@literal jmx-manager} is {@literal false}. * * Defaults to {@literal 1099}. */ - int jmxManagerPort() default 1099; + int jmxManagerPort() default EmbeddedManagerConfiguration.DEFAULT_JMX_MANAGER_PORT; /** - * Enables or disables SSL for connections to the JMX Manager. If {@code true} and {@literal jmx-manager-port} + * Enables or disables SSL for connections to the JMX Manager. If {@literal true} and {@literal jmx-manager-port} * is not zero, then the JMX Manager will only accept SSL connections. If this property is not set, then GemFire * uses the value of {@literal cluster-ssl-enabled} to determine whether JMX connections should use SSL. * - * Defaults to {@code false}. + * Defaults to {@literal false}. */ boolean jmxManagerSslEnabled() default false; @@ -130,17 +131,17 @@ public @interface EnableEmbeddedManager { * then GemFire uses the value of {@literal cluster-ssl-require-authentication} to determine whether JMX connections * require authentication. * - * Defaults to {@code true}. + * Defaults to {@literal true}. */ boolean jmxManagerSslRequireAuthentication() default true; /** * If true then this member will start a JMX Manager when it creates a cache. Management tools like Gfsh can be * configured to connect to the JMX Manager. In most cases you should not set this because a JMX Manager will - * automatically be started when needed on a member that sets {@literal jmx-manager} to {@code true}. Ignored if - * {@literal jmx-manager} is {@code false}. + * automatically be started when needed on a member that sets {@literal jmx-manager} to {@literal true}. Ignored if + * {@literal jmx-manager} is {@literal false}. * - * Defaults to {@code false}. + * Defaults to {@literal false}. */ boolean jmxManagerStart() default false; @@ -149,7 +150,7 @@ public @interface EnableEmbeddedManager { * should be greater than or equal to the {@literal statistic-sample-rate}. Setting this value too high will * cause stale values to be seen by Gfsh and GemFire Pulse. * - * Defaults to {@code 2000}. + * Defaults to {@literal 2000}. */ int jmxManagerUpdateRate() default 2000; 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 5f893d22..70037210 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 @@ -27,20 +27,21 @@ import java.lang.annotation.Target; import org.springframework.context.annotation.Import; /** - * The EnableMemcachedServer annotation marks a Spring {@link org.springframework.context.annotation.Configuration} - * class to embed the Gemcached service in the GemFire server-side data member node. + * 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 Gemcached service implements the Memcached server protocol enabling Memcached clients to connect and speak - * to Pivotal GemFire or Apache Geode. + * The Gemcached service implements the Memcached Server protocol enabling Memcached clients to connect to + * and communicate with Pivotal GemFire or Apache Geode servers. * * @author John Blum + * @see org.springframework.context.annotation.Import * @see org.springframework.data.gemfire.config.annotation.MemcachedServerConfiguration * @since 1.9.0 */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) -@Documented @Inherited +@Documented @Import(MemcachedServerConfiguration.class) @SuppressWarnings("unused") public @interface EnableMemcachedServer { @@ -51,7 +52,7 @@ public @interface EnableMemcachedServer { * * Default to {@literal 11211}. */ - int port() default 11211; + int port() default MemcachedServerConfiguration.DEFAULT_MEMCACHED_SERVER_PORT; /** * Sets the protocol used by an embedded Gemcached server. Valid values are BINARY and ASCII. 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 00ce061b..c48d4bc1 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 @@ -25,26 +25,49 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** - * The EnablePdx class... + * 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. * * @author John Blum - * @since 1.0.0 + * @since 1.9.0 */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) -@Documented @Inherited +@Documented @SuppressWarnings("unused") public @interface EnablePdx { - String diskStoreName(); + /** + * Configures the disk store that is used for PDX meta data. + */ + String diskStoreName() default ""; + /** + * Configures whether pdx ignores fields that were unread during deserialization. + * + * Default is {@literal false}. + */ boolean ignoreUnreadFields() default false; + /** + * Configures whether the type metadata for PDX objects is persisted to disk. + * + * Default is {@literal false}. + */ boolean persistent() default false; + /** + * Configures the object preference to {@link com.gemstone.gemfire.pdx.PdxInstance} type or {@link Object}. + * + * Default is {@literal false}. + */ boolean readSerialized() default false; + /** + * Configures the PDX serializer to be used by the cache to serialize object data. + */ String serializerBeanName() default ""; } 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 4d61550a..c92faded 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 @@ -21,6 +21,7 @@ import java.util.Map; import java.util.Properties; 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} @@ -28,11 +29,14 @@ import org.springframework.data.gemfire.config.annotation.support.EmbeddedServic * an embedded Memcached server. * * @author John Blum + * @see org.springframework.data.gemfire.config.annotation.EnableMemcachedServer * @see org.springframework.data.gemfire.config.annotation.support.EmbeddedServiceConfigurationSupport * @since 1.9.0 */ public class MemcachedServerConfiguration extends EmbeddedServiceConfigurationSupport { + protected static final int DEFAULT_MEMCACHED_SERVER_PORT = 11211; + @Override protected Class getAnnotationType() { return EnableMemcachedServer.class; @@ -40,11 +44,9 @@ public class MemcachedServerConfiguration extends EmbeddedServiceConfigurationSu @Override protected Properties toGemFireProperties(Map annotationAttributes) { - Properties gemfireProperties = new Properties(); - - setProperty(gemfireProperties, "memcached-port", annotationAttributes.get("port")); - setProperty(gemfireProperties, "memcached-protocol", annotationAttributes.get("protocol")); - - return gemfireProperties; + return new PropertiesBuilder() + .setProperty("memcached-port", resolvePort((Integer) annotationAttributes.get("port"), DEFAULT_MEMCACHED_SERVER_PORT)) + .setProperty("memcached-protocol", annotationAttributes.get("protocol")) + .build(); } } 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 dde9e25a..bf7cd3dd 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 @@ -52,7 +52,7 @@ public @interface PeerCacheApplication { /** * Indicates whether the "copy on read" is enabled for this cache. * - * Default is {@code false}. + * Default is {@literal false}. */ boolean copyOnRead() default false; @@ -68,7 +68,7 @@ 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 {@code false}. + * Default is {@literal false}. */ boolean enableAutoReconnect() default false; @@ -133,7 +133,7 @@ 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 {@code false}. + * Default is {@literal false}. */ boolean useClusterConfiguration() default false; diff --git a/src/main/java/org/springframework/data/gemfire/config/annotation/support/EmbeddedServiceConfigurationSupport.java b/src/main/java/org/springframework/data/gemfire/config/annotation/support/EmbeddedServiceConfigurationSupport.java index 2f79ebe3..9a882511 100644 --- a/src/main/java/org/springframework/data/gemfire/config/annotation/support/EmbeddedServiceConfigurationSupport.java +++ b/src/main/java/org/springframework/data/gemfire/config/annotation/support/EmbeddedServiceConfigurationSupport.java @@ -21,6 +21,7 @@ import java.util.Map; import java.util.Properties; import org.springframework.beans.BeansException; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.config.BeanDefinitionHolder; import org.springframework.beans.factory.config.BeanPostProcessor; import org.springframework.beans.factory.support.BeanDefinitionBuilder; @@ -28,6 +29,7 @@ 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.AbstractCacheConfiguration; import org.springframework.data.gemfire.util.CollectionUtils; import org.springframework.util.Assert; import org.springframework.util.StringUtils; @@ -42,42 +44,21 @@ import org.springframework.util.StringUtils; */ public abstract class EmbeddedServiceConfigurationSupport implements ImportBeanDefinitionRegistrar { - /* (non-Javadoc) */ - protected static Properties setProperty(Properties properties, String key, Object value) { - if (value != null) { - setProperty(properties, key, value.toString()); - } + public static final String DEFAULT_HOST = "localhost"; - return properties; + @Autowired + @SuppressWarnings("all") + private AbstractCacheConfiguration cacheConfiguration; + + /* (non-Javadoc) */ + @SuppressWarnings("unchecked") + protected T cacheConfiguration() { + Assert.state(cacheConfiguration != null, "AbstractCacheConfiguration was not properly initialized"); + return (T) this.cacheConfiguration; } /* (non-Javadoc) */ - protected static Properties setProperty(Properties properties, String key, String value) { - Assert.notNull(properties, "Properties must not be null"); - Assert.hasText(key, "Key must not be null or empty"); - - if (StringUtils.hasText(value)) { - properties.setProperty(key, value); - } - - return properties; - } - - /* (non-Javadoc) */ - @Override - public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { - - if (importingClassMetadata.hasAnnotation(getAnnotationTypeName())) { - Map annotationAttributes = - importingClassMetadata.getAnnotationAttributes(getAnnotationTypeName()); - - Properties customizedGemFireProperties = toGemFireProperties(annotationAttributes); - - if (!CollectionUtils.isEmpty(customizedGemFireProperties)) { - registerGemFirePropertiesBeanPostProcessor(registry, customizedGemFireProperties); - } - } - } + protected abstract Class getAnnotationType(); /* (non-Javadoc) */ protected String getAnnotationTypeName() { @@ -90,33 +71,70 @@ public abstract class EmbeddedServiceConfigurationSupport implements ImportBeanD } /* (non-Javadoc) */ - protected abstract Class getAnnotationType(); + @Override + public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { + if (importingClassMetadata.hasAnnotation(getAnnotationTypeName())) { + Map annotationAttributes = + importingClassMetadata.getAnnotationAttributes(getAnnotationTypeName()); - /* (non-Javadoc) */ - protected String getBeanName() { - return String.format("%1$s.%2$s", getClass().getName(), getAnnotationTypeSimpleName()); - } + Properties customGemFireProperties = toGemFireProperties(annotationAttributes); - /* (non-Javadoc) */ - protected BeanDefinitionHolder newBeanDefinitionHolder(BeanDefinitionBuilder builder) { - return new BeanDefinitionHolder(builder.getBeanDefinition(), getBeanName()); + if (hasProperties(customGemFireProperties)) { + try { + cacheConfiguration().add(customGemFireProperties); + } + catch (Exception ignore) { + registerGemFirePropertiesBeanPostProcessor(registry, customGemFireProperties); + } + } + } } /* (non-Javadoc) */ protected abstract Properties toGemFireProperties(Map annotationAttributes); + /* (non-Javadoc) */ + protected boolean hasProperties(Properties properties) { + return !CollectionUtils.isEmpty(properties); + } + /* (non-Javadoc) */ protected void registerGemFirePropertiesBeanPostProcessor(BeanDefinitionRegistry registry, - Properties customizedGemFireProperties) { + Properties customGemFireProperties) { BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition( GemFirePropertiesBeanPostProcessor.class); - builder.addConstructorArgValue(customizedGemFireProperties); + builder.addConstructorArgValue(customGemFireProperties); BeanDefinitionReaderUtils.registerBeanDefinition(newBeanDefinitionHolder(builder), registry); } + /* (non-Javadoc) */ + protected BeanDefinitionHolder newBeanDefinitionHolder(BeanDefinitionBuilder builder) { + return new BeanDefinitionHolder(builder.getBeanDefinition(), generateBeanName()); + } + + /* (non-Javadoc) */ + protected String generateBeanName() { + return String.format("%1$s.%2$s", getClass().getName(), getAnnotationTypeSimpleName()); + } + + /* (non-Javadoc) */ + protected String resolveHost(String hostname) { + return resolveHost(hostname, DEFAULT_HOST); + } + + /* (non-Javadoc) */ + protected String resolveHost(String hostname, String defaultHostname) { + return (StringUtils.hasText(hostname) ? hostname : defaultHostname); + } + + /* (non-Javadoc) */ + protected Integer resolvePort(Integer port, Integer defaultPort) { + return (port != null ? port : defaultPort); + } + /** * Spring {@link BeanPostProcessor} used to post process before initialization in GemFire System properties * Spring bean defined in the application context. @@ -125,7 +143,7 @@ public abstract class EmbeddedServiceConfigurationSupport implements ImportBeanD */ protected static class GemFirePropertiesBeanPostProcessor implements BeanPostProcessor { - static final String GEMFIRE_PROPERTIES_BEAN_NAME = "gemfireProperties"; + protected static final String GEMFIRE_PROPERTIES_BEAN_NAME = "gemfireProperties"; private final Properties gemfireProperties; diff --git a/src/main/java/org/springframework/data/gemfire/util/ArrayUtils.java b/src/main/java/org/springframework/data/gemfire/util/ArrayUtils.java index 7ddc2e4d..93ac489a 100644 --- a/src/main/java/org/springframework/data/gemfire/util/ArrayUtils.java +++ b/src/main/java/org/springframework/data/gemfire/util/ArrayUtils.java @@ -1,11 +1,11 @@ /* * Copyright 2002-2013 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. @@ -117,5 +117,4 @@ public abstract class ArrayUtils { return newArray; } - } diff --git a/src/main/java/org/springframework/data/gemfire/util/CacheUtils.java b/src/main/java/org/springframework/data/gemfire/util/CacheUtils.java index 195e95d0..17c681ab 100644 --- a/src/main/java/org/springframework/data/gemfire/util/CacheUtils.java +++ b/src/main/java/org/springframework/data/gemfire/util/CacheUtils.java @@ -125,5 +125,4 @@ public abstract class CacheUtils extends DistributedSystemUtils { return null; } } - } diff --git a/src/main/java/org/springframework/data/gemfire/util/CollectionUtils.java b/src/main/java/org/springframework/data/gemfire/util/CollectionUtils.java index f3f90c37..c5ee55ef 100644 --- a/src/main/java/org/springframework/data/gemfire/util/CollectionUtils.java +++ b/src/main/java/org/springframework/data/gemfire/util/CollectionUtils.java @@ -77,7 +77,7 @@ public abstract class CollectionUtils extends org.springframework.util.Collectio * @return the given Collection if not null, otherwise return an empty Collection (List). * @see java.util.Collections#emptyList() */ - public static Collection nullSafeCollection(final Collection collection) { + public static Collection nullSafeCollection(Collection collection) { return (collection != null ? collection : Collections.emptyList()); } @@ -100,15 +100,14 @@ public abstract class CollectionUtils extends org.springframework.util.Collectio } @Override public T next() { - throw new NoSuchElementException("no elements in this Iterator"); + throw new NoSuchElementException("No more elements"); } @Override public void remove() { - throw new UnsupportedOperationException("operation not supported"); + throw new UnsupportedOperationException("Operation not supported"); } }; } }); } - } diff --git a/src/main/java/org/springframework/data/gemfire/util/DistributedSystemUtils.java b/src/main/java/org/springframework/data/gemfire/util/DistributedSystemUtils.java index c0982ca8..fe607ed2 100644 --- a/src/main/java/org/springframework/data/gemfire/util/DistributedSystemUtils.java +++ b/src/main/java/org/springframework/data/gemfire/util/DistributedSystemUtils.java @@ -18,9 +18,6 @@ package org.springframework.data.gemfire.util; import java.util.Properties; -import org.springframework.util.Assert; -import org.springframework.util.StringUtils; - import com.gemstone.gemfire.cache.GemFireCache; import com.gemstone.gemfire.cache.server.CacheServer; import com.gemstone.gemfire.distributed.DistributedSystem; @@ -30,6 +27,9 @@ import com.gemstone.gemfire.distributed.internal.InternalDistributedSystem; import com.gemstone.gemfire.distributed.internal.InternalLocator; import com.gemstone.gemfire.internal.DistributionLocator; +import org.springframework.util.Assert; +import org.springframework.util.StringUtils; + /** * DistributedSystemUtils is an abstract utility class for working with the GemFire DistributedSystem. * diff --git a/src/main/java/org/springframework/data/gemfire/util/PropertiesBuilder.java b/src/main/java/org/springframework/data/gemfire/util/PropertiesBuilder.java new file mode 100644 index 00000000..db97c884 --- /dev/null +++ b/src/main/java/org/springframework/data/gemfire/util/PropertiesBuilder.java @@ -0,0 +1,119 @@ +/* + * Copyright 2012 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.util; + +import java.io.IOException; +import java.io.InputStream; +import java.io.Reader; +import java.util.Properties; + +import org.springframework.util.Assert; +import org.springframework.util.StringUtils; + +/** + * The PropertiesBuilder class is a Builder for {@link java.util.Properties}. + * + * @author John Blum + * @see java.util.Properties + * @since 1.0.0 + */ +@SuppressWarnings("unused") +public class PropertiesBuilder { + + private final Properties properties; + + public PropertiesBuilder() { + this.properties = new Properties(); + } + + public PropertiesBuilder(Properties defaults) { + this.properties = new Properties(defaults); + } + + public PropertiesBuilder(PropertiesBuilder builder) { + this(builder != null ? builder.build() : null); + } + + public PropertiesBuilder add(Properties properties) { + if (!CollectionUtils.isEmpty(properties)) { + this.properties.putAll(properties); + } + + return this; + } + + public PropertiesBuilder add(PropertiesBuilder builder) { + if (builder != null) { + add(builder.build()); + } + + return this; + } + + public PropertiesBuilder from(InputStream in) { + try { + this.properties.load(in); + return this; + } + catch (IOException e) { + throw new IllegalArgumentException("Failed to read properties from InputStream", e); + } + } + + public PropertiesBuilder from(Reader reader) { + try { + this.properties.load(reader); + return this; + } + catch (IOException e) { + throw new IllegalArgumentException("Failed to read properties from Reader", e); + } + } + + public PropertiesBuilder fromXml(InputStream xml) { + try { + this.properties.loadFromXML(xml); + return this; + } + catch (IOException e) { + throw new IllegalArgumentException("Failed to read properties from XML InputStream", e); + } + } + + public PropertiesBuilder setProperty(String name, Object value) { + if (value != null) { + setProperty(name, value.toString()); + } + + return this; + } + + public PropertiesBuilder setProperty(String name, String value) { + Assert.hasText(name, String.format("Name [%s] must not be null or empty", name)); + + if (StringUtils.hasText(value)) { + this.properties.setProperty(name, value); + } + + return this; + } + + public Properties build() { + return this.properties; + } +} diff --git a/src/test/java/org/springframework/data/gemfire/util/CollectionUtilsTest.java b/src/test/java/org/springframework/data/gemfire/util/CollectionUtilsTest.java index 28f07e51..b3fa8a2a 100644 --- a/src/test/java/org/springframework/data/gemfire/util/CollectionUtilsTest.java +++ b/src/test/java/org/springframework/data/gemfire/util/CollectionUtilsTest.java @@ -148,18 +148,17 @@ public class CollectionUtilsTest { iterator.next(); } catch (NoSuchElementException ignore) { - assertThat(ignore.getMessage(), is(equalTo("no elements in this Iterator"))); + assertThat(ignore.getMessage(), is(equalTo("No more elements"))); assertThat(ignore.getCause(), is(nullValue())); try { iterator.remove(); } catch (UnsupportedOperationException expected) { - assertThat(expected.getMessage(), is(equalTo("operation not supported"))); + assertThat(expected.getMessage(), is(equalTo("Operation not supported"))); assertThat(expected.getCause(), is(nullValue())); throw expected; } } } - }