SGF-535 - Allow both SpEL and property placeholder expressions to be used in the locators/servers attributes of the <gfe:pool> XML namespace element.

This commit is contained in:
John Blum
2016-09-28 13:25:20 -07:00
parent 2132e2d66b
commit b7bcabd9b8
24 changed files with 1234 additions and 1342 deletions

View File

@@ -19,6 +19,13 @@ package org.springframework.data.gemfire.client;
import java.net.InetSocketAddress;
import java.util.List;
import com.gemstone.gemfire.cache.client.ClientCache;
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.cache.query.QueryService;
import com.gemstone.gemfire.distributed.DistributedSystem;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeansException;
@@ -35,17 +42,10 @@ import org.springframework.data.gemfire.util.DistributedSystemUtils;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import com.gemstone.gemfire.cache.client.ClientCache;
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.cache.query.QueryService;
import com.gemstone.gemfire.distributed.DistributedSystem;
/**
* FactoryBean for easy declaration and configuration of a GemFire {@link Pool}. If a new {@link Pool} is created,
* its lifecycle is bound to that of this declaring factory.
*
*
* Note, if a {@link Pool} having the configured name already exists, then the existing {@link Pool} will be returned
* as is without any modifications and its lifecycle will be unaffected by this factory.
*
@@ -596,5 +596,4 @@ public class PoolFactoryBean implements FactoryBean<Pool>, InitializingBean, Dis
public void setThreadLocalConnections(boolean threadLocalConnections) {
this.threadLocalConnections = threadLocalConnections;
}
}

View File

@@ -16,11 +16,8 @@
package org.springframework.data.gemfire.config;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.regex.Pattern;
import org.springframework.beans.factory.BeanDefinitionStoreException;
import org.springframework.beans.factory.config.BeanDefinition;
@@ -42,21 +39,24 @@ import org.springframework.util.xml.DomUtils;
import org.w3c.dom.Element;
/**
* Parser for GFE &lt;pool;gt; bean definitions.
*
* Parser for &lt;gfe:pool&gt; bean definitions.
*
* @author Costin Leau
* @author David Turanski
* @author John Blum
* @see org.springframework.beans.factory.config.BeanDefinition
* @see org.springframework.beans.factory.support.BeanDefinitionBuilder
* @see org.springframework.beans.factory.support.BeanDefinitionRegistry
* @see org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser
* @see org.springframework.data.gemfire.client.PoolFactoryBean
*/
class PoolParser extends AbstractSingleBeanDefinitionParser {
static final AtomicBoolean INFRASTRUCTURE_REGISTRATION = new AtomicBoolean(false);
static final AtomicBoolean INFRASTRUCTURE_COMPONENTS_REGISTERED = new AtomicBoolean(false);
protected static final int DEFAULT_LOCATOR_PORT = GemfireUtils.DEFAULT_LOCATOR_PORT;
protected static final int DEFAULT_SERVER_PORT = GemfireUtils.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";
protected static final String LOCATOR_ELEMENT_NAME = "locator";
@@ -66,8 +66,8 @@ class PoolParser extends AbstractSingleBeanDefinitionParser {
protected static final String SERVERS_ATTRIBUTE_NAME = "servers";
/* (non-Javadoc) */
static void registerSupportingInfrastructureComponents(ParserContext parserContext) {
if (INFRASTRUCTURE_REGISTRATION.compareAndSet(false, true)) {
static void registerInfrastructureComponents(ParserContext parserContext) {
if (INFRASTRUCTURE_COMPONENTS_REGISTERED.compareAndSet(false, true)) {
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder
.genericBeanDefinition(ClientRegionAndPoolBeanFactoryPostProcessor.class)
.setRole(BeanDefinition.ROLE_INFRASTRUCTURE)
@@ -85,7 +85,7 @@ class PoolParser extends AbstractSingleBeanDefinitionParser {
@Override
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
registerSupportingInfrastructureComponents(parserContext);
registerInfrastructureComponents(parserContext);
ParsingUtils.setPropertyValue(element, builder, "free-connection-timeout");
ParsingUtils.setPropertyValue(element, builder, "idle-timeout");
@@ -124,13 +124,13 @@ class PoolParser extends AbstractSingleBeanDefinitionParser {
}
}
locators.addAll(parseLocators(element, getRegistry(parserContext)));
servers.addAll(parseServers(element, getRegistry(parserContext)));
boolean locatorsSet = parseLocators(element, getRegistry(parserContext));
boolean serversSet = parseServers(element, getRegistry(parserContext));
// NOTE if neither Locators nor Servers were specified, then setup a connection to a Server
// running on localhost, listening on the default CacheServer port, 40404
if (childElements.isEmpty() && !hasAttributes(element, LOCATORS_ATTRIBUTE_NAME, SERVERS_ATTRIBUTE_NAME)) {
servers.add(buildConnection(DEFAULT_HOST, String.valueOf(DEFAULT_SERVER_PORT), false));
// NOTE: if neither Locators nor Servers were configured, then setup a connection to a Server
// running on localhost, listening on the default CacheServer port 40404
if (childElements.isEmpty() && !(locatorsSet || serversSet)) {
servers.add(buildConnection(DEFAULT_HOST, String.valueOf(DEFAULT_SERVER_PORT), true));
}
if (!locators.isEmpty()) {
@@ -142,43 +142,15 @@ class PoolParser extends AbstractSingleBeanDefinitionParser {
}
}
/* (non-Javadoc) */
boolean hasAttributes(Element element, String... attributeNames) {
for (String attributeName : attributeNames) {
if (element.hasAttribute(attributeName)) {
return true;
}
}
return false;
}
/* (non-Javadoc) */
boolean isPropertyPlaceholder(String value) {
return PROPERTY_PLACEHOLDER_PATTERN.matcher(value).matches();
}
/* (non-Javadoc) */
BeanDefinitionRegistry getRegistry(ParserContext parserContext) {
return parserContext.getRegistry();
}
/* (non-Javadoc) */
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 connectionEndpointBuilder = BeanDefinitionBuilder.genericBeanDefinition(
ConnectionEndpoint.class);
BeanDefinitionBuilder connectionEndpointBuilder =
BeanDefinitionBuilder.genericBeanDefinition(ConnectionEndpoint.class);
connectionEndpointBuilder.addConstructorArgValue(defaultHost(host));
connectionEndpointBuilder.addConstructorArgValue(defaultPort(port, server));
@@ -186,6 +158,18 @@ class PoolParser extends AbstractSingleBeanDefinitionParser {
return connectionEndpointBuilder.getBeanDefinition();
}
/* (non-Javadoc) */
BeanDefinition buildConnections(String expression, boolean server) {
BeanDefinitionBuilder connectionEndpointListBuilder =
BeanDefinitionBuilder.genericBeanDefinition(ConnectionEndpointList.class);
connectionEndpointListBuilder.setFactoryMethod("parse");
connectionEndpointListBuilder.addConstructorArgValue(defaultPort(null, server));
connectionEndpointListBuilder.addConstructorArgValue(expression);
return connectionEndpointListBuilder.getBeanDefinition();
}
/* (non-Javadoc) */
String defaultHost(String host) {
return (StringUtils.hasText(host) ? host : DEFAULT_HOST);
@@ -197,51 +181,6 @@ class PoolParser extends AbstractSingleBeanDefinitionParser {
: String.valueOf(DEFAULT_LOCATOR_PORT)));
}
/* (non-Javadoc) */
List<BeanDefinition> parseConnections(String hostPortCommaDelimitedList, boolean server) {
List<BeanDefinition> connections = Collections.emptyList();
if (StringUtils.hasText(hostPortCommaDelimitedList)) {
String[] hostsPorts = hostPortCommaDelimitedList.split(",");
connections = new ArrayList<BeanDefinition>(hostsPorts.length);
for (String hostPort : hostsPorts) {
connections.add(parseConnection(hostPort, server));
}
}
return connections;
}
/* (non-Javadoc) */
BeanDefinition parseConnection(String hostPort, boolean server) {
String host = hostPort.trim();
String port = defaultPort(null, server);
int portIndex = host.indexOf('[');
if (portIndex > -1) {
port = parseDigits(host.substring(portIndex)).trim();
host = host.substring(0, portIndex).trim();
}
return buildConnection(host, port, server);
}
/* (non-Javadoc) */
String parseDigits(String value) {
StringBuilder digits = new StringBuilder();
for (char character : value.toCharArray()) {
if (Character.isDigit(character)) {
digits.append(character);
}
}
return digits.toString();
}
/* (non-Javadoc) */
BeanDefinition parseLocator(Element element) {
return buildConnection(element.getAttribute(HOST_ATTRIBUTE_NAME),
@@ -249,14 +188,12 @@ class PoolParser extends AbstractSingleBeanDefinitionParser {
}
/* (non-Javadoc) */
List<BeanDefinition> parseLocators(Element element, BeanDefinitionRegistry registry) {
List<BeanDefinition> beanDefinitions = Collections.emptyList();
boolean parseLocators(Element element, BeanDefinitionRegistry registry) {
String locatorsAttributeValue = element.getAttribute(LOCATORS_ATTRIBUTE_NAME);
if (isPropertyPlaceholder(locatorsAttributeValue)) {
BeanDefinitionBuilder addLocatorsMethodInvokingBeanBuilder = BeanDefinitionBuilder.genericBeanDefinition(
MethodInvokingBean.class);
if (StringUtils.hasText(locatorsAttributeValue)) {
BeanDefinitionBuilder addLocatorsMethodInvokingBeanBuilder =
BeanDefinitionBuilder.genericBeanDefinition(MethodInvokingBean.class);
addLocatorsMethodInvokingBeanBuilder.addPropertyReference("targetObject", resolveDereferencedId(element));
addLocatorsMethodInvokingBeanBuilder.addPropertyValue("targetMethod", "addLocators");
@@ -267,12 +204,11 @@ class PoolParser extends AbstractSingleBeanDefinitionParser {
addLocatorsMethodInvokingBeanBuilder.getBeanDefinition();
BeanDefinitionReaderUtils.registerWithGeneratedName(addLocatorsMethodInvokingBean, registry);
}
else {
beanDefinitions = parseConnections(locatorsAttributeValue, false);
return true;
}
return beanDefinitions;
return false;
}
/* (non-Javadoc) */
@@ -282,14 +218,12 @@ class PoolParser extends AbstractSingleBeanDefinitionParser {
}
/* (non-Javadoc) */
List<BeanDefinition> parseServers(Element element, BeanDefinitionRegistry registry) {
List<BeanDefinition> beanDefinitions = Collections.emptyList();
boolean parseServers(Element element, BeanDefinitionRegistry registry) {
String serversAttributeValue = element.getAttribute(SERVERS_ATTRIBUTE_NAME);
if (isPropertyPlaceholder(serversAttributeValue)) {
BeanDefinitionBuilder addServersMethodInvokingBeanBuilder = BeanDefinitionBuilder.genericBeanDefinition(
MethodInvokingBean.class);
if (StringUtils.hasText(serversAttributeValue)) {
BeanDefinitionBuilder addServersMethodInvokingBeanBuilder =
BeanDefinitionBuilder.genericBeanDefinition(MethodInvokingBean.class);
addServersMethodInvokingBeanBuilder.addPropertyReference("targetObject", resolveDereferencedId(element));
addServersMethodInvokingBeanBuilder.addPropertyValue("targetMethod", "addServers");
@@ -300,12 +234,11 @@ class PoolParser extends AbstractSingleBeanDefinitionParser {
addServersMethodInvokingBeanBuilder.getBeanDefinition();
BeanDefinitionReaderUtils.registerWithGeneratedName(addServersMethodInvokingBean, registry);
}
else {
beanDefinitions = parseConnections(serversAttributeValue, true);
return true;
}
return beanDefinitions;
return false;
}
/* (non-Javadoc) */
@@ -333,5 +266,4 @@ class PoolParser extends AbstractSingleBeanDefinitionParser {
return id;
}
}

View File

@@ -18,6 +18,7 @@ package org.springframework.data.gemfire.support;
import java.net.InetSocketAddress;
import org.springframework.data.gemfire.util.SpringUtils;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
@@ -126,12 +127,17 @@ public class ConnectionEndpoint implements Cloneable, Comparable<ConnectionEndpo
* @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));
Assert.isTrue(isValidPort(port), String.format("port number [%d] must be between 0 and 65535", port));
this.host = (StringUtils.hasText(host) ? host : DEFAULT_HOST);
this.host = SpringUtils.defaultIfEmpty(host, DEFAULT_HOST);
this.port = port;
}
/* (non-Javadoc) */
private boolean isValidPort(int port) {
return (port >= 0 && port <= 65535);
}
/**
* Gets the host in this ConnectionEndpoint.
*
@@ -208,5 +214,4 @@ public class ConnectionEndpoint implements Cloneable, Comparable<ConnectionEndpo
public String toString() {
return String.format("%1$s[%2$d]", getHost(), getPort());
}
}

View File

@@ -26,7 +26,6 @@ import java.util.List;
import org.springframework.data.gemfire.util.ArrayUtils;
import org.springframework.data.gemfire.util.CollectionUtils;
import org.springframework.data.gemfire.util.SpringUtils;
/**
* The ConnectionEndpointList class is an Iterable collection of ConnectionEndpoint objects.
@@ -34,6 +33,7 @@ import org.springframework.data.gemfire.util.SpringUtils;
* @author John Blum
* @see java.lang.Iterable
* @see java.net.InetSocketAddress
* @see java.util.AbstractList
* @see org.springframework.data.gemfire.support.ConnectionEndpoint
* @since 1.6.3
*/
@@ -97,7 +97,8 @@ public class ConnectionEndpointList extends AbstractList<ConnectionEndpoint> {
* @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);
List<ConnectionEndpoint> connectionEndpoints = new ArrayList<ConnectionEndpoint>(
ArrayUtils.length((Object) hostsPorts));
for (String hostPort : ArrayUtils.nullSafeArray(hostsPorts, String.class)) {
connectionEndpoints.add(ConnectionEndpoint.parse(hostPort, defaultPort));
@@ -139,7 +140,7 @@ public class ConnectionEndpointList extends AbstractList<ConnectionEndpoint> {
/* (non-Javadoc) */
@Override
public boolean add(ConnectionEndpoint connectionEndpoint) {
return (add(SpringUtils.toArray(connectionEndpoint)) == this);
return (add(ArrayUtils.asArray(connectionEndpoint)) == this);
}
/**
@@ -334,5 +335,4 @@ public class ConnectionEndpointList extends AbstractList<ConnectionEndpoint> {
public String toString() {
return connectionEndpoints.toString();
}
}

View File

@@ -14,6 +14,7 @@
package org.springframework.data.gemfire.util;
import java.lang.reflect.Array;
import java.util.Arrays;
/**
* The ArrayUtils class is a utility class for working with Object arrays.
@@ -24,6 +25,44 @@ import java.lang.reflect.Array;
*/
public abstract class ArrayUtils {
/**
* Returns the given varargs {@code element} as an array.
*
* @param <T> Class type of the elements.
* @param elements variable list of arguments to return as an array.
* @return an arry for the given varargs {@code elements}.
*/
public static <T> T[] asArray(T... elements) {
return elements;
}
/**
* Null-safe method to return the first element in the array or {@literal null}
* if the array is {@literal null} or empty.
*
* @param <T> Class type of the array elements.
* @param array the array from which to extract the first element.
* @return the first element in the array or {@literal null} if the array is null or empty.
* @see #getFirst(Object[], Object)
*/
public static <T> T getFirst(T... array) {
return getFirst(array, null);
}
/**
* Null-safe method to return the first element in the array or the {@code defaultValue}
* if the array is {@literal null} or empty.
*
* @param <T> Class type of the array elements.
* @param array the array from which to extract the first element.
* @param defaultValue value to return if the array is {@literal null} or empty.
* @return the first element in the array or {@code defaultValue} if the array is {@literal null} or empty.
* @see #getFirst(Object[], Object)
*/
public static <T> T getFirst(T[] array, T defaultValue) {
return (isEmpty(array) ? defaultValue : array[0]);
}
/**
* Insert an element into the given array at position (index). The element is inserted at the given position
* and all elements afterwards are moved to the right.
@@ -119,4 +158,17 @@ public abstract class ArrayUtils {
return newArray;
}
/**
* Sort the array of elements according to the elements natural ordering.
*
* @param <T> {@link Comparable} class type of the array elements.
* @param array array of elements to sort.
* @return the sorted array of elements.
* @see java.util.Arrays#sort(Object[])
*/
public static <T extends Comparable<T>> T[] sort(T[] array) {
Arrays.sort(array);
return array;
}
}

View File

@@ -16,6 +16,7 @@
package org.springframework.data.gemfire.util;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration;
@@ -26,12 +27,16 @@ import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
import org.springframework.util.Assert;
/**
* The CollectionUtils class is a utility class for working with Java Collections Framework and classes.
*
* @author John Blum
* @see java.util.Collection
* @see java.util.Collections
* @see java.util.Enumeration
* @see java.util.Iterator
* @see java.util.List
* @see java.util.Map
* @see java.util.Set
@@ -97,6 +102,7 @@ public abstract class CollectionUtils extends org.springframework.util.Collectio
* @return the given {@link Collection} if not null or return an empty {@link Collection}
* (implemented with {@link List}).
* @see java.util.Collections#emptyList()
* @see java.util.Collection
*/
public static <T> Collection<T> nullSafeCollection(Collection<T> collection) {
return (collection != null ? collection : Collections.<T>emptyList());
@@ -140,6 +146,7 @@ public abstract class CollectionUtils extends org.springframework.util.Collectio
* @param list {@link List} to evaluate.
* @return the given {@link List} if not null or an empty {@link List}.
* @see java.util.Collections#emptyList()
* @see java.util.List
*/
public static <T> List<T> nullSafeList(List<T> list) {
return (list != null ? list : Collections.<T>emptyList());
@@ -154,6 +161,7 @@ public abstract class CollectionUtils extends org.springframework.util.Collectio
* @param map {@link Map} to evaluate.
* @return the given {@link Map} if not null or an empty {@link Map}.
* @see java.util.Collections#emptyMap()
* @see java.util.Map
*/
public static <K, V> Map<K, V> nullSafeMap(Map<K, V> map) {
return (map != null ? map : Collections.<K, V>emptyMap());
@@ -167,8 +175,48 @@ public abstract class CollectionUtils extends org.springframework.util.Collectio
* @param set {@link Set} to evaluate.
* @return the given {@link Set} if not null or an empty {@link Set}.
* @see java.util.Collections#emptySet()
* @see java.util.Set
*/
public static <T> Set<T> nullSafeSet(Set<T> set) {
return (set != null ? set : Collections.<T>emptySet());
}
/**
* Sors the elements of the given {@link List} by their natural, {@link Comparable} ordering.
*
* @param <T> {@link Comparable} class type of the collection elements.
* @param list {@link List} of elements to sort.
* @return the {@link List} sorted.
* @see java.util.Collections#sort(List)
* @see java.util.List
*/
public static <T extends Comparable<T>> List<T> sort(List<T> list) {
Collections.sort(list);
return list;
}
/**
* Returns a sub-list of elements from the given {@link List} based on the provided {@code indices}.
*
* @param <T> Class type of the elements in the list.
* @param source {@link List} from which the elements of the sub-list is constructed.
* @param indices array of indexes in the {@code source} {@link List} to the elements
* used to construct the sub-list.
* @return a sub-list of elements from the given {@link List} based on the provided {@code indices}.
* @throws IndexOutOfBoundsException if the array of indexes contains an index that is not within
* the bounds of the list.
* @throws NullPointerException if either the list or indexes are null.
* @see java.util.List
*/
public static <T> List<T> subList(List<T> source, int... indices) {
Assert.notNull(source, "List must not be null");
List<T> result = new ArrayList<T>(indices.length);
for (int index : indices) {
result.add(source.get(index));
}
return result;
}
}

View File

@@ -17,10 +17,6 @@
package org.springframework.data.gemfire.util;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.util.StringUtils;
@@ -31,6 +27,7 @@ import org.springframework.util.StringUtils;
* @since 1.8.0
*/
@SuppressWarnings("unused")
// TODO rename this utiltiy class using a more intuitive, meaningful name
public abstract class SpringUtils {
/* (non-Javadoc) */
@@ -47,22 +44,4 @@ public abstract class SpringUtils {
public static String dereferenceBean(String beanName) {
return String.format("%1$s%2$s", BeanFactory.FACTORY_BEAN_PREFIX, beanName);
}
/* (non-Javadoc) */
public static <T> T[] toArray(T... array) {
return array;
}
/* (non-Javadoc) */
public static <T extends Comparable<T>> T[] sort(T[] array) {
Arrays.sort(array);
return array;
}
/* (non-Javadoc) */
public static <T extends Comparable<T>> List<T> sort(List<T> list) {
Collections.sort(list);
return list;
}
}