diff --git a/src/main/java/org/springframework/data/gemfire/config/annotation/EnableGemFireProperties.java b/src/main/java/org/springframework/data/gemfire/config/annotation/EnableGemFireProperties.java
index 2abefeae..bc562ae3 100644
--- a/src/main/java/org/springframework/data/gemfire/config/annotation/EnableGemFireProperties.java
+++ b/src/main/java/org/springframework/data/gemfire/config/annotation/EnableGemFireProperties.java
@@ -115,14 +115,14 @@ public @interface EnableGemFireProperties {
*
* Defaults to unset.
*/
- String bindAddress() default "";
+ String bindAddress() default GemFirePropertiesConfiguration.DEFAULT_BIND_ADDRESS;
/**
* Declarative initialization file for the member’s cache.
*
* Defaults to unset.
*/
- String cacheXmlFile() default "";
+ String cacheXmlFile() default GemFirePropertiesConfiguration.DEFAULT_CACHE_XML_FILE;
/**
* This property specifies the directory in which the cluster configuration related disk-store and artifacts
@@ -131,7 +131,8 @@ public @interface EnableGemFireProperties {
*
* Defaults to unset.
*/
- String clusterConfigurationDirectory() default "";
+ String clusterConfigurationDirectory()
+ default GemFirePropertiesConfiguration.DEFAULT_CLUSTER_CONFIGURATION_DIRECTORY;
/**
* Used only by clients in a client/server installation. This is a client-side property
@@ -204,7 +205,8 @@ public @interface EnableGemFireProperties {
*
* Defaults to {@literal false}.
*/
- boolean enableNetworkPartitionDetection() default GemFirePropertiesConfiguration.DEFAULT_ENABLE_NETWORK_PARTITION_DETECTION;
+ boolean enableNetworkPartitionDetection()
+ default GemFirePropertiesConfiguration.DEFAULT_ENABLE_NETWORK_PARTITION_DETECTION;
/**
* Whether partitioned regions will put redundant copies of the same data in different members
@@ -232,7 +234,8 @@ public @interface EnableGemFireProperties {
*
* Defaults to {@literal false}.
*/
- boolean loadClusterConfigurationFromDirectory() default GemFirePropertiesConfiguration.DEFAULT_LOAD_CLUSTER_CONFIGURATION_FROM_DIRECTORY;
+ boolean loadClusterConfigurationFromDirectory()
+ default GemFirePropertiesConfiguration.DEFAULT_LOAD_CLUSTER_CONFIGURATION_FROM_DIRECTORY;
/**
* The number of seconds that a member should wait for a Locator to start if a Locator is not available
@@ -302,6 +305,14 @@ public @interface EnableGemFireProperties {
*/
String membershipPortRange() default GemFirePropertiesConfiguration.DEFAULT_MEMBERSHIP_PORT_RANGE;
+ /**
+ * Configures the {@link String name} of this member in the Apache Geode/Pivotal GemFire distributed system
+ * whether the member is a client in the client/server topology or a peer in the cluster.
+ *
+ * Defaults to unset.
+ */
+ String name() default GemFirePropertiesConfiguration.DEFAULT_NAME;
+
/**
* Defines this member’s redundancy zone. Used to separate member’s into different groups for satisfying
* Partitioned Region redundancy. If this property is set, GemFire will not put redundant copies of data
@@ -311,7 +322,7 @@ public @interface EnableGemFireProperties {
*
* @see Configure High Availability for a Partitioned Region
*/
- String redundancyZone() default "";
+ String redundancyZone() default GemFirePropertiesConfiguration.DEFAULT_REDUNDANCY_ZONE;
/**
* Used to configure the Locators that a cluster will use in order to connect to a remote site in a multi-site
@@ -338,7 +349,7 @@ public @interface EnableGemFireProperties {
*
* Defaults to unset.
*/
- String remoteLocators() default "";
+ String remoteLocators() default GemFirePropertiesConfiguration.DEFAULT_REMOTE_LOCATORS;
/**
* When this property is set to {@literal true}, the primary server drops unresponsive clients
@@ -350,6 +361,17 @@ public @interface EnableGemFireProperties {
*/
boolean removeUnresponsiveClient() default GemFirePropertiesConfiguration.DEFAULT_REMOVE_UNRESPONSIVE_CLIENT;
+ /**
+ * A semicolon-separated list of items that become full class names of objects that the system will serialize
+ * when the property {@link #validateSerializableObjects()} is set to {@literal true}.
+ *
+ * The list is expanded using the patterns specified in the createFilter method at
+ * Class ObjectInputFilter.Config.
+ *
+ * Defaults to unset.
+ */
+ String serializableObjectFilter() default GemFirePropertiesConfiguration.DEFAULT_SERIALIZABLE_OBJECT_FILTER;
+
/**
* Receive buffer sizes in bytes of the TCP/IP connections used for data transmission. To minimize the buffer size
* allocation needed for distributing large, serializable messages, the messages are sent in chunks. This setting
@@ -433,6 +455,19 @@ public @interface EnableGemFireProperties {
*
* Defaults to unset.
*/
- String userCommandPackages() default "";
+ String userCommandPackages() default GemFirePropertiesConfiguration.DEFAULT_USER_COMMAND_PACKAGES;
+
+ /**
+ * A boolean that defaults to {@literal false}. When {@literal true}, instances of classes that are not internal
+ * to Apache Geode/Pivotal GemFire and whose class name is not allowed by the list defined in
+ * the {@link #serializableObjectFilter()} property will not be permitted to be deserialized.
+ *
+ * An {@literal IncompatibleClassException} is thrown for objects not listed. JDK 8 build 121 or a later build
+ * must be installed to use this property. Servers and clients that do not meet this requirement
+ * will throw an exception upon startup.
+ *
+ * Defaults to {@literal false}.
+ */
+ boolean validateSerializableObjects() default GemFirePropertiesConfiguration.DEFAULT_VALIDATE_SERIALIZABLE_OBJECTS;
}
diff --git a/src/main/java/org/springframework/data/gemfire/config/annotation/GemFirePropertiesConfiguration.java b/src/main/java/org/springframework/data/gemfire/config/annotation/GemFirePropertiesConfiguration.java
index eaf234f6..c18e03db 100644
--- a/src/main/java/org/springframework/data/gemfire/config/annotation/GemFirePropertiesConfiguration.java
+++ b/src/main/java/org/springframework/data/gemfire/config/annotation/GemFirePropertiesConfiguration.java
@@ -17,6 +17,7 @@
package org.springframework.data.gemfire.config.annotation;
+import java.lang.annotation.Annotation;
import java.util.Map;
import java.util.Properties;
@@ -44,6 +45,7 @@ public class GemFirePropertiesConfiguration extends EmbeddedServiceConfiguration
public static final boolean DEFAULT_LOAD_CLUSTER_CONFIGURATION_FROM_DIRECTORY = false;
public static final boolean DEFAULT_LOCK_MEMORY = false;
public static final boolean DEFAULT_REMOVE_UNRESPONSIVE_CLIENT = false;
+ public static final boolean DEFAULT_VALIDATE_SERIALIZABLE_OBJECTS = false;
public static final int DEFAULT_ACK_SEVERE_ALERT_THRESHOLD = 0;
public static final int DEFAULT_ACK_WAIT_THRESHOLD = 15;
@@ -63,15 +65,26 @@ public class GemFirePropertiesConfiguration extends EmbeddedServiceConfiguration
public static final long DEFAULT_MEMBER_TIMEOUT = 5000L;
public static final long DEFAULT_SOCKET_LEASE_TIME = 60000L;
+ public static final String DEFAULT_BIND_ADDRESS = "";
+ public static final String DEFAULT_CACHE_XML_FILE = "";
+ public static final String DEFAULT_CLUSTER_CONFIGURATION_DIRECTORY = "";
public static final String DEFAULT_CONFLATE_EVENTS = "server";
public static final String DEFAULT_DEPLOY_WORKING_DIRECTORY = ".";
public static final String DEFAULT_MEMBERSHIP_PORT_RANGE = "1024-65535";
+ public static final String DEFAULT_NAME = "";
+ public static final String DEFAULT_REDUNDANCY_ZONE = "";
+ public static final String DEFAULT_REMOTE_LOCATORS = "";
+ public static final String DEFAULT_SERIALIZABLE_OBJECT_FILTER = "";
+ public static final String DEFAULT_USER_COMMAND_PACKAGES = "";
+
+ @SuppressWarnings("unused")
+ public static final String[] DEFAULT_GROUPS = {};
/**
* {@inheritDoc}
*/
@Override
- protected Class getAnnotationType() {
+ protected Class extends Annotation> getAnnotationType() {
return EnableGemFireProperties.class;
}
@@ -80,6 +93,7 @@ public class GemFirePropertiesConfiguration extends EmbeddedServiceConfiguration
*/
@Override
protected Properties toGemFireProperties(Map annotationAttributes) {
+
PropertiesBuilder gemfireProperties = new PropertiesBuilder();
gemfireProperties.setPropertyIfNotDefault("ack-severe-alert-threshold",
@@ -149,6 +163,8 @@ public class GemFirePropertiesConfiguration extends EmbeddedServiceConfiguration
gemfireProperties.setPropertyIfNotDefault("membership-port-range",
annotationAttributes.get("membershipPortRange"), DEFAULT_MEMBERSHIP_PORT_RANGE);
+ gemfireProperties.setProperty("name", annotationAttributes.get("name"));
+
gemfireProperties.setProperty("redundancy-zone", annotationAttributes.get("redundancyZone"));
gemfireProperties.setProperty("remote-locators", annotationAttributes.get("remoteLocators"));
@@ -156,13 +172,17 @@ public class GemFirePropertiesConfiguration extends EmbeddedServiceConfiguration
gemfireProperties.setPropertyIfNotDefault("remove-unresponsive-client",
annotationAttributes.get("removeUnresponsiveClient"), DEFAULT_REMOVE_UNRESPONSIVE_CLIENT);
+ gemfireProperties.setProperty("serializable-object-filter",
+ annotationAttributes.get("serializableObjectFilter"));
+
gemfireProperties.setPropertyIfNotDefault("socket-buffer-size",
annotationAttributes.get("socketBufferSize"), DEFAULT_SOCKET_BUFFER_SIZE);
gemfireProperties.setPropertyIfNotDefault("socket-lease-time",
annotationAttributes.get("socketLeaseTime"), DEFAULT_SOCKET_LEASE_TIME);
- gemfireProperties.setPropertyIfNotDefault("tcp-port", annotationAttributes.get("tcpPort"), DEFAULT_TCP_PORT);
+ gemfireProperties.setPropertyIfNotDefault("tcp-port",
+ annotationAttributes.get("tcpPort"), DEFAULT_TCP_PORT);
gemfireProperties.setPropertyIfNotDefault("tombstone-gc-threshold",
annotationAttributes.get("tombstoneGcThreshold"), DEFAULT_TOMBSTONE_THRESHOLD);
@@ -178,6 +198,9 @@ public class GemFirePropertiesConfiguration extends EmbeddedServiceConfiguration
gemfireProperties.setProperty("user-command-packages", annotationAttributes.get("userCommandPackages"));
+ gemfireProperties.setPropertyIfNotDefault("validate-serializable-objects",
+ annotationAttributes.get("validateSerializableObjects"), DEFAULT_VALIDATE_SERIALIZABLE_OBJECTS);
+
return gemfireProperties.build();
}
}
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 6e5120a9..1593eb59 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
@@ -97,13 +97,11 @@ public abstract class EmbeddedServiceConfigurationSupport extends AbstractAnnota
}
}
- /* (non-Javadoc) */
@SuppressWarnings("unused")
protected void registerBeanDefinitions(AnnotationMetadata importingClassMetaData,
Map annotationAttributes, BeanDefinitionRegistry registry) {
}
- /* (non-Javadoc) */
protected void setGemFireProperties(AnnotationMetadata importingClassMetadata,
Map annotationAttributes, BeanDefinitionRegistry registry) {
@@ -119,20 +117,16 @@ public abstract class EmbeddedServiceConfigurationSupport extends AbstractAnnota
}
}
- /* (non-Javadoc) */
protected abstract Properties toGemFireProperties(Map annotationAttributes);
- /* (non-Javadoc) */
protected boolean isAnnotationPresent(AnnotationMetadata importingClassMetadata) {
return importingClassMetadata.hasAnnotation(getAnnotationTypeName());
}
- /* (non-Javadoc) */
protected boolean hasProperties(Properties properties) {
return !CollectionUtils.isEmpty(properties);
}
- /* (non-Javadoc) */
protected void registerGemFirePropertiesBeanPostProcessor(BeanDefinitionRegistry registry,
Properties customGemFireProperties) {
@@ -144,22 +138,18 @@ public abstract class EmbeddedServiceConfigurationSupport extends AbstractAnnota
BeanDefinitionReaderUtils.registerBeanDefinition(newBeanDefinitionHolder(builder), registry);
}
- /* (non-Javadoc) */
protected BeanDefinitionHolder newBeanDefinitionHolder(BeanDefinitionBuilder builder) {
return new BeanDefinitionHolder(builder.getBeanDefinition(), generateBeanName());
}
- /* (non-Javadoc) */
protected String generateBeanName() {
return generateBeanName(getAnnotationType());
}
- /* (non-Javadoc) */
protected String generateBeanName(Class> typeQualifier) {
return generateBeanName(typeQualifier.getSimpleName());
}
- /* (non-Javadoc) */
protected String generateBeanName(String nameQualifier) {
return String.format("%1$s.%2$s", getClass().getName(), nameQualifier);
}
@@ -199,22 +189,18 @@ public abstract class EmbeddedServiceConfigurationSupport extends AbstractAnnota
}
}
- /* (non-Javadoc) */
protected String resolveHost(String hostname) {
return resolveHost(hostname, DEFAULT_HOST);
}
- /* (non-Javadoc) */
protected String resolveHost(String hostname, String defaultHostname) {
return Optional.ofNullable(hostname).filter(StringUtils::hasText).orElse(defaultHostname);
}
- /* (non-Javadoc) */
protected Integer resolvePort(Integer port) {
return resolvePort(port, DEFAULT_PORT);
}
- /* (non-Javadoc) */
protected Integer resolvePort(Integer port, Integer defaultPort) {
return Optional.ofNullable(port).orElse(defaultPort);
}
@@ -240,7 +226,9 @@ public abstract class EmbeddedServiceConfigurationSupport extends AbstractAnnota
* @see java.util.Properties
*/
protected GemFirePropertiesBeanPostProcessor(Properties gemfireProperties) {
+
Assert.notEmpty(gemfireProperties, "GemFire Properties are required");
+
this.gemfireProperties = gemfireProperties;
}
@@ -251,7 +239,9 @@ public abstract class EmbeddedServiceConfigurationSupport extends AbstractAnnota
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof Properties && GEMFIRE_PROPERTIES_BEAN_NAME.equals(beanName)) {
+
Properties gemfirePropertiesBean = (Properties) bean;
+
gemfirePropertiesBean.putAll(gemfireProperties);
}
diff --git a/src/test/java/org/springframework/data/gemfire/config/annotation/EnableGemFirePropertiesIntegrationTests.java b/src/test/java/org/springframework/data/gemfire/config/annotation/EnableGemFirePropertiesIntegrationTests.java
index 6bf619fa..9fe69e95 100644
--- a/src/test/java/org/springframework/data/gemfire/config/annotation/EnableGemFirePropertiesIntegrationTests.java
+++ b/src/test/java/org/springframework/data/gemfire/config/annotation/EnableGemFirePropertiesIntegrationTests.java
@@ -57,14 +57,21 @@ public class EnableGemFirePropertiesIntegrationTests {
Optional.ofNullable(this.applicationContext).ifPresent(ConfigurableApplicationContext::close);
}
+ private ConfigurableApplicationContext newApplicationContext(Class>... annotatedClasses) {
+ return newApplicationContext(null, annotatedClasses);
+ }
+
private ConfigurableApplicationContext newApplicationContext(PropertySource> testPropertySource,
Class>... annotatedClasses) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
- MutablePropertySources propertySources = applicationContext.getEnvironment().getPropertySources();
+ Optional.ofNullable(testPropertySource).ifPresent(it -> {
- propertySources.addFirst(testPropertySource);
+ MutablePropertySources propertySources = applicationContext.getEnvironment().getPropertySources();
+
+ propertySources.addFirst(testPropertySource);
+ });
applicationContext.registerShutdownHook();
applicationContext.register(annotatedClasses);
@@ -259,6 +266,36 @@ public class EnableGemFirePropertiesIntegrationTests {
assertThat(gemfireProperties.getProperty("memcached-protocol")).isEqualTo("BINARY");
}
+ @Test
+ public void nameAndGroupGemFirePropertiesAnnotationConfiguration() {
+
+ this.applicationContext = newApplicationContext(TestNameAndGroupGemFirePropertiesAnnotationConfiguration.class);
+
+ assertThat(this.applicationContext).isNotNull();
+ assertThat(this.applicationContext.containsBean("gemfireCache")).isTrue();
+ assertThat(this.applicationContext.containsBean("gemfireProperties")).isTrue();
+
+ Properties gemfireProperties = this.applicationContext.getBean("gemfireProperties", Properties.class);
+
+
+ // TODO: uncomment when Spring Test for Apache Geode/Pivotal GemFire project replaces
+ // the test infrastructure classes in SDG.
+ /*
+ GemFireCache gemfireCache = this.applicationContext.getBean("gemfireCache", GemFireCache.class);
+
+ assertThat(gemfireCache).isNotNull();
+ assertThat(gemfireCache.getDistributedSystem()).isNotNull();
+
+ Properties gemfireProperties = gemfireCache.getDistributedSystem().getProperties();
+ */
+
+ assertThat(gemfireProperties).isNotNull();
+ assertThat(gemfireProperties.containsKey("name")).isTrue();
+ assertThat(gemfireProperties.getProperty("name")).isEqualTo("TestName");
+ assertThat(gemfireProperties.containsKey("groups")).isTrue();
+ assertThat(gemfireProperties.getProperty("groups")).isEqualTo("TestGroupOne,TestGroupTwo");
+ }
+
@Test
public void offHeapGemFirePropertiesConfiguration() {
@@ -422,64 +459,60 @@ public class EnableGemFirePropertiesIntegrationTests {
@PeerCacheApplication
@EnableAuth
@EnableGemFireProperties
- static class TestAuthGemFirePropertiesConfiguration {
- }
+ static class TestAuthGemFirePropertiesConfiguration { }
@EnableGemFireMockObjects
@PeerCacheApplication
@EnableGemFireProperties
@EnableHttpService
- static class TestHttpGemFirePropertiesConfiguration {
- }
+ static class TestHttpGemFirePropertiesConfiguration { }
@EnableGemFireMockObjects
@PeerCacheApplication
@EnableGemFireProperties
@EnableLocator
- static class TestLocatorGemFirePropertiesConfiguration {
- }
+ static class TestLocatorGemFirePropertiesConfiguration { }
@EnableGemFireMockObjects
@PeerCacheApplication
@EnableGemFireProperties
@EnableLogging
- static class TestLoggingGemFirePropertiesConfiguration {
- }
+ static class TestLoggingGemFirePropertiesConfiguration { }
@EnableGemFireMockObjects
@PeerCacheApplication
@EnableGemFireProperties
@EnableManager
- static class TestManagerGemFirePropertiesConfiguration {
- }
+ static class TestManagerGemFirePropertiesConfiguration { }
@EnableGemFireMockObjects
@PeerCacheApplication
@EnableGemFireProperties
@EnableMemcachedServer
- static class TestMemcachedServerGemFirePropertiesConfiguration {
- }
+ static class TestMemcachedServerGemFirePropertiesConfiguration { }
+
+ @EnableGemFireMockObjects
+ @PeerCacheApplication
+ @EnableGemFireProperties(name = "TestName", groups = { "TestGroupOne", "TestGroupTwo" })
+ static class TestNameAndGroupGemFirePropertiesAnnotationConfiguration { }
@EnableGemFireMockObjects
@PeerCacheApplication
@EnableGemFireProperties
@EnableOffHeap(memorySize = "64g")
- static class TestOffHeapGemFirePropertiesConfiguration {
- }
+ static class TestOffHeapGemFirePropertiesConfiguration { }
@EnableGemFireMockObjects
@PeerCacheApplication
@EnableGemFireProperties
@EnableRedisServer
- static class TestRedisServerGemFirePropertiesConfiguration {
- }
+ static class TestRedisServerGemFirePropertiesConfiguration { }
@EnableGemFireMockObjects
@PeerCacheApplication
@EnableGemFireProperties
@EnableSecurity
- static class TestSecurityGemFirePropertiesConfiguration {
- }
+ static class TestSecurityGemFirePropertiesConfiguration { }
@EnableGemFireMockObjects
@PeerCacheApplication
@@ -491,13 +524,12 @@ public class EnableGemFirePropertiesIntegrationTests {
@EnableSsl.ComponentAlias(component = EnableSsl.Component.GATEWAY, alias = "WanCert"),
@EnableSsl.ComponentAlias(component = EnableSsl.Component.WEB, alias = "HttpCert")
}, defaultCertificateAlias = "MockCert", protocols = "HTTP")
- static class TestSslGemFirePropertiesConfiguration {
- }
+ static class TestSslGemFirePropertiesConfiguration { }
@EnableGemFireMockObjects
@PeerCacheApplication
@EnableGemFireProperties
@EnableStatistics
- static class TestStatisticsGemFirePropertiesConfiguration {
- }
+ static class TestStatisticsGemFirePropertiesConfiguration { }
+
}