SGF-512 - Configure GemFire System Properties with annotations.
This commit is contained in:
@@ -28,11 +28,13 @@ import org.springframework.context.annotation.Import;
|
||||
|
||||
/**
|
||||
* The EnableManager 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.
|
||||
* annotated class to configure, embed and start a GemFire/Geode Manager service in the GemFire/Geode Server.
|
||||
*
|
||||
* Automatically sets {@literal jmx-manager} to {@literal true}.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.springframework.context.annotation.Import
|
||||
* @see ManagerConfiguration
|
||||
* @see org.springframework.data.gemfire.config.annotation.ManagerConfiguration
|
||||
* @since 1.9.0
|
||||
*/
|
||||
@Target(ElementType.TYPE)
|
||||
@@ -43,15 +45,6 @@ import org.springframework.context.annotation.Import;
|
||||
@SuppressWarnings("unused")
|
||||
public @interface EnableManager {
|
||||
|
||||
/**
|
||||
* 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 {@literal true}.
|
||||
*/
|
||||
boolean jmxManager() default true;
|
||||
|
||||
/**
|
||||
* By default, the JMX Manager will allow full access to all mbeans by any client. If this property is set to
|
||||
* the name of a file then it can restrict clients to only being able to read MBeans; they will not be able
|
||||
@@ -59,17 +52,19 @@ public @interface EnableManager {
|
||||
* in the password file. For more information about the format of this file see Oracle's documentation
|
||||
* of the {@code com.sun.management.jmxremote.access.file} System property. Ignored if {@literal jmx-manager}
|
||||
* is false or if {@literal jmx-manager-port} is zero.
|
||||
*
|
||||
* Defaults to unset.
|
||||
*/
|
||||
String jmxManagerAccessFile() default "";
|
||||
String accessFile() default "";
|
||||
|
||||
/**
|
||||
* 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 {@literal false} or {@literal jmx-manager-port} is zero.
|
||||
*
|
||||
* Defaults to {@literal localhost}.
|
||||
* Defaults to unset.
|
||||
*/
|
||||
String jmxManagerBindAddress() default "";
|
||||
String bindAddress() default "";
|
||||
|
||||
/**
|
||||
* Lets you control what hostname will be given to clients that ask the Locator for the location of a JMX Manager.
|
||||
@@ -77,9 +72,9 @@ public @interface EnableManager {
|
||||
* this property allows you to configure a different hostname that will be given to clients. Ignored if
|
||||
* {@literal jmx-manager} is {@literal false} or {@literal jmx-manager-port} is zero.
|
||||
*
|
||||
* Defaults to {@literal localhost}.
|
||||
* Defaults to unset.
|
||||
*/
|
||||
String jmxManagerHostnameForClients() default "";
|
||||
String hostnameForClients() default "";
|
||||
|
||||
/**
|
||||
* By default, the JMX Manager will allow clients without credentials to connect. If this property is set to
|
||||
@@ -87,8 +82,10 @@ public @interface EnableManager {
|
||||
* 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 {@literal false} or {@literal jmx-manager-port} is zero.
|
||||
*
|
||||
* Defaults to unset.
|
||||
*/
|
||||
String jmxManagerPasswordFile() default "";
|
||||
String passwordFile() default "";
|
||||
|
||||
/**
|
||||
* The port this JMX Manager will listen to for client connections. If this property is set to zero then GemFire
|
||||
@@ -97,61 +94,25 @@ public @interface EnableManager {
|
||||
*
|
||||
* Defaults to {@literal 1099}.
|
||||
*/
|
||||
int jmxManagerPort() default ManagerConfiguration.DEFAULT_JMX_MANAGER_PORT;
|
||||
int port() default ManagerConfiguration.DEFAULT_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.
|
||||
* If {@literal 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 {@literal true}. Ignored if {@literal jmx-manager} is {@literal false}.
|
||||
*
|
||||
* Defaults to {@literal false}.
|
||||
*/
|
||||
boolean jmxManagerSslEnabled() default false;
|
||||
|
||||
/**
|
||||
* A space-separated list of the valid SSL ciphers for JMX Manager connections. A setting of 'any' uses any ciphers
|
||||
* that are enabled by default in the configured JSSE provider. If this property is not set, then GemFire uses
|
||||
* the value of {@literal cluster-ssl-ciphers} to determine which SSL ciphers are used for JMX connections.
|
||||
*
|
||||
* Defaults to {@literal any}.
|
||||
*/
|
||||
String jmxManagerSslCiphers() default "any";
|
||||
|
||||
/**
|
||||
* A space-separated list of the valid SSL protocols for JMX Manager connections. A setting of 'any' uses any
|
||||
* protocol that is enabled by default in the configured JSSE provider. If this property is not set, then GemFire
|
||||
* uses the value of {@literal cluster-ssl-protocols} to determine which SSL protocols are used for JMX connections.
|
||||
*
|
||||
* Defaults to {@literal any}.
|
||||
*/
|
||||
String jmxManagerSslProtocols() default "any";
|
||||
|
||||
/**
|
||||
* Boolean indicating whether to require authentication for JMX Manager connections. If this property is not set,
|
||||
* then GemFire uses the value of {@literal cluster-ssl-require-authentication} to determine whether JMX connections
|
||||
* require authentication.
|
||||
*
|
||||
* 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 {@literal true}. Ignored if
|
||||
* {@literal jmx-manager} is {@literal false}.
|
||||
*
|
||||
* Defaults to {@literal false}.
|
||||
*/
|
||||
boolean jmxManagerStart() default false;
|
||||
boolean start() default false;
|
||||
|
||||
/**
|
||||
* The rate, in milliseconds, at which this member will push updates to any JMX Managers. Currently this value
|
||||
* 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 {@literal 2000}.
|
||||
* Defaults to {@literal 2000} milliseconds.
|
||||
*/
|
||||
int jmxManagerUpdateRate() default 2000;
|
||||
int updateRate() default 2000;
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,178 @@
|
||||
/*
|
||||
* 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.config.annotation;
|
||||
|
||||
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 GemFirePropertiesConfiguration class is a Spring {@link org.springframework.context.annotation.ImportBeanDefinitionRegistrar}
|
||||
* capable of configuring additional GemFire Properties on the (Spring Boot) application class at runtime
|
||||
* during startup.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.springframework.data.gemfire.config.annotation.WithGemFireProperties
|
||||
* @see org.springframework.data.gemfire.config.annotation.support.EmbeddedServiceConfigurationSupport
|
||||
* @since 1.9.0
|
||||
*/
|
||||
public class GemFirePropertiesConfiguration extends EmbeddedServiceConfigurationSupport {
|
||||
|
||||
public static final boolean DEFAULT_CONSERVE_SOCKETS = true;
|
||||
public static final boolean DEFAULT_DELTA_PROPAGATION = true;
|
||||
public static final boolean DEFAULT_DISABLE_TCP = false;
|
||||
public static final boolean DEFAULT_ENABLE_NETWORK_PARTITION_DETECTION = false;
|
||||
public static final boolean DEFAULT_ENFORCE_UNIQUE_HOST = false;
|
||||
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 int DEFAULT_ACK_SEVERE_ALERT_THRESHOLD = 0;
|
||||
public static final int DEFAULT_ACK_WAIT_THRESHOLD = 15;
|
||||
public static final int DEFAULT_ASYNC_MAX_QUEUE_SIZE = 8;
|
||||
public static final int DEFAULT_DISTRIBUTED_SYSTEM_ID = -1;
|
||||
public static final int DEFAULT_SOCKET_BUFFER_SIZE = 32768;
|
||||
public static final int DEFAULT_TCP_PORT = 0;
|
||||
public static final int DEFAULT_TOMBSTONE_THRESHOLD = 100000;
|
||||
public static final int DEFAULT_UDP_FRAGMENT_SIZE = 60000;
|
||||
public static final int DEFAULT_UDP_RECEIVE_BUFFER_SIZE = 1048576;
|
||||
public static final int DEFAULT_UDP_SEND_BUFFER_SIZE = 65535;
|
||||
|
||||
public static final long DEFAULT_ASYNC_DISTRIBUTION_TIMEOUT = 0L;
|
||||
public static final long DEFAULT_ASYNC_QUEUE_TIMEOUT = 60000L;
|
||||
public static final long DEFAULT_LOCATOR_WAIT_TIME = 0L;
|
||||
public static final long DEFAULT_MAX_WAIT_TIME_RECONNECT = 60000L;
|
||||
public static final long DEFAULT_MEMBER_TIMEOUT = 5000L;
|
||||
public static final long DEFAULT_SOCKET_LEASE_TIME = 60000L;
|
||||
|
||||
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";
|
||||
|
||||
/* (non-Javadoc) */
|
||||
@Override
|
||||
protected Class getAnnotationType() {
|
||||
return WithGemFireProperties.class;
|
||||
}
|
||||
|
||||
/* (non-Javadoc) */
|
||||
@Override
|
||||
protected Properties toGemFireProperties(Map<String, Object> annotationAttributes) {
|
||||
PropertiesBuilder gemfireProperties = new PropertiesBuilder();
|
||||
|
||||
gemfireProperties.setPropertyIfNotDefault("ack-severe-alert-threshold",
|
||||
annotationAttributes.get("ackSevereAlertThreshold"), DEFAULT_ACK_SEVERE_ALERT_THRESHOLD);
|
||||
|
||||
gemfireProperties.setPropertyIfNotDefault("ack-wait-threshold",
|
||||
annotationAttributes.get("ackWaitThreshold"), DEFAULT_ACK_WAIT_THRESHOLD);
|
||||
|
||||
gemfireProperties.setPropertyIfNotDefault("async-distribution-timeout",
|
||||
annotationAttributes.get("asyncDistributionTimeout"), DEFAULT_ASYNC_DISTRIBUTION_TIMEOUT);
|
||||
|
||||
gemfireProperties.setPropertyIfNotDefault("async-max-queue-size",
|
||||
annotationAttributes.get("asyncMaxQueueSize"), DEFAULT_ASYNC_MAX_QUEUE_SIZE);
|
||||
|
||||
gemfireProperties.setPropertyIfNotDefault("async-queue-timeout",
|
||||
annotationAttributes.get("asyncQueueTimeout"), DEFAULT_ASYNC_QUEUE_TIMEOUT);
|
||||
|
||||
gemfireProperties.setProperty("bind-address", annotationAttributes.get("bindAddress"));
|
||||
|
||||
gemfireProperties.setProperty("cache-xml-file", annotationAttributes.get("cacheXmlFile"));
|
||||
|
||||
gemfireProperties.setProperty("cluster-configuration-dir",
|
||||
annotationAttributes.get("clusterConfigurationDirectory"));
|
||||
|
||||
gemfireProperties.setPropertyIfNotDefault("conflate-events",
|
||||
annotationAttributes.get("conflateEvents"), DEFAULT_CONFLATE_EVENTS);
|
||||
|
||||
gemfireProperties.setPropertyIfNotDefault("conserve-sockets",
|
||||
annotationAttributes.get("conserveSockets"), DEFAULT_CONSERVE_SOCKETS);
|
||||
|
||||
gemfireProperties.setPropertyIfNotDefault("delta-propagation",
|
||||
annotationAttributes.get("deltaPropagation"), DEFAULT_DELTA_PROPAGATION);
|
||||
|
||||
gemfireProperties.setPropertyIfNotDefault("deploy-working-dir",
|
||||
annotationAttributes.get("deployWorkingDirectory"), DEFAULT_DEPLOY_WORKING_DIRECTORY);
|
||||
|
||||
gemfireProperties.setPropertyIfNotDefault("disable-tcp",
|
||||
annotationAttributes.get("disableTcp"), DEFAULT_DISABLE_TCP);
|
||||
|
||||
gemfireProperties.setPropertyIfNotDefault("distributed-system-id",
|
||||
annotationAttributes.get("distributedSystemId"), DEFAULT_DISTRIBUTED_SYSTEM_ID);
|
||||
|
||||
gemfireProperties.setPropertyIfNotDefault("enable-network-partition-detection",
|
||||
annotationAttributes.get("enableNetworkPartitionDetection"), DEFAULT_ENABLE_NETWORK_PARTITION_DETECTION);
|
||||
|
||||
gemfireProperties.setPropertyIfNotDefault("enforce-unique-host",
|
||||
annotationAttributes.get("enforceUniqueHost"), DEFAULT_ENFORCE_UNIQUE_HOST);
|
||||
|
||||
gemfireProperties.setProperty("groups", (String[]) annotationAttributes.get("groups"));
|
||||
|
||||
gemfireProperties.setPropertyIfNotDefault("load-cluster-configuration-from-dir",
|
||||
annotationAttributes.get("loadClusterConfigurationFromDirectory"),
|
||||
DEFAULT_LOAD_CLUSTER_CONFIGURATION_FROM_DIRECTORY);
|
||||
|
||||
gemfireProperties.setPropertyIfNotDefault("locator-wait-time",
|
||||
annotationAttributes.get("locatorWaitTimeout"), DEFAULT_LOCATOR_WAIT_TIME);
|
||||
|
||||
gemfireProperties.setPropertyIfNotDefault("lock-memory",
|
||||
annotationAttributes.get("lockMemory"), DEFAULT_LOCK_MEMORY);
|
||||
|
||||
gemfireProperties.setPropertyIfNotDefault("max-wait-time-reconnect",
|
||||
annotationAttributes.get("maxWaitTimeReconnect"), DEFAULT_MAX_WAIT_TIME_RECONNECT);
|
||||
|
||||
gemfireProperties.setPropertyIfNotDefault("member-timeout",
|
||||
annotationAttributes.get("memberTimeout"), DEFAULT_MEMBER_TIMEOUT);
|
||||
|
||||
gemfireProperties.setPropertyIfNotDefault("membership-port-range",
|
||||
annotationAttributes.get("membershipPortRange"), DEFAULT_MEMBERSHIP_PORT_RANGE);
|
||||
|
||||
gemfireProperties.setProperty("redundancy-zone", annotationAttributes.get("redundancyZone"));
|
||||
|
||||
gemfireProperties.setProperty("remote-locators", annotationAttributes.get("remoteLocators"));
|
||||
|
||||
gemfireProperties.setPropertyIfNotDefault("remove-unresponsive-client",
|
||||
annotationAttributes.get("removeUnresponsiveClient"), DEFAULT_REMOVE_UNRESPONSIVE_CLIENT);
|
||||
|
||||
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("tombstone-gc-threshold",
|
||||
annotationAttributes.get("tombstoneGcThreshold"), DEFAULT_TOMBSTONE_THRESHOLD);
|
||||
|
||||
gemfireProperties.setPropertyIfNotDefault("udp-fragment-size",
|
||||
annotationAttributes.get("udpFragmentSize"), DEFAULT_UDP_FRAGMENT_SIZE);
|
||||
|
||||
gemfireProperties.setPropertyIfNotDefault("udp-recv-buffer-size",
|
||||
annotationAttributes.get("udpReceiveBufferSize"), DEFAULT_UDP_RECEIVE_BUFFER_SIZE);
|
||||
|
||||
gemfireProperties.setPropertyIfNotDefault("udp-send-buffer-size",
|
||||
annotationAttributes.get("udpSendBufferSize"), DEFAULT_UDP_SEND_BUFFER_SIZE);
|
||||
|
||||
gemfireProperties.setProperty("user-command-packages", annotationAttributes.get("userCommandPackages"));
|
||||
|
||||
return gemfireProperties.build();
|
||||
}
|
||||
}
|
||||
@@ -25,7 +25,7 @@ import org.springframework.data.gemfire.util.PropertiesBuilder;
|
||||
|
||||
/**
|
||||
* The ManagerConfiguration class is a Spring {@link org.springframework.context.annotation.ImportBeanDefinitionRegistrar}
|
||||
* that applies additional GemFire configuration by way of GemFire System properties to configure
|
||||
* that applies additional GemFire configuration using GemFire System {@link Properties} to configure
|
||||
* an embedded GemFire Manager.
|
||||
*
|
||||
* @author John Blum
|
||||
@@ -46,27 +46,15 @@ public class ManagerConfiguration extends EmbeddedServiceConfigurationSupport {
|
||||
protected Properties toGemFireProperties(Map<String, Object> annotationAttributes) {
|
||||
PropertiesBuilder gemfireProperties = new PropertiesBuilder();
|
||||
|
||||
boolean jmxManager = Boolean.valueOf(String.valueOf(annotationAttributes.get("jmxManager")));
|
||||
|
||||
if (jmxManager) {
|
||||
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) {
|
||||
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"));
|
||||
}
|
||||
}
|
||||
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-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"));
|
||||
|
||||
return gemfireProperties.build();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,437 @@
|
||||
/*
|
||||
* 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.config.annotation;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Inherited;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
||||
/**
|
||||
* The WithGemFireProperties annotation marks a Spring {@link org.springframework.context.annotation.Configuration @Configuration}
|
||||
* annotated class to configure GemFire/Geode System properties at runtime during [Spring Boot] application startup.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.springframework.data.gemfire.config.annotation.GemFirePropertiesConfiguration
|
||||
* @see <a href="http://gemfire.docs.pivotal.io/docs-gemfire/reference/topics/gemfire_properties.html">GemFire System Properties</a>
|
||||
* @see <a href="http://geode.docs.pivotal.io/docs/reference/topics/gemfire_properties.html">Geode System Properties</a>
|
||||
* @since 1.9.0
|
||||
*/
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Inherited
|
||||
@Documented
|
||||
@Import(GemFirePropertiesConfiguration.class)
|
||||
@SuppressWarnings("unused")
|
||||
public @interface WithGemFireProperties {
|
||||
|
||||
/**
|
||||
* Number of seconds the distributed system will wait after the {@literal ack-wait-threshold} for a message
|
||||
* to be acknowledged before it issues an alert at severe level. A value of zero disables this feature.
|
||||
*
|
||||
* Defaults to {@literal 0} seconds.
|
||||
*/
|
||||
int ackSevereAlertThreshold() default GemFirePropertiesConfiguration.DEFAULT_ACK_SEVERE_ALERT_THRESHOLD;
|
||||
|
||||
/**
|
||||
* Number of seconds a distributed message can wait for acknowledgment before it sends an alert to signal
|
||||
* that something might be wrong with the system member that is unresponsive.
|
||||
*
|
||||
* The waiter continues to wait. The alerts are logged in the system member’s log as warnings.
|
||||
* Valid values are in the range 0…2147483647
|
||||
*
|
||||
* Defaults to {@literal 15} seconds.
|
||||
*/
|
||||
int ackWaitThreshold() default GemFirePropertiesConfiguration.DEFAULT_ACK_WAIT_THRESHOLD;
|
||||
|
||||
/**
|
||||
* The number of milliseconds a process that is publishing to this process should attempt to distribute
|
||||
* a cache operation before switching over to asynchronous messaging for this process. The switch to
|
||||
* asynchronous messaging lasts until this process catches up, departs, or some specified limit is reached,
|
||||
* such as async-queue-timeout or async-max-queue-size.
|
||||
*
|
||||
* This setting controls only peer-to-peer communication and does not apply to client/server
|
||||
* or multi-site communication.
|
||||
*
|
||||
* Defaults to {@literal 0} milliseconds.
|
||||
*/
|
||||
long asyncDistributionTimeout() default GemFirePropertiesConfiguration.DEFAULT_ASYNC_DISTRIBUTION_TIMEOUT;
|
||||
|
||||
/**
|
||||
* Affects non-conflated asynchronous queues for members that publish to this member. This is the maximum size
|
||||
* the queue can reach (in megabytes) before the publisher asks this member to leave the distributed system.
|
||||
*
|
||||
* Valid values are in the range 0..1024.
|
||||
*
|
||||
* This setting controls only peer-to-peer communication and does not apply to client/server
|
||||
* or multi-site communication.
|
||||
*
|
||||
* Defaults to {@literal 8} MB.
|
||||
*/
|
||||
int asyncMaxQueueSize() default GemFirePropertiesConfiguration.DEFAULT_ASYNC_MAX_QUEUE_SIZE;
|
||||
|
||||
/**
|
||||
* Affects asynchronous queues for members that publish to this member. This is the maximum milliseconds
|
||||
* the publisher should wait with no distribution to this member before it asks this member to leave
|
||||
* the distributed system. Used for handling slow receivers.
|
||||
*
|
||||
* This setting controls only peer-to-peer communication and does not apply to client/server
|
||||
* or multi-site communication.
|
||||
*
|
||||
* Defaults to {@literal 60000} milliseconds.
|
||||
*/
|
||||
long asyncQueueTimeout() default GemFirePropertiesConfiguration.DEFAULT_ASYNC_QUEUE_TIMEOUT;
|
||||
|
||||
/**
|
||||
* Relevant only for multi-homed hosts - machines with multiple network interface cards (NICs).
|
||||
* Specifies the adapter card the cache binds to for peer-to-peer (P2P) communication. Also specifies
|
||||
* the default location for GemFire Servers to listen on, which is used unless overridden by
|
||||
* the {@literal server-bind-address}. An empty string causes the member to listen on the default card
|
||||
* for the machine. This is a machine-wide attribute used for system member and client/server communication.
|
||||
* It has no effect on Locator location, unless the Locator is embedded in a member process.
|
||||
*
|
||||
* Specify the IP address, not the hostname, because each network card may not have a unique hostname.
|
||||
* An empty string (the default) causes the member to listen on the default card for the machine.
|
||||
*
|
||||
* Defaults to unset.
|
||||
*/
|
||||
String bindAddress() default "";
|
||||
|
||||
/**
|
||||
* Declarative initialization file for the member’s cache.
|
||||
*
|
||||
* Defaults to unset.
|
||||
*/
|
||||
String cacheXmlFile() default "";
|
||||
|
||||
/**
|
||||
* This property specifies the directory in which the cluster configuration related disk-store and artifacts
|
||||
* are stored. This property is only applicable to dedicated Locators that have {@literal enable-cluster-configuration}
|
||||
* set to {@literal true}.
|
||||
*
|
||||
* Defaults to unset.
|
||||
*/
|
||||
String clusterConfigurationDirectory() default "";
|
||||
|
||||
/**
|
||||
* Used only by clients in a client/server installation. This is a client-side property
|
||||
* that is passed to the server. Affects subscription queue conflation in this client’s
|
||||
* servers. Specifies whether to conflate (true setting), not conflate (false), or to
|
||||
* use the server’s conflation setting (server).
|
||||
*
|
||||
* Defaults to {@literal server}.
|
||||
*/
|
||||
String conflateEvents() default GemFirePropertiesConfiguration.DEFAULT_CONFLATE_EVENTS;
|
||||
|
||||
/**
|
||||
* Specifies whether sockets are shared by the system member’s threads. If true, threads share,
|
||||
* and a minimum number of sockets are used to connect to the distributed system. If false,
|
||||
* every application thread has its own sockets for distribution purposes. You can override
|
||||
* this setting for individual threads inside your application. Where possible, it is better to
|
||||
* set {@literal conserve-sockets} to {@literal true} and enable the use of specific extra sockets
|
||||
* in the application code if needed. WAN deployments increase the messaging demands on a GemFire system.
|
||||
* To avoid hangs related to WAN messaging, always set {@literal conserve-sockets} to {@literal false}
|
||||
* for GemFire members that participate in a WAN deployment.
|
||||
*
|
||||
* Defaults to {@literal true}.
|
||||
*/
|
||||
boolean conserveSockets() default GemFirePropertiesConfiguration.DEFAULT_CONSERVE_SOCKETS;
|
||||
|
||||
/**
|
||||
* Specifies whether to distribute the deltas for entry updates, instead of the full values,
|
||||
* between clients and servers, and between peers.
|
||||
*
|
||||
* Default to {@literal true}.
|
||||
*/
|
||||
boolean deltaPropagation() default GemFirePropertiesConfiguration.DEFAULT_DELTA_PROPAGATION;
|
||||
|
||||
/**
|
||||
* Working directory used when deploying JAR application files to distributed system members.
|
||||
* This directory can be local and unique to the member or a shared resource.
|
||||
*
|
||||
* Defaults to current working directory of this GemFire JVM process.
|
||||
*/
|
||||
String deployWorkingDirectory() default GemFirePropertiesConfiguration.DEFAULT_DEPLOY_WORKING_DIRECTORY;
|
||||
|
||||
/**
|
||||
* Boolean indicating whether to disable the use of TCP/IP sockets for inter-cache point-to-point messaging.
|
||||
* If disabled, the cache uses datagram (UDP) sockets.
|
||||
*
|
||||
* Defaults to {@literal false}.
|
||||
*/
|
||||
boolean disableTcp() default GemFirePropertiesConfiguration.DEFAULT_DISABLE_TCP;
|
||||
|
||||
/**
|
||||
* Identifier used to distinguish messages from different distributed systems.
|
||||
*
|
||||
* Set this to different values for different systems in a multi-site (WAN) configuration. This is required
|
||||
* for Portable Data eXchange (PDX) data serialization. This setting must be the same for every member
|
||||
* in the same distributed system and unique to the distributed system within the WAN installation.
|
||||
*
|
||||
* -1 means no setting. Valid values are integers in the range -1…255.
|
||||
*
|
||||
* Defaults to {@literal -1}.
|
||||
*/
|
||||
int distributedSystemId() default GemFirePropertiesConfiguration.DEFAULT_DISTRIBUTED_SYSTEM_ID;
|
||||
|
||||
/**
|
||||
* Boolean instructing the system to detect and handle splits in the distributed system, typically caused by
|
||||
* a partitioning of the network (split brain) where the distributed system is running. We recommend setting
|
||||
* this property to {@literal true}. You must set this property to the same value across all your
|
||||
* distributed system members. In addition, you must set this property to {@literal true} if you are using
|
||||
* persistent Regions and configure your Regions to use {@literal DISTRIBUTED_ACK} or {@literal GLOBAL} scope
|
||||
* to avoid potential data conflicts.
|
||||
*
|
||||
* Defaults to {@literal false}.
|
||||
*/
|
||||
boolean enableNetworkPartitionDetection() default GemFirePropertiesConfiguration.DEFAULT_ENABLE_NETWORK_PARTITION_DETECTION;
|
||||
|
||||
/**
|
||||
* Whether partitioned regions will put redundant copies of the same data in different members
|
||||
* running on the same physical machine. By default, GemFire tries to put redundant copies on different machines,
|
||||
* but it will put them on the same machine if no other machines are available. Setting this property
|
||||
* to {@literal true} prevents this and requires different machines for redundant copies.
|
||||
*
|
||||
* Defaults to {@literal false}.
|
||||
*/
|
||||
boolean enforceUniqueHost() default GemFirePropertiesConfiguration.DEFAULT_ENFORCE_UNIQUE_HOST;
|
||||
|
||||
/**
|
||||
* Defines the list of groups that this member belongs to. Use commas to separate group names.
|
||||
* Note that anything defined by the {@literal roles} gemfire property will also be considered
|
||||
* a group.
|
||||
*
|
||||
* Default to unset.
|
||||
*/
|
||||
String[] groups() default {};
|
||||
|
||||
/**
|
||||
* Setting this property to {@literal true} causes loading of cluster configuration from the
|
||||
* {@literal cluster_config} directory in the Locator. This property is only applicable to dedicated Locators
|
||||
* that have {@literal enable-cluster-configuration} set to {@literal true}.
|
||||
*
|
||||
* Defaults to {@literal false}.
|
||||
*/
|
||||
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
|
||||
* when attempting to join the distributed system. Use this setting when you are starting Locators
|
||||
* and peers all at once. This timeout allows peers to wait for the Locators to finish starting up
|
||||
* before attempting to join the distributed system.
|
||||
*
|
||||
* Defaults to {@literal 0} seconds.
|
||||
*/
|
||||
long locatorWaitTimeout() default GemFirePropertiesConfiguration.DEFAULT_LOCATOR_WAIT_TIME;
|
||||
|
||||
/**
|
||||
* When true, locks heap and off-heap memory into RAM to prevent the operating system from paging the memory
|
||||
* out to disk.
|
||||
*
|
||||
* Defaults to {@literal false}.
|
||||
*/
|
||||
boolean lockMemory() default GemFirePropertiesConfiguration.DEFAULT_LOCK_MEMORY;
|
||||
|
||||
/**
|
||||
* Maximum number of milliseconds to wait for the distributed system to reconnect on each reconnect attempt.
|
||||
*
|
||||
* {@link PeerCacheApplication#enableAutoReconnect()} or {@link CacheServerApplication#enableAutoReconnect()}
|
||||
* must be set to {@literal true} for this property to have any effect.
|
||||
*
|
||||
* Defaults to {@literal 60000} milliseconds.
|
||||
*/
|
||||
long maxWaitTimeReconnect() default GemFirePropertiesConfiguration.DEFAULT_MAX_WAIT_TIME_RECONNECT;
|
||||
|
||||
/**
|
||||
* GemFire uses the {@literal member-timeout} server configuration, specified in milliseconds, to detect
|
||||
* the abnormal termination of members. The configuration setting is used in two ways:
|
||||
*
|
||||
* 1) First, it is used during the UDP heartbeat detection process. When a member detects that
|
||||
* a heartbeat datagram is missing from the member that it is monitoring after the time interval
|
||||
* of 2 * the value of member-timeout, the detecting member attempts to form a TCP/IP stream-socket connection
|
||||
* with the monitored member as described in the next case.
|
||||
*
|
||||
* 2) The property is then used again during the TCP/IP stream-socket connection. If the suspected process
|
||||
* does not respond to the are you alive datagram within the time period specified in member-timeout,
|
||||
* the membership coordinator sends out a new membership view that notes the member’s failure.
|
||||
*
|
||||
* Valid values are in the range 1000..600000.
|
||||
*
|
||||
* Defaults to {@literal 5000} milliseconds.
|
||||
*/
|
||||
long memberTimeout() default GemFirePropertiesConfiguration.DEFAULT_MEMBER_TIMEOUT;
|
||||
|
||||
/**
|
||||
* The range of ports available for unicast UDP messaging and for TCP failure detection. This is specified
|
||||
* as two integers separated by a hyphen. Different members can use different ranges.
|
||||
*
|
||||
* GemFire randomly chooses at least two unique integers from this range for the member, one for
|
||||
* UDP unicast messaging and the other for TCP failure detection messaging. If {@literal tcp-port}
|
||||
* is configured to {@literal 0}, it will also randomly select a port from this range for TCP sockets
|
||||
* used for peer-to-peer communication only.
|
||||
*
|
||||
* Therefore, the specified range must include at least three available port numbers (UDP, FD_SOCK,
|
||||
* and TCP DirectChannel).
|
||||
*
|
||||
* The system uniquely identifies the member using the combined host IP address and UDP port number.
|
||||
*
|
||||
* You may want to restrict the range of ports that GemFire uses so the product can run in an environment
|
||||
* where routers only allow traffic on certain ports.
|
||||
*
|
||||
* Defaults to {@literal 1024-65535}.
|
||||
*/
|
||||
String membershipPortRange() default GemFirePropertiesConfiguration.DEFAULT_MEMBERSHIP_PORT_RANGE;
|
||||
|
||||
/**
|
||||
* 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
|
||||
* in members with the same redundancy zone setting.
|
||||
*
|
||||
* Defaults to unset.
|
||||
*
|
||||
* @see <a href="http://geode.docs.pivotal.io/docs/developing/partitioned_regions/configuring_ha_for_pr.html">Configure High Availability for a Partitioned Region</a>
|
||||
*/
|
||||
String redundancyZone() default "";
|
||||
|
||||
/**
|
||||
* Used to configure the Locators that a cluster will use in order to connect to a remote site in a multi-site
|
||||
* (WAN) configuration.
|
||||
*
|
||||
* To use Locators in a WAN configuration, you must specify a unique distributed system ID
|
||||
* ({@literal distributed-system-id}) for the local cluster and remote Locator(s) for the remote clusters
|
||||
* to which you will connect.
|
||||
*
|
||||
* For each remote Locator, provide a host name and/or address (separated by ‘@’, if you use both),
|
||||
* followed by a port number in brackets.
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* <pre>
|
||||
* <code>
|
||||
* remote-locators=address1[port1],address2[port2]
|
||||
*
|
||||
* remote-locators=hostName1@address1[port1],hostName2@address2[port2]
|
||||
*
|
||||
* remote-locators=hostName1[port1],hostName2[port2]
|
||||
* </code>
|
||||
* </pre>
|
||||
*
|
||||
* Defaults to unset.
|
||||
*/
|
||||
String remoteLocators() default "";
|
||||
|
||||
/**
|
||||
* When this property is set to {@literal true}, the primary server drops unresponsive clients
|
||||
* from all secondaries and itself. Clients are deemed unresponsive when their messaging queues
|
||||
* become full on the server. While a client’s queue is full, puts that would add to the queue
|
||||
* block on the server.
|
||||
*
|
||||
* Defaults to {@literal false}.
|
||||
*/
|
||||
boolean removeUnresponsiveClient() default GemFirePropertiesConfiguration.DEFAULT_REMOVE_UNRESPONSIVE_CLIENT;
|
||||
|
||||
/**
|
||||
* 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
|
||||
* determines the size of the chunks. Larger buffers can handle large messages more quickly, but take up
|
||||
* more memory.
|
||||
*
|
||||
* Defaults to {@literal 32768} bytes.
|
||||
*/
|
||||
int socketBufferSize() default GemFirePropertiesConfiguration.DEFAULT_SOCKET_BUFFER_SIZE;
|
||||
|
||||
/**
|
||||
* Time, in milliseconds, a thread can have exclusive access to a socket it is not actively using.
|
||||
* A value of zero causes socket leases to never expire. This property is ignored
|
||||
* if {@literal conserve-sockets} is {@literal true}.
|
||||
*
|
||||
* Valid values are in the range 0..600000.
|
||||
*
|
||||
* Defaults to {@literal 60000} milliseconds.
|
||||
*/
|
||||
long socketLeaseTime() default GemFirePropertiesConfiguration.DEFAULT_SOCKET_LEASE_TIME;
|
||||
|
||||
/**
|
||||
* The TCP port to listen on for cache communications. If set to zero, the operating system selects
|
||||
* an available port. Each process on a machine must have its own TCP port. Note that some operating systems
|
||||
* restrict the range of ports usable by non-privileged users, and using restricted port numbers can cause
|
||||
* runtime errors in GemFire startup.
|
||||
*
|
||||
* Valid values are in the range 0..65535.
|
||||
*
|
||||
* Defaults to {@literal 0}.
|
||||
*/
|
||||
int tcpPort() default GemFirePropertiesConfiguration.DEFAULT_TCP_PORT;
|
||||
|
||||
/**
|
||||
* The number of tombstones that can accumulate before the GemFire member triggers garbage collection
|
||||
* for tombstones.
|
||||
*
|
||||
* Defaults to {@literal 100000} tombstones.
|
||||
*
|
||||
* @see <a href="http://geode.docs.pivotal.io/docs/developing/distributed_regions/how_region_versioning_works.html#topic_321B05044B6641FCAEFABBF5066BD399">How Destroy and Clear Operations Are Resolved</a>
|
||||
*/
|
||||
int tombstoneGcThreshold() default GemFirePropertiesConfiguration.DEFAULT_TOMBSTONE_THRESHOLD;
|
||||
|
||||
/**
|
||||
* Maximum fragment size, in bytes, for transmission over UDP unicast or multicast sockets. Smaller messages
|
||||
* are combined, if possible, for transmission up to the fragment size setting.
|
||||
*
|
||||
* Valid values are in the range 1000..60000.
|
||||
*
|
||||
* Defaults to {@literal 60000} bytes.
|
||||
*/
|
||||
int udpFragmentSize() default GemFirePropertiesConfiguration.DEFAULT_UDP_FRAGMENT_SIZE;
|
||||
|
||||
/**
|
||||
* The size of the socket buffer used for incoming UDP point-to-point transmissions. If {@literal disable-tcp}
|
||||
* is {@literal false}, a reduced buffer size of 65535 is used by default.
|
||||
*
|
||||
* The default setting of 1048576 is higher than the default OS maximum buffer size on Unix, which should be
|
||||
* increased to at least 1 megabyte to provide high-volume messaging on Unix systems.
|
||||
*
|
||||
* Valid values are in the range 2048.. OS_maximum.
|
||||
*
|
||||
* Defaults to {@literal 1048576} bytes.
|
||||
*/
|
||||
int udpReceiveBufferSize() default GemFirePropertiesConfiguration.DEFAULT_UDP_RECEIVE_BUFFER_SIZE;
|
||||
|
||||
/**
|
||||
* The size of the socket buffer used for outgoing UDP point-to-point transmissions.
|
||||
*
|
||||
* Valid values are in the range 2048..OS_maximum.
|
||||
*
|
||||
* Defaults to {@literal 65535} bytes.
|
||||
*/
|
||||
int udpSendBufferSize() default GemFirePropertiesConfiguration.DEFAULT_UDP_SEND_BUFFER_SIZE;
|
||||
|
||||
/**
|
||||
* A comma separated list of Java packages that contain classes implementing the Spring Shell
|
||||
* CommandMarker interface.
|
||||
*
|
||||
* Matching classes will be loaded when the VM starts and will be available in the GFSH command-line utility.
|
||||
*
|
||||
* Defaults to unset.
|
||||
*/
|
||||
String userCommandPackages() default "";
|
||||
|
||||
}
|
||||
@@ -73,9 +73,8 @@ public abstract class EmbeddedServiceConfigurationSupport implements ImportBeanD
|
||||
/* (non-Javadoc) */
|
||||
@Override
|
||||
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
|
||||
if (importingClassMetadata.hasAnnotation(getAnnotationTypeName())) {
|
||||
Map<String, Object> annotationAttributes =
|
||||
importingClassMetadata.getAnnotationAttributes(getAnnotationTypeName());
|
||||
if (isAnnotationPresent(importingClassMetadata)) {
|
||||
Map<String, Object> annotationAttributes = getAnnotationAttributes(importingClassMetadata);
|
||||
|
||||
Properties customGemFireProperties = toGemFireProperties(annotationAttributes);
|
||||
|
||||
@@ -93,11 +92,21 @@ public abstract class EmbeddedServiceConfigurationSupport implements ImportBeanD
|
||||
/* (non-Javadoc) */
|
||||
protected abstract Properties toGemFireProperties(Map<String, Object> 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 Map<String, Object> getAnnotationAttributes(AnnotationMetadata importingClassMetadata) {
|
||||
return importingClassMetadata.getAnnotationAttributes(getAnnotationTypeName());
|
||||
}
|
||||
|
||||
/* (non-Javadoc) */
|
||||
protected void registerGemFirePropertiesBeanPostProcessor(BeanDefinitionRegistry registry,
|
||||
Properties customGemFireProperties) {
|
||||
|
||||
@@ -24,6 +24,7 @@ import java.util.Properties;
|
||||
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
@@ -49,6 +50,70 @@ public class PropertiesBuilder implements FactoryBean<Properties> {
|
||||
return new PropertiesBuilder();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs and initializes a {@link PropertiesBuilder} containing all properties
|
||||
* from the given {@link InputStream}.
|
||||
*
|
||||
* @param in {@link InputStream} source containing properties to use as the defaults for the constructed builder.
|
||||
* @return a {@link PropertiesBuilder} initialized with properties from the given {@link InputStream}.
|
||||
* @throws IllegalArgumentException if the {@link InputStream} cannot be read.
|
||||
* @see java.io.InputStream
|
||||
* @see java.util.Properties#load(InputStream)
|
||||
*/
|
||||
public static PropertiesBuilder from(InputStream in) {
|
||||
try {
|
||||
Properties defaults = new Properties();
|
||||
defaults.load(in);
|
||||
return new PropertiesBuilder(defaults);
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new IllegalArgumentException("Failed to read properties from InputStream", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs and initializes a {@link PropertiesBuilder} containing all properties
|
||||
* from the given {@link Reader}.
|
||||
*
|
||||
* @param reader {@link Reader} source containing properties to use as the defaults for the constructed builder.
|
||||
* @return a {@link PropertiesBuilder} initialized with properties from the given {@link Reader}.
|
||||
* @throws IllegalArgumentException if the {@link Reader} cannot be read.
|
||||
* @see java.io.Reader
|
||||
* @see java.util.Properties#load(Reader)
|
||||
*/
|
||||
public static PropertiesBuilder from(Reader reader) {
|
||||
try {
|
||||
Properties defaults = new Properties();
|
||||
defaults.load(reader);
|
||||
return new PropertiesBuilder(defaults);
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new IllegalArgumentException("Failed to read properties from Reader", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs and initializes a {@link PropertiesBuilder} containing all properties
|
||||
* from the given {@link InputStream} in XML format.
|
||||
*
|
||||
* @param xml {@link InputStream} source containing properties in XML format to use as defaults
|
||||
* for the constructed builder.
|
||||
* @return a {@link PropertiesBuilder} initialized with properties from the given XML {@link InputStream}.
|
||||
* @throws IllegalArgumentException if the XML {@link InputStream} cannot be read.
|
||||
* @see java.io.InputStream
|
||||
* @see java.util.Properties#loadFromXML(InputStream)
|
||||
*/
|
||||
public static PropertiesBuilder fromXml(InputStream xml) {
|
||||
try {
|
||||
Properties defaults = new Properties();
|
||||
defaults.loadFromXML(xml);
|
||||
return new PropertiesBuilder(defaults);
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new IllegalArgumentException("Failed to read properties from XML", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an instance of the {@link PropertiesBuilder} class.
|
||||
*/
|
||||
@@ -60,6 +125,7 @@ public class PropertiesBuilder implements FactoryBean<Properties> {
|
||||
* Constructs an instance of the {@link PropertiesBuilder} class initialized with the default {@link Properties}.
|
||||
*
|
||||
* @param defaults {@link Properties} used as the defaults.
|
||||
* @throws NullPointerException if the {@link Properties} reference is {@literal null}.
|
||||
* @see java.util.Properties
|
||||
*/
|
||||
public PropertiesBuilder(Properties defaults) {
|
||||
@@ -72,10 +138,11 @@ public class PropertiesBuilder implements FactoryBean<Properties> {
|
||||
* {@link PropertiesBuilder} providing the default {@link Properties} for this builder.
|
||||
*
|
||||
* @param builder {@link PropertiesBuilder} providing the default {@link Properties} for this builder.
|
||||
* @throws NullPointerException if the {@link PropertiesBuilder} reference is {@literal null}.
|
||||
* @see #PropertiesBuilder(Properties)
|
||||
*/
|
||||
public PropertiesBuilder(PropertiesBuilder builder) {
|
||||
this(builder != null ? builder.build() : null);
|
||||
this(builder.build());
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -130,68 +197,7 @@ public class PropertiesBuilder implements FactoryBean<Properties> {
|
||||
* @see org.springframework.data.gemfire.util.PropertiesBuilder
|
||||
*/
|
||||
public PropertiesBuilder add(PropertiesBuilder builder) {
|
||||
if (builder != null) {
|
||||
add(builder.build());
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds all properties from the given {@link InputStream} to this builder.
|
||||
*
|
||||
* @param in {@link InputStream} source containing properties to add to this builder.
|
||||
* @return a reference to this {@link PropertiesBuilder}.
|
||||
* @throws IllegalArgumentException if the {@link InputStream} cannot be read.
|
||||
* @see java.util.Properties#load(InputStream)
|
||||
* @see java.io.InputStream
|
||||
*/
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds all properties from the given {@link Reader} to this builder.
|
||||
*
|
||||
* @param reader {@link Reader} source containing properties to add to this builder.
|
||||
* @return a reference to this {@link PropertiesBuilder}.
|
||||
* @throws IllegalArgumentException if the {@link Reader} cannot be read.
|
||||
* @see java.util.Properties#load(Reader)
|
||||
* @see java.io.Reader
|
||||
*/
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds all properties from the given {@link InputStream} in XML format to this builder.
|
||||
*
|
||||
* @param xml {@link InputStream} source containing properties in XML format to add to this builder.
|
||||
* @return a reference to this {@link PropertiesBuilder}.
|
||||
* @throws IllegalArgumentException if the XML {@link InputStream} cannot be read.
|
||||
* @see java.util.Properties#loadFromXML(InputStream)
|
||||
* @see java.io.InputStream
|
||||
*/
|
||||
public PropertiesBuilder fromXml(InputStream xml) {
|
||||
try {
|
||||
this.properties.loadFromXML(xml);
|
||||
return this;
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new IllegalArgumentException("Failed to read properties from XML", e);
|
||||
}
|
||||
return (builder != null ? add(builder.build()) : this);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -206,6 +212,11 @@ public class PropertiesBuilder implements FactoryBean<Properties> {
|
||||
return (value != null ? setProperty(name, value.toString()) : this);
|
||||
}
|
||||
|
||||
public PropertiesBuilder setProperty(String name, Object[] values) {
|
||||
return (!ObjectUtils.isEmpty(values) ? setProperty(name, StringUtils.arrayToCommaDelimitedString(values))
|
||||
: this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a property with the given name to the specified {@link String} value. The property is only set
|
||||
* if the value is not {@literal null}, an empty {@link String} or not equal to the {@link String} literal
|
||||
@@ -218,7 +229,7 @@ public class PropertiesBuilder implements FactoryBean<Properties> {
|
||||
* @see java.util.Properties#setProperty(String, String)
|
||||
*/
|
||||
public PropertiesBuilder setProperty(String name, String value) {
|
||||
Assert.hasText(name, String.format("Name [%s] must not be specified", name));
|
||||
Assert.hasText(name, String.format("Name [%s] must be specified", name));
|
||||
|
||||
if (isValuable(value)) {
|
||||
this.properties.setProperty(name, value);
|
||||
@@ -227,6 +238,10 @@ public class PropertiesBuilder implements FactoryBean<Properties> {
|
||||
return this;
|
||||
}
|
||||
|
||||
public <T> PropertiesBuilder setPropertyIfNotDefault(String name, Object value, T defaultValue) {
|
||||
return (defaultValue == null || !defaultValue.equals(value) ? setProperty(name, value) : this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the given {@link String} value is a valid {@link Properties} value. A property value is
|
||||
* considered valid if it is not null, not empty and not equal to (case-insensitive) {@link String} literal
|
||||
|
||||
@@ -39,7 +39,7 @@ import org.junit.Test;
|
||||
* @author John Blum
|
||||
* @see java.util.Properties
|
||||
* @see org.springframework.data.gemfire.util.PropertiesBuilder
|
||||
* @since 1.0.0
|
||||
* @since 1.9.0
|
||||
*/
|
||||
public class PropertiesBuilderTests {
|
||||
|
||||
@@ -84,59 +84,10 @@ public class PropertiesBuilderTests {
|
||||
|
||||
assertThat(properties, is(notNullValue(Properties.class)));
|
||||
assertThat(properties.size(), is(equalTo(1)));
|
||||
assertThat(properties.containsKey("one"), is(true));
|
||||
assertThat(properties.getProperty("one"), is(equalTo("1")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void propertiesBuilderIsSingleton() {
|
||||
assertThat(new PropertiesBuilder().isSingleton(), is(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void addPropertiesFromPropertiesIsSuccessful() {
|
||||
PropertiesBuilder builder = PropertiesBuilder.create()
|
||||
.setProperty("one", "1")
|
||||
.setProperty("two", "@");
|
||||
|
||||
Properties sink = builder.build();
|
||||
|
||||
assertThat(sink, is(notNullValue(Properties.class)));
|
||||
assertThat(sink.size(), is(2));
|
||||
assertThat(sink.getProperty("one"), is(equalTo("1")));
|
||||
assertThat(sink.getProperty("two"), is(equalTo("@")));
|
||||
assertThat(sink.containsKey("three"), is(false));
|
||||
|
||||
Properties source = new Properties();
|
||||
|
||||
source.setProperty("two", "2");
|
||||
source.setProperty("three", "3");
|
||||
|
||||
builder.add(source);
|
||||
|
||||
sink = builder.build();
|
||||
|
||||
assertThat(sink, is(notNullValue(Properties.class)));
|
||||
assertThat(sink.size(), is(equalTo(3)));
|
||||
assertThat(sink, is(not(sameInstance(source))));
|
||||
assertThat(sink.getProperty("one"), is(equalTo("1")));
|
||||
assertThat(sink.getProperty("two"), is(equalTo("2")));
|
||||
assertThat(sink.getProperty("three"), is(equalTo("3")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void addPropertiesFromPropertiesBuilderIsSuccessful() {
|
||||
PropertiesBuilder source = PropertiesBuilder.create()
|
||||
.setProperty("one", "1")
|
||||
.setProperty("two", "2");
|
||||
|
||||
Properties properties = new PropertiesBuilder().add(source).build();
|
||||
|
||||
assertThat(properties, is(notNullValue(Properties.class)));
|
||||
assertThat(properties.size(), is(equalTo(2)));
|
||||
assertThat(properties.getProperty("one"), is(equalTo("1")));
|
||||
assertThat(properties.getProperty("two"), is(equalTo("2")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void fromInputStreamIsSuccessful() throws IOException {
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
@@ -145,7 +96,7 @@ public class PropertiesBuilderTests {
|
||||
|
||||
source.store(out, "fromInputStreamIsSuccessfulTest");
|
||||
|
||||
Properties sink = PropertiesBuilder.create().from(new ByteArrayInputStream(out.toByteArray())).build();
|
||||
Properties sink = PropertiesBuilder.from(new ByteArrayInputStream(out.toByteArray())).build();
|
||||
|
||||
assertThat(sink, is(notNullValue(Properties.class)));
|
||||
assertThat(sink, is(not(sameInstance(source))));
|
||||
@@ -160,7 +111,7 @@ public class PropertiesBuilderTests {
|
||||
|
||||
source.store(writer, "fromReaderIsSuccessfulTest");
|
||||
|
||||
Properties sink = PropertiesBuilder.create().from(new StringReader(writer.toString())).build();
|
||||
Properties sink = PropertiesBuilder.from(new StringReader(writer.toString())).build();
|
||||
|
||||
assertThat(sink, is(notNullValue(Properties.class)));
|
||||
assertThat(sink, is(not(sameInstance(source))));
|
||||
@@ -175,13 +126,76 @@ public class PropertiesBuilderTests {
|
||||
|
||||
source.storeToXML(out, "fromXmlInputStreamIsSuccessfulTest");
|
||||
|
||||
Properties sink = PropertiesBuilder.create().fromXml(new ByteArrayInputStream(out.toByteArray())).build();
|
||||
Properties sink = PropertiesBuilder.fromXml(new ByteArrayInputStream(out.toByteArray())).build();
|
||||
|
||||
assertThat(sink, is(notNullValue(Properties.class)));
|
||||
assertThat(sink, is(not(sameInstance(source))));
|
||||
assertThat(sink, is(equalTo(source)));
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void propertiesBuilderObjectTypeIsPropertiesClass() {
|
||||
assertThat((Class<Properties>) PropertiesBuilder.create().getObjectType(), is(equalTo(Properties.class)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void propertiesBuilderIsSingletonIsTrue() {
|
||||
assertThat(new PropertiesBuilder().isSingleton(), is(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void addPropertiesFromPropertiesIsSuccessful() {
|
||||
PropertiesBuilder builder = PropertiesBuilder.create()
|
||||
.setProperty("one", "1")
|
||||
.setProperty("two", "@");
|
||||
|
||||
Properties sink = builder.build();
|
||||
|
||||
assertThat(sink, is(notNullValue(Properties.class)));
|
||||
assertThat(sink.size(), is(2));
|
||||
assertThat(sink.containsKey("one"), is(true));
|
||||
assertThat(sink.containsKey("two"), is(true));
|
||||
assertThat(sink.containsKey("three"), is(false));
|
||||
assertThat(sink.getProperty("one"), is(equalTo("1")));
|
||||
assertThat(sink.getProperty("two"), is(equalTo("@")));
|
||||
|
||||
Properties source = new Properties();
|
||||
|
||||
source.setProperty("two", "2");
|
||||
source.setProperty("three", "3");
|
||||
|
||||
builder.add(source);
|
||||
|
||||
sink = builder.build();
|
||||
|
||||
assertThat(sink, is(notNullValue(Properties.class)));
|
||||
assertThat(sink.size(), is(equalTo(3)));
|
||||
assertThat(sink, is(not(sameInstance(source))));
|
||||
assertThat(sink.containsKey("one"), is(true));
|
||||
assertThat(sink.containsKey("two"), is(true));
|
||||
assertThat(sink.containsKey("three"), is(true));
|
||||
assertThat(sink.getProperty("one"), is(equalTo("1")));
|
||||
assertThat(sink.getProperty("two"), is(equalTo("2")));
|
||||
assertThat(sink.getProperty("three"), is(equalTo("3")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void addPropertiesFromPropertiesBuilderIsSuccessful() {
|
||||
PropertiesBuilder source = PropertiesBuilder.create()
|
||||
.setProperty("one", "1")
|
||||
.setProperty("two", "2");
|
||||
|
||||
Properties properties = PropertiesBuilder.create().add(source).build();
|
||||
|
||||
assertThat(properties, is(notNullValue(Properties.class)));
|
||||
assertThat(properties.size(), is(equalTo(2)));
|
||||
assertThat(properties.containsKey("one"), is(true));
|
||||
assertThat(properties.containsKey("two"), is(true));
|
||||
assertThat(properties.getProperty("one"), is(equalTo("1")));
|
||||
assertThat(properties.getProperty("two"), is(equalTo("2")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setObjectPropertyValuesIsSuccessful() {
|
||||
Properties properties = PropertiesBuilder.create()
|
||||
@@ -201,9 +215,21 @@ public class PropertiesBuilderTests {
|
||||
assertThat(properties.getProperty("string"), is(equalTo("test")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setObjectArrayPropertyValueIsSuccessful() {
|
||||
Properties properties = PropertiesBuilder.create()
|
||||
.setProperty("numbers", new Object[] { "one", "two", "three" })
|
||||
.build();
|
||||
|
||||
assertThat(properties, is(notNullValue(Properties.class)));
|
||||
assertThat(properties.size(), is(equalTo(1)));
|
||||
assertThat(properties.containsKey("numbers"), is(true));
|
||||
assertThat(properties.getProperty("numbers"), is(equalTo("one,two,three")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setPropertyIgnoresNullObjectValue() {
|
||||
Properties properties = PropertiesBuilder.create().setProperty("object", null).build();
|
||||
Properties properties = PropertiesBuilder.create().setProperty("object", (Object) null).build();
|
||||
|
||||
assertThat(properties, is(notNullValue(Properties.class)));
|
||||
assertThat(properties.isEmpty(), is(true));
|
||||
@@ -215,12 +241,29 @@ public class PropertiesBuilderTests {
|
||||
.setProperty("blank", " ")
|
||||
.setProperty("empty", "")
|
||||
.setProperty("null", "null")
|
||||
.setProperty("nullWithWhiteSpace", " null ")
|
||||
.build();
|
||||
|
||||
assertThat(properties, is(notNullValue(Properties.class)));
|
||||
assertThat(properties.isEmpty(), is(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setPropertyIgnoresEmptyObjectArray() {
|
||||
Properties properties = PropertiesBuilder.create().setProperty("emptyArray", new Object[0]).build();
|
||||
|
||||
assertThat(properties, is(notNullValue(Properties.class)));
|
||||
assertThat(properties.isEmpty(), is(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setPropertyIgnoresNullObjectArray() {
|
||||
Properties properties = PropertiesBuilder.create().setProperty("nullArray", (Object[]) null).build();
|
||||
|
||||
assertThat(properties, is(notNullValue(Properties.class)));
|
||||
assertThat(properties.isEmpty(), is(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void setStringPropertyValuesIsSuccessful() {
|
||||
Properties properties = PropertiesBuilder.create()
|
||||
@@ -230,6 +273,8 @@ public class PropertiesBuilderTests {
|
||||
|
||||
assertThat(properties, is(notNullValue(Properties.class)));
|
||||
assertThat(properties.size(), is(equalTo(2)));
|
||||
assertThat(properties.containsKey("one"), is(true));
|
||||
assertThat(properties.containsKey("two"), is(true));
|
||||
assertThat(properties.getProperty("one"), is(equalTo("1")));
|
||||
assertThat(properties.getProperty("two"), is(equalTo("2")));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user