SGF-433 - Fix improper resolution of Spring property placeholders in 'locators' and 'servers' attributes on the '<gfe:pool>' element(s) in Spring XML config.

This commit is contained in:
John Blum
2015-09-30 23:23:00 -07:00
parent 2f15b322ee
commit 1cd2a7ff50
23 changed files with 2232 additions and 242 deletions

View File

@@ -28,7 +28,9 @@ import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.data.gemfire.util.CollectionUtils;
import org.springframework.data.gemfire.support.ConnectionEndpoint;
import org.springframework.data.gemfire.support.ConnectionEndpointList;
import org.springframework.data.gemfire.util.DistributedSystemUtils;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
@@ -36,7 +38,6 @@ import com.gemstone.gemfire.cache.client.Pool;
import com.gemstone.gemfire.cache.client.PoolFactory;
import com.gemstone.gemfire.cache.client.PoolManager;
import com.gemstone.gemfire.distributed.DistributedSystem;
import com.gemstone.gemfire.distributed.internal.InternalDistributedSystem;
/**
* FactoryBean for easy declaration and configuration of a GemFire Pool. If a new Pool is created,
@@ -47,13 +48,26 @@ import com.gemstone.gemfire.distributed.internal.InternalDistributedSystem;
*
* @author Costin Leau
* @author John Blum
* @see java.net.InetSocketAddress
* @see org.springframework.beans.factory.BeanFactory
* @see org.springframework.beans.factory.BeanFactoryAware
* @see org.springframework.beans.factory.BeanNameAware
* @see org.springframework.beans.factory.DisposableBean
* @see org.springframework.beans.factory.FactoryBean
* @see org.springframework.beans.factory.InitializingBean
* @see org.springframework.data.gemfire.support.ConnectionEndpoint
* @see org.springframework.data.gemfire.support.ConnectionEndpointList
* @see com.gemstone.gemfire.cache.client.Pool
* @see com.gemstone.gemfire.cache.client.PoolFactory
* @see com.gemstone.gemfire.cache.client.PoolManager
* @see com.gemstone.gemfire.distributed.DistributedSystem
*/
@SuppressWarnings("unused")
public class PoolFactoryBean implements FactoryBean<Pool>, InitializingBean, DisposableBean, BeanNameAware,
BeanFactoryAware {
public class PoolFactoryBean implements FactoryBean<Pool>, InitializingBean, DisposableBean,
BeanNameAware, BeanFactoryAware {
protected static final int DEFAULT_LOCATOR_PORT = DistributedSystemUtils.DEFAULT_LOCATOR_PORT;
protected static final int DEFAULT_SERVER_PORT = DistributedSystemUtils.DEFAULT_CACHE_SERVER_PORT;
private static final Log log = LogFactory.getLog(PoolFactoryBean.class);
@@ -62,8 +76,8 @@ public class PoolFactoryBean implements FactoryBean<Pool>, InitializingBean, Dis
private BeanFactory beanFactory;
private Collection<InetSocketAddress> locators;
private Collection<InetSocketAddress> servers;
private ConnectionEndpointList locators = new ConnectionEndpointList();
private ConnectionEndpointList servers = new ConnectionEndpointList();
private Pool pool;
@@ -128,7 +142,7 @@ public class PoolFactoryBean implements FactoryBean<Pool>, InitializingBean, Dis
log.debug(String.format("No Pool with name '%1$s' was found. Creating a new Pool...", name));
}
if (CollectionUtils.isEmpty(locators) && CollectionUtils.isEmpty(servers)) {
if (locators.isEmpty() && servers.isEmpty()) {
throw new IllegalArgumentException("at least one GemFire Locator or Server is required");
}
@@ -155,12 +169,12 @@ public class PoolFactoryBean implements FactoryBean<Pool>, InitializingBean, Dis
poolFactory.setSubscriptionRedundancy(subscriptionRedundancy);
poolFactory.setThreadLocalConnections(threadLocalConnections);
for (InetSocketAddress connection : CollectionUtils.nullSafeCollection(locators)) {
poolFactory.addLocator(connection.getHostName(), connection.getPort());
for (ConnectionEndpoint locator : locators) {
poolFactory.addLocator(locator.getHost(), locator.getPort());
}
for (InetSocketAddress connection : CollectionUtils.nullSafeCollection(servers)) {
poolFactory.addServer(connection.getHostName(), connection.getPort());
for (ConnectionEndpoint server : servers) {
poolFactory.addServer(server.getHost(), server.getPort());
}
// eagerly initialize the GemFire DistributedSystem (if needed)
@@ -177,7 +191,7 @@ public class PoolFactoryBean implements FactoryBean<Pool>, InitializingBean, Dis
/* (non-Javadoc) */
void resolveDistributedSystem() {
if (InternalDistributedSystem.getAnyInstance() == null) {
if (DistributedSystemUtils.getDistributedSystem() == null) {
doDistributedSystemConnect(resolveGemfireProperties());
}
}
@@ -257,8 +271,17 @@ public class PoolFactoryBean implements FactoryBean<Pool>, InitializingBean, Dis
this.keepAlive = keepAlive;
}
public void setLocators(Collection<InetSocketAddress> locators) {
this.locators = locators;
@Deprecated
public void setLocators(Iterable<InetSocketAddress> locators) {
setLocatorEndpoints(ConnectionEndpointList.from(locators));
}
public void setLocatorEndpoints(Iterable<ConnectionEndpoint> endpoints) {
this.locators.add(endpoints);
}
public void setLocatorEndpointList(ConnectionEndpointList endpointList) {
setLocatorEndpoints(endpointList);
}
public void setLoadConditioningInterval(int loadConditioningInterval) {
@@ -297,8 +320,17 @@ public class PoolFactoryBean implements FactoryBean<Pool>, InitializingBean, Dis
this.serverGroup = serverGroup;
}
@Deprecated
public void setServers(Collection<InetSocketAddress> servers) {
this.servers = servers;
setServerEndpoints(ConnectionEndpointList.from(servers));
}
public void setServerEndpoints(Iterable<ConnectionEndpoint> endpoints) {
this.servers.add(endpoints);
}
public void setServerEndpointList(ConnectionEndpointList endpointList) {
setServerEndpoints(endpointList);
}
public void setSocketBufferSize(int socketBufferSize) {

View File

@@ -16,24 +16,26 @@
package org.springframework.data.gemfire.config;
import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.regex.Pattern;
import org.springframework.beans.factory.BeanDefinitionStoreException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.ManagedList;
import org.springframework.beans.factory.xml.AbstractSimpleBeanDefinitionParser;
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.data.gemfire.client.PoolFactoryBean;
import org.springframework.data.gemfire.support.ConnectionEndpoint;
import org.springframework.data.gemfire.support.ConnectionEndpointList;
import org.springframework.data.gemfire.util.DistributedSystemUtils;
import org.springframework.util.StringUtils;
import org.springframework.util.xml.DomUtils;
import org.w3c.dom.Element;
import com.gemstone.gemfire.cache.server.CacheServer;
import com.gemstone.gemfire.internal.DistributionLocator;
/**
* Parser for GFE &lt;pool;gt; bean definitions.
*
@@ -41,10 +43,12 @@ import com.gemstone.gemfire.internal.DistributionLocator;
* @author David Turanski
* @author John Blum
*/
class PoolParser extends AbstractSimpleBeanDefinitionParser {
class PoolParser extends AbstractSingleBeanDefinitionParser {
protected static final int DEFAULT_LOCATOR_PORT = DistributionLocator.DEFAULT_LOCATOR_PORT;
protected static final int DEFAULT_SERVER_PORT = CacheServer.DEFAULT_PORT;
protected static final int DEFAULT_LOCATOR_PORT = DistributedSystemUtils.DEFAULT_LOCATOR_PORT;
protected static final int DEFAULT_SERVER_PORT = DistributedSystemUtils.DEFAULT_CACHE_SERVER_PORT;
protected static final Pattern PROPERTY_PLACEHOLDER_PATTERN = Pattern.compile("\\$\\{.+\\}");
protected static final String DEFAULT_HOST = "localhost";
protected static final String HOST_ATTRIBUTE_NAME = "host";
@@ -58,53 +62,95 @@ class PoolParser extends AbstractSimpleBeanDefinitionParser {
protected Class<?> getBeanClass(Element element) {
return PoolFactoryBean.class;
}
@Override
protected void postProcess(BeanDefinitionBuilder builder, Element element) {
List<Element> subElements = DomUtils.getChildElements(element);
protected void doParse(Element element, BeanDefinitionBuilder builder) {
ParsingUtils.setPropertyValue(element, builder, "free-connection-timeout");
ParsingUtils.setPropertyValue(element, builder, "idle-timeout");
ParsingUtils.setPropertyValue(element, builder, "load-conditioning-interval");
ParsingUtils.setPropertyValue(element, builder, "keep-alive");
ParsingUtils.setPropertyValue(element, builder, "max-connections");
ParsingUtils.setPropertyValue(element, builder, "min-connections");
ParsingUtils.setPropertyValue(element, builder, "multi-user-authentication");
ParsingUtils.setPropertyValue(element, builder, "ping-interval");
ParsingUtils.setPropertyValue(element, builder, "pr-single-hop-enabled");
ParsingUtils.setPropertyValue(element, builder, "read-timeout");
ParsingUtils.setPropertyValue(element, builder, "retry-attempts");
ParsingUtils.setPropertyValue(element, builder, "server-group");
ParsingUtils.setPropertyValue(element, builder, "socket-buffer-size");
ParsingUtils.setPropertyValue(element, builder, "statistic-interval");
ParsingUtils.setPropertyValue(element, builder, "subscription-ack-interval");
ParsingUtils.setPropertyValue(element, builder, "subscription-enabled");
ParsingUtils.setPropertyValue(element, builder, "subscription-message-tracking-timeout");
ParsingUtils.setPropertyValue(element, builder, "subscription-redundancy");
ParsingUtils.setPropertyValue(element, builder, "thread-local-connections");
ManagedList<BeanDefinition> locators = new ManagedList<BeanDefinition>(subElements.size());
ManagedList<BeanDefinition> servers = new ManagedList<BeanDefinition>(subElements.size());
List<Element> childElements = DomUtils.getChildElements(element);
// parse nested locator/server elements
for (Element subElement : subElements) {
String name = subElement.getLocalName();
ManagedList<BeanDefinition> locators = new ManagedList<BeanDefinition>(childElements.size());
ManagedList<BeanDefinition> servers = new ManagedList<BeanDefinition>(childElements.size());
if (LOCATOR_ELEMENT_NAME.equals(name)) {
locators.add(parseLocator(subElement));
for (Element childElement : childElements) {
String childElementName = childElement.getLocalName();
if (LOCATOR_ELEMENT_NAME.equals(childElementName)) {
locators.add(parseLocator(childElement));
}
if (SERVER_ELEMENT_NAME.equals(name)) {
servers.add(parseServer(subElement));
if (SERVER_ELEMENT_NAME.equals(childElementName)) {
servers.add(parseServer(childElement));
}
}
locators.addAll(parseLocators(element));
servers.addAll(parseServers(element));
locators.addAll(parseLocators(element, builder));
servers.addAll(parseServers(element, builder));
// NOTE if neither Locators or Servers were specified, then setup a default connection to a Locator
// running on localhost listening on the default Locator port (10334) for convenience
if (locators.isEmpty() && servers.isEmpty()) {
// NOTE if neither Locators nor Servers were specified, then setup a default connection to a Locator
// listening on the default Locator port (10334), running on localhost
if (childElements.isEmpty() && !hasAttributes(element, LOCATORS_ATTRIBUTE_NAME, SERVERS_ATTRIBUTE_NAME)) {
locators.add(buildConnection(DEFAULT_HOST, String.valueOf(DEFAULT_LOCATOR_PORT), false));
}
if (!locators.isEmpty()) {
builder.addPropertyValue("locators", locators);
builder.addPropertyValue("locatorEndpoints", locators);
}
if (!servers.isEmpty()) {
builder.addPropertyValue("servers", servers);
builder.addPropertyValue("serverEndpoints", servers);
}
}
/* (non-Javadoc) */
boolean hasAttributes(Element element, String... attributeNames) {
for (String attributeName : attributeNames) {
if (element.hasAttribute(attributeName)) {
return true;
}
}
return false;
}
BeanDefinition buildConnections(String propertyPlaceholder, boolean server) {
BeanDefinitionBuilder connectionEndpointListBuilder = BeanDefinitionBuilder.genericBeanDefinition(
ConnectionEndpointList.class);
connectionEndpointListBuilder.setFactoryMethod("parse");
connectionEndpointListBuilder.addConstructorArgValue(defaultPort(null, server));
connectionEndpointListBuilder.addConstructorArgValue(propertyPlaceholder);
return connectionEndpointListBuilder.getBeanDefinition();
}
/* (non-Javadoc) */
BeanDefinition buildConnection(String host, String port, boolean server) {
BeanDefinitionBuilder inetSocketAddressBuilder = BeanDefinitionBuilder.genericBeanDefinition(
InetSocketAddress.class);
BeanDefinitionBuilder connectionEndpointBuilder = BeanDefinitionBuilder.genericBeanDefinition(
ConnectionEndpoint.class);
inetSocketAddressBuilder.addConstructorArgValue(defaultHost(host));
inetSocketAddressBuilder.addConstructorArgValue(defaultPort(port, server));
connectionEndpointBuilder.addConstructorArgValue(defaultHost(host));
connectionEndpointBuilder.addConstructorArgValue(defaultPort(port, server));
return inetSocketAddressBuilder.getBeanDefinition();
return connectionEndpointBuilder.getBeanDefinition();
}
/* (non-Javadoc) */
@@ -119,13 +165,15 @@ class PoolParser extends AbstractSimpleBeanDefinitionParser {
}
/* (non-Javadoc) */
ManagedList<BeanDefinition> parseConnections(String hostPortCommaDelimitedList, boolean server) {
ManagedList<BeanDefinition> connections = new ManagedList<BeanDefinition>();
List<BeanDefinition> parseConnections(String hostPortCommaDelimitedList, boolean server) {
List<BeanDefinition> connections = Collections.emptyList();
if (StringUtils.hasText(hostPortCommaDelimitedList)) {
String[] hostPorts = hostPortCommaDelimitedList.split(",");
String[] hostsPorts = hostPortCommaDelimitedList.split(",");
for (String hostPort : hostPorts) {
connections = new ArrayList<BeanDefinition>(hostsPorts.length);
for (String hostPort : hostsPorts) {
connections.add(parseConnection(hostPort, server));
}
}
@@ -135,17 +183,14 @@ class PoolParser extends AbstractSimpleBeanDefinitionParser {
/* (non-Javadoc) */
BeanDefinition parseConnection(String hostPort, boolean server) {
String host = hostPort.trim();
String port = defaultPort(null, server);
String host;
int portIndex = hostPort.indexOf('[');
int portIndex = host.indexOf('[');
if (portIndex > -1) {
host = hostPort.substring(0, portIndex).trim();
port = parseDigits(hostPort.substring(portIndex)).trim();
}
else {
host = hostPort.trim();
port = parseDigits(host.substring(portIndex)).trim();
host = host.substring(0, portIndex).trim();
}
return buildConnection(host, port, server);
@@ -155,9 +200,9 @@ class PoolParser extends AbstractSimpleBeanDefinitionParser {
String parseDigits(String value) {
StringBuilder digits = new StringBuilder();
for (char chr : value.toCharArray()) {
if (Character.isDigit(chr)) {
digits.append(chr);
for (char character : value.toCharArray()) {
if (Character.isDigit(character)) {
digits.append(character);
}
}
@@ -165,21 +210,52 @@ class PoolParser extends AbstractSimpleBeanDefinitionParser {
}
/* (non-Javadoc) */
BeanDefinition parseLocator(Element element) {
return buildConnection(element.getAttribute(HOST_ATTRIBUTE_NAME), element.getAttribute(PORT_ATTRIBUTE_NAME), false);
boolean isPropertyPlaceholder(String value) {
return PROPERTY_PLACEHOLDER_PATTERN.matcher(value).matches();
}
ManagedList<BeanDefinition> parseLocators(Element element) {
return parseConnections(element.getAttribute(LOCATORS_ATTRIBUTE_NAME), false);
/* (non-Javadoc) */
BeanDefinition parseLocator(Element element) {
return buildConnection(element.getAttribute(HOST_ATTRIBUTE_NAME),
element.getAttribute(PORT_ATTRIBUTE_NAME), false);
}
/* (non-Javadoc) */
List<BeanDefinition> parseLocators(Element element, BeanDefinitionBuilder builder) {
List<BeanDefinition> beanDefinitions = Collections.emptyList();
String locatorsAttributeValue = element.getAttribute(LOCATORS_ATTRIBUTE_NAME);
if (isPropertyPlaceholder(locatorsAttributeValue)) {
builder.addPropertyValue("locatorEndpointList", buildConnections(locatorsAttributeValue, false));
}
else {
beanDefinitions = parseConnections(locatorsAttributeValue, false);
}
return beanDefinitions;
}
/* (non-Javadoc) */
BeanDefinition parseServer(Element element) {
return buildConnection(element.getAttribute(HOST_ATTRIBUTE_NAME), element.getAttribute(PORT_ATTRIBUTE_NAME), false);
return buildConnection(element.getAttribute(HOST_ATTRIBUTE_NAME),
element.getAttribute(PORT_ATTRIBUTE_NAME), true);
}
ManagedList<BeanDefinition> parseServers(Element element) {
return parseConnections(element.getAttribute(SERVERS_ATTRIBUTE_NAME), true);
/* (non-Javadoc) */
List<BeanDefinition> parseServers(Element element, BeanDefinitionBuilder builder) {
List<BeanDefinition> beanDefinitions = Collections.emptyList();
String serversAttributeValue = element.getAttribute(SERVERS_ATTRIBUTE_NAME);
if (isPropertyPlaceholder(serversAttributeValue)) {
builder.addPropertyValue("serverEndpointList", buildConnections(serversAttributeValue, true));
}
else {
beanDefinitions = parseConnections(serversAttributeValue, true);
}
return beanDefinitions;
}
/* (non-Javadoc) */

View File

@@ -0,0 +1,200 @@
/*
* Copyright 2010-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.
*/
package org.springframework.data.gemfire.support;
import java.net.InetSocketAddress;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
/**
* The ConnectionEndpoint class models a GemFire connection endpoint in the format of hostname[portnumber],
* where hostname is the network name or IP address of the host.
*
* @author John Blum
* @see java.lang.Cloneable
* @see java.lang.Comparable
* @since 1.6.3
*/
@SuppressWarnings("unused")
public class ConnectionEndpoint implements Cloneable, Comparable<ConnectionEndpoint> {
protected static final int DEFAULT_PORT = 0; // ephemeral port
protected static final String DEFAULT_HOST = "localhost";
private final int port;
private final String host;
/**
* Converts the InetSocketAddress into a ConnectionEndpoint.
*
* @param socketAddress the InetSocketAddress used to construct and initialize the ConnectionEndpoint.
* @return a ConnectionEndpoint representing the InetSocketAddress.
* @see java.net.InetSocketAddress
*/
public static ConnectionEndpoint from(InetSocketAddress socketAddress) {
return new ConnectionEndpoint(socketAddress.getHostString(), socketAddress.getPort());
}
/**
* Parses the host and port String value into a valid ConnectionEndpoint.
*
* @param hostPort a String value containing the host and port formatted as 'host[port]'.
* @return a valid ConnectionEndpoint initialized with the host and port, or with DEFAULT_PORT
* if port was unspecified.
* @see #parse(String, int)
* @see #DEFAULT_PORT
*/
public static ConnectionEndpoint parse(String hostPort) {
return parse(hostPort, DEFAULT_PORT);
}
/**
* Parses the host and port value into a valid ConnectionEndpoint.
*
* @param hostPort a String value containing the host and port formatted as 'host[port]'.
* @param defaultPort an Integer value indicating the default port to use if the port is unspecified
* in the host and port String value.
* @return a valid ConnectionEndpoint initialized with the host and port, or with the default port
* if port was unspecified.
* @see #ConnectionEndpoint(String, int)
*/
public static ConnectionEndpoint parse(String hostPort, int defaultPort) {
Assert.hasText(hostPort, "'hostPort' must be specified");
String host = StringUtils.trimAllWhitespace(hostPort);
int port = defaultPort;
int portIndex = hostPort.indexOf("[");
if (portIndex > -1) {
port = parsePort(parseDigits(host.substring(portIndex)), defaultPort);
host = host.substring(0, portIndex).trim();
}
return new ConnectionEndpoint(host, port);
}
/* (non-Javadoc) */
static String parseDigits(String value) {
StringBuilder digits = new StringBuilder();
if (StringUtils.hasText(value)) {
for (char character : value.toCharArray()) {
if (Character.isDigit(character)) {
digits.append(character);
}
}
}
return digits.toString();
}
/* (non-Javadoc) */
static int parsePort(String port, int defaultPort) {
try {
return Integer.parseInt(port);
}
catch (NumberFormatException ignore) {
return defaultPort;
}
}
/**
* Constructs a ConnectionEndpoint initialized with the specific host and port.
*
* @param host the hostname or IP address of the ConnectionEndpoint. If the host is unspecified,
* then ConnectionEndpoint.DEFAULT_HOST will be used.
* @param port the (service) port number in this ConnectionEndpoint.
* @throws IllegalArgumentException if the port number is less than 0.
* @see ConnectionEndpoint#DEFAULT_HOST
*/
public ConnectionEndpoint(String host, int port) {
Assert.isTrue(port >= 0 && port <= 65535, String.format("port number (%1$d) must be between 0 and 65535", port));
this.host = (StringUtils.hasText(host) ? host : DEFAULT_HOST);
this.port = port;
}
/**
* Gets the host in this ConnectionEndpoint.
*
* @return a String value indicating the hostname or IP address in this ConnectionEndpoint.
*/
public String getHost() {
return host;
}
/**
* Gets the port number in this ConnectionEndpoint.
*
* @return an Integer value indicating the (service) port number in this ConnectionEndpoint.
*/
public int getPort() {
return port;
}
/* (non-Javadoc) */
@Override
@SuppressWarnings("all")
protected Object clone() throws CloneNotSupportedException {
return new ConnectionEndpoint(this.getHost(), this.getPort());
}
/* (non-Javadoc) */
@Override
@SuppressWarnings("all")
public int compareTo(ConnectionEndpoint connectionEndpoint) {
int compareValue = getHost().compareTo(connectionEndpoint.getHost());
return (compareValue != 0 ? compareValue : getPort() - connectionEndpoint.getPort());
}
/* (non-Javadoc) */
@Override
public boolean equals(final Object obj) {
if (obj == this) {
return true;
}
if (!(obj instanceof ConnectionEndpoint)) {
return false;
}
ConnectionEndpoint that = (ConnectionEndpoint) obj;
return ObjectUtils.nullSafeEquals(this.getHost(), that.getHost())
&& ObjectUtils.nullSafeEquals(this.getPort(), that.getPort());
}
/* (non-Javadoc) */
@Override
public int hashCode() {
int hashValue = 17;
hashValue = 37 * hashValue + ObjectUtils.nullSafeHashCode(getHost());
hashValue = 37 * hashValue + ObjectUtils.nullSafeHashCode(getPort());
return hashValue;
}
/* (non-Javadoc) */
@Override
public String toString() {
return String.format("%1$s[%2$d]", getHost(), getPort());
}
}

View File

@@ -0,0 +1,219 @@
/*
* Copyright 2010-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.
*/
package org.springframework.data.gemfire.support;
import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import org.springframework.data.gemfire.util.ArrayUtils;
import org.springframework.data.gemfire.util.CollectionUtils;
/**
* The ConnectionEndpointList class is an Iterable collection of ConnectionEndpoint objects.
*
* @author John Blum
* @see java.lang.Iterable
* @see java.net.InetSocketAddress
* @see org.springframework.data.gemfire.support.ConnectionEndpoint
* @since 1.6.3
*/
@SuppressWarnings("unused")
public class ConnectionEndpointList implements Iterable<ConnectionEndpoint> {
private final List<ConnectionEndpoint> connectionEndpoints;
/**
* Converts the array of InetSocketAddresses into an instance of ConnectionEndpointList.
*
* @param socketAddresses the array of InetSocketAddresses used to initialize an instance of ConnectionEndpointList.
* @return a ConnectionEndpointList representing the array of InetSocketAddresses.
* @see java.net.InetSocketAddress
* @see #from(Iterable)
*/
public static ConnectionEndpointList from(InetSocketAddress... socketAddresses) {
return from(Arrays.asList(socketAddresses));
}
/**
* Converts the Iterable collection of InetSocketAddresses into an instance of ConnectionEndpointList.
*
* @param socketAddresses in Iterable collection of InetSocketAddresses used to initialize an instance
* of ConnectionEndpointList.
* @return a ConnectionEndpointList representing the array of InetSocketAddresses.
* @see java.net.InetSocketAddress
*/
public static ConnectionEndpointList from(Iterable<InetSocketAddress> socketAddresses) {
List<ConnectionEndpoint> connectionEndpoints = new ArrayList<ConnectionEndpoint>();
for (InetSocketAddress socketAddress : CollectionUtils.nullSafeIterable(socketAddresses)) {
connectionEndpoints.add(ConnectionEndpoint.from(socketAddress));
}
return new ConnectionEndpointList(connectionEndpoints);
}
/**
* Parses the array of hosts and ports in the format 'host[port]' to convert into an instance
* of ConnectionEndpointList.
*
* @param defaultPort the default port number to use if port is not specified in a host and port value.
* @param hostsPorts the array of hosts and ports to parse.
* @return a ConnectionEndpointList representing the hosts and ports in the array.
* @see org.springframework.data.gemfire.support.ConnectionEndpoint#parse(String, int)
*/
public static ConnectionEndpointList parse(int defaultPort, String... hostsPorts) {
List<ConnectionEndpoint> connectionEndpoints = new ArrayList<ConnectionEndpoint>(hostsPorts.length);
for (String hostPort : ArrayUtils.nullSafeArray(hostsPorts)) {
connectionEndpoints.add(ConnectionEndpoint.parse(hostPort, defaultPort));
}
return new ConnectionEndpointList(connectionEndpoints);
}
/**
* Constructs an empty, uninitialized instance of the ConnectionEndpointList collection.
*/
public ConnectionEndpointList() {
this(Collections.<ConnectionEndpoint>emptyList());
}
/**
* Constructs an instance of ConnectionEndpointList initialized with the the array of ConnectionEndpoints.
*
* @param connectionEndpoints is an array containing ConnectionEndpoints to add to this collection.
* @see org.springframework.data.gemfire.support.ConnectionEndpoint
* @see #ConnectionEndpointList(Iterable)
*/
public ConnectionEndpointList(ConnectionEndpoint... connectionEndpoints) {
this(Arrays.asList(connectionEndpoints));
}
/**
* Constructs an instance of ConnectionEndpointList initialized with the Iterable collection of ConnectionEndpoints.
*
* @param connectionEndpoints the Iterable object containing ConnectionEndpoints to add to this collection.
* @see org.springframework.data.gemfire.support.ConnectionEndpoint
* @see java.lang.Iterable
*/
public ConnectionEndpointList(Iterable<ConnectionEndpoint> connectionEndpoints) {
this.connectionEndpoints = new ArrayList<ConnectionEndpoint>();
add(connectionEndpoints);
}
/**
* Adds the array of ConnectionEndpoints to this list.
*
* @param connectionEndpoints the array of ConnectionEndpoints to add to this list.
* @return this ConnectionEndpointList to support the Builder pattern style of chaining.
* @see org.springframework.data.gemfire.support.ConnectionEndpoint
* @see #add(Iterable)
*/
public final ConnectionEndpointList add(ConnectionEndpoint... connectionEndpoints) {
Collections.addAll(this.connectionEndpoints, connectionEndpoints);
return this;
}
/**
* Adds the Iterable collection of ConnectionEndpoints to this list.
*
* @param connectionEndpoints the Iterable collection of ConnectionEndpoints to add to this list.
* @return this ConnectionEndpointList to support the Builder pattern style of chaining.
* @see org.springframework.data.gemfire.support.ConnectionEndpoint
* @see #add(ConnectionEndpoint...)
*/
public final ConnectionEndpointList add(Iterable<ConnectionEndpoint> connectionEndpoints) {
for (ConnectionEndpoint connectionEndpoint : CollectionUtils.nullSafeIterable(connectionEndpoints)) {
this.connectionEndpoints.add(connectionEndpoint);
}
return this;
}
/**
* Finds all ConnectionEndpoints in this list with the specified hostname.
*
* @param host a String indicating the hostname to use in the match.
* @return a ConnectionEndpointList (sub-List) containing all the ConnectionEndpoints matching the given hostname.
* @see #findBy(int)
*/
public ConnectionEndpointList findBy(String host) {
List<ConnectionEndpoint> connectionEndpoints = new ArrayList<ConnectionEndpoint>(size());
for (ConnectionEndpoint connectionEndpoint : this) {
if (connectionEndpoint.getHost().equals(host)) {
connectionEndpoints.add(connectionEndpoint);
}
}
return new ConnectionEndpointList(connectionEndpoints);
}
/**
* Finds all ConnectionEndpoints in this list with the specified port number.
*
* @param port an Integer value indicating the port number to use in the match.
* @return a ConnectionEndpointList (sub-List) containing all the ConnectionEndpoints matching the given port number.
* @see #findBy(String)
*/
public ConnectionEndpointList findBy(int port) {
List<ConnectionEndpoint> connectionEndpoints = new ArrayList<ConnectionEndpoint>(size());
for (ConnectionEndpoint connectionEndpoint : this) {
if (connectionEndpoint.getPort() == port) {
connectionEndpoints.add(connectionEndpoint);
}
}
return new ConnectionEndpointList(connectionEndpoints);
}
/**
* Determines whether this collection contains any ConnectionEndpoints.
*
* @return a boolean value indicating whether this collection contains any ConnectionEndpoints.
*/
public boolean isEmpty() {
return connectionEndpoints.isEmpty();
}
/* (non-Javadoc) */
@Override
public Iterator<ConnectionEndpoint> iterator() {
return Collections.unmodifiableList(connectionEndpoints).iterator();
}
/**
* Determines the number of ConnectionEndpoints contained in this collection.
*
* @return an integer value indicating the number of ConnectionEndpoints contained in this collection.
*/
public int size() {
return connectionEndpoints.size();
}
/* (non-Javadoc) */
@Override
public String toString() {
return connectionEndpoints.toString();
}
}

View File

@@ -78,6 +78,19 @@ public abstract class ArrayUtils {
return (array != null ? array.length : 0);
}
/**
* Null-safe, empty array operation returning the given Object array if not null or an empty Object array
* if the array argument is null.
*
* @param <T> the element Class type of the array.
* @param array the Object array on which a null check is performed.
* @return the given Object array if not null, otherwise return an empty Object array.
*/
@SuppressWarnings("unchecked")
public static <T> T[] nullSafeArray(T[] array) {
return (array != null ? array : (T[]) new Object[0]);
}
/**
* Remove an element from the given array at position (index). The element is removed at the specified position
* and all remaining elements are shifted to the left.

View File

@@ -16,8 +16,10 @@
package org.springframework.data.gemfire.util;
import com.gemstone.gemfire.cache.server.CacheServer;
import com.gemstone.gemfire.distributed.DistributedSystem;
import com.gemstone.gemfire.distributed.internal.InternalDistributedSystem;
import com.gemstone.gemfire.internal.DistributionLocator;
/**
* DistributedSystemUtils is an abstract utility class for working with the GemFire DistributedSystem.
@@ -28,6 +30,9 @@ import com.gemstone.gemfire.distributed.internal.InternalDistributedSystem;
*/
public abstract class DistributedSystemUtils {
public static final int DEFAULT_CACHE_SERVER_PORT = CacheServer.DEFAULT_PORT;
public static final int DEFAULT_LOCATOR_PORT = DistributionLocator.DEFAULT_LOCATOR_PORT;
@SuppressWarnings("unchecked")
public static <T extends DistributedSystem> T getDistributedSystem() {
return (T) InternalDistributedSystem.getAnyInstance();