SGF-416 - Avoid eager creation of a GemFire DistributedSystem in the PoolFactoryBean by creating a ClientCache first.

This commit is contained in:
John Blum
2016-03-09 18:43:06 -08:00
parent b052f0ac8d
commit 127b62e722
75 changed files with 5797 additions and 1934 deletions

View File

@@ -18,17 +18,11 @@ package org.springframework.data.gemfire;
import java.util.concurrent.ConcurrentMap;
import org.springframework.data.gemfire.util.DistributedSystemUtils;
import org.springframework.data.gemfire.util.CacheUtils;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
import com.gemstone.gemfire.cache.Cache;
import com.gemstone.gemfire.cache.CacheClosedException;
import com.gemstone.gemfire.cache.CacheFactory;
import com.gemstone.gemfire.cache.Region;
import com.gemstone.gemfire.cache.client.ClientCache;
import com.gemstone.gemfire.cache.client.ClientCacheFactory;
import com.gemstone.gemfire.distributed.DistributedSystem;
/**
* GemfireUtils is an abstract utility class encapsulating common functionality to access features and capabilities
@@ -36,72 +30,22 @@ import com.gemstone.gemfire.distributed.DistributedSystem;
*
* @author John Blum
* @see org.springframework.data.gemfire.util.DistributedSystemUtils
* @see com.gemstone.gemfire.cache.Cache
* @see com.gemstone.gemfire.cache.CacheFactory
* @see com.gemstone.gemfire.cache.Region
* @see com.gemstone.gemfire.cache.client.ClientCache
* @see com.gemstone.gemfire.cache.client.ClientCacheFactory
* @see com.gemstone.gemfire.distributed.DistributedSystem
* @since 1.3.3
*/
@SuppressWarnings("unused")
public abstract class GemfireUtils extends DistributedSystemUtils {
public abstract class GemfireUtils extends CacheUtils {
public final static String GEMFIRE_VERSION = CacheFactory.getVersion();
public static boolean isDurable(ClientCache clientCache) {
DistributedSystem distributedSystem = getDistributedSystem(clientCache);
// NOTE technically the following code snippet would be more useful/valuable but is not "testable"!
//((InternalDistributedSystem) distributedSystem).getConfig().getDurableClientId();
return (isConnected(distributedSystem) && StringUtils.hasText(distributedSystem.getProperties()
.getProperty(DURABLE_CLIENT_ID_PROPERTY_NAME, null)));
}
public static boolean closeCache() {
try {
CacheFactory.getAnyInstance().close();
return true;
}
catch (Exception ignore) {
return false;
}
}
public static boolean closeClientCache() {
try {
ClientCacheFactory.getAnyInstance().close();
return true;
}
catch (Exception ignore) {
return false;
}
}
public static Cache getCache() {
try {
return CacheFactory.getAnyInstance();
}
catch (CacheClosedException ignore) {
return null;
}
}
public static ClientCache getClientCache() {
try {
return ClientCacheFactory.getAnyInstance();
}
catch (CacheClosedException ignore) {
return null;
}
}
/* (non-Javadoc) */
public static boolean isGemfireVersionGreaterThanEqualTo(double expectedVersion) {
double actualVersion = Double.parseDouble(GEMFIRE_VERSION.substring(0, 3));
return actualVersion >= expectedVersion;
}
/* (non-Javadoc) */
public static boolean isGemfireVersion65OrAbove() {
// expected 'major.minor'
try {
@@ -114,6 +58,7 @@ public abstract class GemfireUtils extends DistributedSystemUtils {
}
}
/* (non-Javadoc) */
public static boolean isGemfireVersion7OrAbove() {
try {
return isGemfireVersionGreaterThanEqualTo(7.0);
@@ -125,6 +70,7 @@ public abstract class GemfireUtils extends DistributedSystemUtils {
}
}
/* (non-Javadoc) */
public static boolean isGemfireVersion8OrAbove() {
try {
return isGemfireVersionGreaterThanEqualTo(8.0);

View File

@@ -16,16 +16,25 @@
package org.springframework.data.gemfire.client;
import java.net.InetSocketAddress;
import java.util.Map;
import java.util.Properties;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.data.gemfire.CacheFactoryBean;
import org.springframework.data.gemfire.GemfireUtils;
import org.springframework.data.gemfire.client.support.DefaultableDelegatingPoolAdapter;
import org.springframework.data.gemfire.client.support.DelegatingPoolAdapter;
import org.springframework.data.gemfire.config.GemfireConstants;
import org.springframework.data.gemfire.support.ConnectionEndpoint;
import org.springframework.data.gemfire.support.ConnectionEndpointList;
import org.springframework.data.gemfire.util.SpringUtils;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.springframework.util.ObjectUtils;
import com.gemstone.gemfire.cache.CacheClosedException;
import com.gemstone.gemfire.cache.GemFireCache;
@@ -45,28 +54,54 @@ import com.gemstone.gemfire.pdx.PdxSerializer;
* @see org.springframework.context.ApplicationListener
* @see org.springframework.context.event.ContextRefreshedEvent
* @see org.springframework.data.gemfire.CacheFactoryBean
* @see org.springframework.data.gemfire.support.ConnectionEndpoint
* @see org.springframework.data.gemfire.support.ConnectionEndpointList
* @see com.gemstone.gemfire.cache.GemFireCache
* @see com.gemstone.gemfire.cache.client.ClientCache
* @see com.gemstone.gemfire.cache.client.ClientCacheFactory
* @see com.gemstone.gemfire.cache.client.Pool
* @see com.gemstone.gemfire.cache.client.PoolManager
* @see com.gemstone.gemfire.distributed.DistributedSystem
* @see com.gemstone.gemfire.pdx.PdxSerializer
*/
@SuppressWarnings("unused")
public class ClientCacheFactoryBean extends CacheFactoryBean implements ApplicationListener<ContextRefreshedEvent> {
protected Boolean keepAlive = false;
protected Boolean readyForEvents;
private Boolean keepAlive = false;
private Boolean multiUserAuthentication;
private Boolean prSingleHopEnabled;
private Boolean readyForEvents;
private Boolean subscriptionEnabled;
private Boolean threadLocalConnections;
protected Integer durableClientTimeout;
private ConnectionEndpointList locators = new ConnectionEndpointList();
private ConnectionEndpointList servers = new ConnectionEndpointList();
private Integer durableClientTimeout;
private Integer freeConnectionTimeout;
private Integer loadConditioningInterval;
private Integer maxConnections;
private Integer minConnections;
private Integer readTimeout;
private Integer retryAttempts;
private Integer socketBufferSize;
private Integer statisticsInterval;
private Integer subscriptionAckInterval;
private Integer subscriptionMessageTrackingTimeout;
private Integer subscriptionRedundancy;
private Long idleTimeout;
private Long pingInterval;
private Pool pool;
protected String durableClientId;
protected String poolName;
private String durableClientId;
private String poolName;
private String serverGroup;
private String serverName;
@Override
protected void postProcessPropertiesBeforeInitialization(Properties gemfireProperties) {
protected void postProcessBeforeCacheInitialization(Properties gemfireProperties) {
}
/**
@@ -82,7 +117,8 @@ public class ClientCacheFactoryBean extends CacheFactoryBean implements Applicat
@Override
@SuppressWarnings("unchecked")
protected <T extends GemFireCache> T fetchCache() {
return (T) ClientCacheFactory.getAnyInstance();
ClientCache cache = getCache();
return (T) (cache != null ? cache : ClientCacheFactory.getAnyInstance());
}
/**
@@ -137,83 +173,132 @@ public class ClientCacheFactoryBean extends CacheFactoryBean implements Applicat
*/
@Override
protected Object prepareFactory(final Object factory) {
if (isPdxOptionsSpecified()) {
ClientCacheFactory clientCacheFactory = (ClientCacheFactory) factory;
return initializePool(initializePdx((ClientCacheFactory) factory));
}
if (pdxSerializer != null) {
Assert.isAssignable(PdxSerializer.class, pdxSerializer.getClass(), "Invalid pdx serializer used");
clientCacheFactory.setPdxSerializer((PdxSerializer) pdxSerializer);
/**
* Initialize the PDX settings on the {@link ClientCacheFactory}.
*
* @param clientCacheFactory the GemFire {@link ClientCacheFactory} used to configure and create
* a GemFire {@link ClientCache}.
* @see com.gemstone.gemfire.cache.client.ClientCacheFactory
*/
ClientCacheFactory initializePdx(ClientCacheFactory clientCacheFactory) {
if (isPdxOptionsSpecified()) {
if (getPdxSerializer() != null) {
Assert.isInstanceOf(PdxSerializer.class, getPdxSerializer(),
String.format("[%1$s] of type [%2$s] is not a PdxSerializer;", getPdxSerializer(),
ObjectUtils.nullSafeClassName(getPdxSerializer())));
clientCacheFactory.setPdxSerializer((PdxSerializer) getPdxSerializer());
}
if (pdxDiskStoreName != null) {
clientCacheFactory.setPdxDiskStore(pdxDiskStoreName);
if (getPdxDiskStoreName() != null) {
clientCacheFactory.setPdxDiskStore(getPdxDiskStoreName());
}
if (pdxIgnoreUnreadFields != null) {
clientCacheFactory.setPdxIgnoreUnreadFields(pdxIgnoreUnreadFields);
if (getPdxIgnoreUnreadFields() != null) {
clientCacheFactory.setPdxIgnoreUnreadFields(getPdxIgnoreUnreadFields());
}
if (pdxPersistent != null) {
clientCacheFactory.setPdxPersistent(pdxPersistent);
if (getPdxPersistent() != null) {
clientCacheFactory.setPdxPersistent(getPdxPersistent());
}
if (pdxReadSerialized != null) {
clientCacheFactory.setPdxReadSerialized(pdxReadSerialized);
if (getPdxReadSerialized() != null) {
clientCacheFactory.setPdxReadSerialized(getPdxReadSerialized());
}
}
return factory;
}
/**
* Creates a new GemFire cache instance using the provided factory.
*
* @param <T> parameterized Class type extension of GemFireCache.
* @param factory the appropriate GemFire factory used to create a cache instance.
* @return an instance of the GemFire cache.
* @see com.gemstone.gemfire.cache.GemFireCache
* @see com.gemstone.gemfire.cache.client.ClientCacheFactory#create()
*/
@Override
@SuppressWarnings("unchecked")
protected <T extends GemFireCache> T createCache(Object factory) {
return (T) initializePool((ClientCacheFactory) factory).create();
}
/**
* Initialize the Pool settings on the ClientCacheFactory.
*
* @param clientCacheFactory the GemFire ClientCacheFactory used to configure and create a GemFire ClientCache.
* @see com.gemstone.gemfire.cache.client.ClientCacheFactory
*/
private ClientCacheFactory initializePool(ClientCacheFactory clientCacheFactory) {
resolvePool(pool);
return clientCacheFactory;
}
/**
* Resolves the appropriate GemFire Pool from configuration used to configure the ClientCache.
* Initialize the {@link Pool} settings on the {@link ClientCacheFactory} with a given {@link Pool} instance
* or named {@link Pool}.
*
* @param pool the preferred GemFire Pool to use in the configuration of the ClientCache.
* @return the resolved GemFire Pool.
* @param clientCacheFactory the GemFire {@link ClientCacheFactory} used to configure and create
* a GemFire {@link ClientCache}.
* @see com.gemstone.gemfire.cache.client.ClientCacheFactory
* @see com.gemstone.gemfire.cache.client.Pool
* @see com.gemstone.gemfire.cache.client.PoolManager#find(String)
*/
private Pool resolvePool(final Pool pool) {
Pool localPool = pool;
ClientCacheFactory initializePool(ClientCacheFactory clientCacheFactory) {
DefaultableDelegatingPoolAdapter pool = DefaultableDelegatingPoolAdapter.from(
DelegatingPoolAdapter.from(resolvePool())).preferDefault();
clientCacheFactory.setPoolFreeConnectionTimeout(pool.getFreeConnectionTimeout(getFreeConnectionTimeout()));
clientCacheFactory.setPoolIdleTimeout(pool.getIdleTimeout(getIdleTimeout()));
clientCacheFactory.setPoolLoadConditioningInterval(pool.getLoadConditioningInterval(getLoadConditioningInterval()));
clientCacheFactory.setPoolMaxConnections(pool.getMaxConnections(getMaxConnections()));
clientCacheFactory.setPoolMinConnections(pool.getMinConnections(getMinConnections()));
clientCacheFactory.setPoolMultiuserAuthentication(pool.getMultiuserAuthentication(getMultiUserAuthentication()));
clientCacheFactory.setPoolPRSingleHopEnabled(pool.getPRSingleHopEnabled(getPrSingleHopEnabled()));
clientCacheFactory.setPoolPingInterval(pool.getPingInterval(getPingInterval()));
clientCacheFactory.setPoolReadTimeout(pool.getReadTimeout(getReadTimeout()));
clientCacheFactory.setPoolRetryAttempts(pool.getRetryAttempts(getRetryAttempts()));
clientCacheFactory.setPoolServerGroup(pool.getServerGroup(getServerGroup()));
clientCacheFactory.setPoolSocketBufferSize(pool.getSocketBufferSize(getSocketBufferSize()));
clientCacheFactory.setPoolStatisticInterval(pool.getStatisticInterval(getStatisticsInterval()));
clientCacheFactory.setPoolSubscriptionAckInterval(pool.getSubscriptionAckInterval(getSubscriptionAckInterval()));
clientCacheFactory.setPoolSubscriptionEnabled(pool.getSubscriptionEnabled(getSubscriptionEnabled()));
clientCacheFactory.setPoolSubscriptionMessageTrackingTimeout(pool.getSubscriptionMessageTrackingTimeout(getSubscriptionMessageTrackingTimeout()));
clientCacheFactory.setPoolSubscriptionRedundancy(pool.getSubscriptionRedundancy(getSubscriptionRedundancy()));
clientCacheFactory.setPoolThreadLocalConnections(pool.getThreadLocalConnections(getThreadLocalConnections()));
boolean noServers = getServers().isEmpty();
boolean hasServers = !noServers;
boolean noLocators = getLocators().isEmpty();
boolean hasLocators = !noLocators;
if (hasServers || noLocators) {
Iterable<InetSocketAddress> servers = pool.getServers(getServers().toInetSocketAddresses());
for (InetSocketAddress server : servers) {
clientCacheFactory.addPoolServer(server.getHostName(), server.getPort());
noServers = false;
}
}
if (hasLocators || noServers) {
Iterable<InetSocketAddress> locators = pool.getLocators(getLocators().toInetSocketAddresses());
for (InetSocketAddress locator : locators) {
clientCacheFactory.addPoolLocator(locator.getHostName(), locator.getPort());
}
}
return clientCacheFactory;
}
/**
* Resolves the appropriate GemFire {@link Pool} from Spring configuration that will be used to configure
* the GemFire {@link ClientCache}.
*
* @return the resolved GemFire {@link Pool}.
* @see com.gemstone.gemfire.cache.client.PoolManager#find(String)
* @see com.gemstone.gemfire.cache.client.Pool
*/
Pool resolvePool() {
Pool localPool = getPool();
if (localPool == null) {
localPool = PoolManager.find(poolName);
String poolName = SpringUtils.defaultIfNull(getPoolName(), GemfireConstants.DEFAULT_GEMFIRE_POOL_NAME);
localPool = findPool(poolName);
if (localPool == null) {
if (StringUtils.hasText(poolName) && getBeanFactory().isTypeMatch(poolName, Pool.class)) {
localPool = getBeanFactory().getBean(poolName, Pool.class);
}
else {
BeanFactory beanFactory = getBeanFactory();
if (beanFactory instanceof ListableBeanFactory) {
try {
localPool = getBeanFactory().getBean(Pool.class);
this.poolName = localPool.getName();
Map<String, PoolFactoryBean> poolFactoryBeanMap =
((ListableBeanFactory) beanFactory).getBeansOfType(PoolFactoryBean.class, false, false);
String dereferencedPoolName = SpringUtils.dereferenceBean(poolName);
if (poolFactoryBeanMap.containsKey(dereferencedPoolName)) {
return poolFactoryBeanMap.get(dereferencedPoolName).getPool();
}
}
catch (BeansException ignore) {
log.info(String.format("no bean of type '%1$s' having name '%2$s' was found",
Pool.class.getName(), (StringUtils.hasText(poolName) ? poolName
: GemfireConstants.DEFAULT_GEMFIRE_POOL_NAME)));
catch (BeansException e) {
log.info(String.format("unable to resolve bean of type [%1$s] with name [%2$s]",
PoolFactoryBean.class.getName(), poolName));
}
}
}
@@ -222,6 +307,34 @@ public class ClientCacheFactoryBean extends CacheFactoryBean implements Applicat
return localPool;
}
/**
* Attempts to find a GemFire {@link Pool} with the given name.
*
* @param name a String indicating the name of the GemFire {@link Pool} to find.
* @return a {@link Pool} instance with the given name registered in GemFire or <code>null</code> if no {@link Pool}
* with name exists.
* @see com.gemstone.gemfire.cache.client.PoolManager#find(String)
* @see com.gemstone.gemfire.cache.client.Pool
*/
Pool findPool(String name) {
return PoolManager.find(name);
}
/**
* Creates a new GemFire cache instance using the provided factory.
*
* @param <T> parameterized Class type extension of {@link GemFireCache}.
* @param factory the appropriate GemFire factory used to create a cache instance.
* @return an instance of the GemFire cache.
* @see com.gemstone.gemfire.cache.client.ClientCacheFactory#create()
* @see com.gemstone.gemfire.cache.GemFireCache
*/
@Override
@SuppressWarnings("unchecked")
protected <T extends GemFireCache> T createCache(Object factory) {
return (T) ((ClientCacheFactory) factory).create();
}
/**
* Inform the GemFire cluster that this client cache is ready to receive events iff the client is non-durable.
*
@@ -240,23 +353,42 @@ public class ClientCacheFactoryBean extends CacheFactoryBean implements Applicat
// thrown if clientCache.readyForEvents() is called on a non-durable client
}
catch (CacheClosedException ignore) {
// cache is closed or was shutdown so ready-for-events is moot
}
}
}
/* (non-Javadoc) */
@Override
protected void close(final GemFireCache cache) {
protected void close(GemFireCache cache) {
((ClientCache) cache).close(isKeepAlive());
}
/* (non-Javadoc) */
@Override
public Class<? extends GemFireCache> getObjectType() {
ClientCache cache = getCache();
return (cache != null ? cache.getClass() : ClientCache.class);
}
@Override
public final void setEnableAutoReconnect(final Boolean enableAutoReconnect) {
throw new UnsupportedOperationException("Auto-reconnect is not supported on ClientCache.");
/* (non-Javadoc) */
public void addLocators(ConnectionEndpoint... locators) {
this.locators.add(locators);
}
/* (non-Javadoc) */
public void addLocators(Iterable<ConnectionEndpoint> locators) {
this.locators.add(locators);
}
/* (non-Javadoc) */
public void addServers(ConnectionEndpoint... servers) {
this.servers.add(servers);
}
/* (non-Javadoc) */
public void addServers(Iterable<ConnectionEndpoint> servers) {
this.servers.add(servers);
}
/**
@@ -264,7 +396,7 @@ public class ClientCacheFactoryBean extends CacheFactoryBean implements Applicat
*
* @param durableClientId a String value indicating the durable client id.
*/
public void setDurableClientId(final String durableClientId) {
public void setDurableClientId(String durableClientId) {
this.durableClientId = durableClientId;
}
@@ -285,7 +417,7 @@ public class ClientCacheFactoryBean extends CacheFactoryBean implements Applicat
* @param durableClientTimeout an Integer value indicating the timeout in seconds for the server to keep
* the durable client's queue around.
*/
public void setDurableClientTimeout(final Integer durableClientTimeout) {
public void setDurableClientTimeout(Integer durableClientTimeout) {
this.durableClientTimeout = durableClientTimeout;
}
@@ -300,11 +432,38 @@ public class ClientCacheFactoryBean extends CacheFactoryBean implements Applicat
return durableClientTimeout;
}
/* (non-Javadoc) */
@Override
public final void setEnableAutoReconnect(final Boolean enableAutoReconnect) {
throw new UnsupportedOperationException("Auto-reconnect does not apply to clients.");
}
/* (non-Javadoc) */
@Override
public final Boolean getEnableAutoReconnect() {
return Boolean.FALSE;
}
/* (non-Javadoc) */
public void setFreeConnectionTimeout(Integer freeConnectionTimeout) {
this.freeConnectionTimeout = freeConnectionTimeout;
}
/* (non-Javadoc) */
public Integer getFreeConnectionTimeout() {
return freeConnectionTimeout;
}
/* (non-Javadoc) */
public void setIdleTimeout(Long idleTimeout) {
this.idleTimeout = idleTimeout;
}
/* (non-Javadoc) */
public Long getIdleTimeout() {
return idleTimeout;
}
/**
* Sets whether the server(s) should keep the durable client's queue alive for the duration of the timeout
* when the client voluntarily disconnects.
@@ -335,35 +494,132 @@ public class ClientCacheFactoryBean extends CacheFactoryBean implements Applicat
return Boolean.TRUE.equals(getKeepAlive());
}
/* (non-Javadoc) */
public void setLoadConditioningInterval(Integer loadConditioningInterval) {
this.loadConditioningInterval = loadConditioningInterval;
}
/* (non-Javadoc) */
public Integer getLoadConditioningInterval() {
return loadConditioningInterval;
}
/* (non-Javadoc) */
public void setLocators(ConnectionEndpoint[] locators) {
setLocators(ConnectionEndpointList.from(locators));
}
/* (non-Javadoc) */
public void setLocators(Iterable<ConnectionEndpoint> locators) {
getLocators().clear();
addLocators(locators);
}
/* (non-Javadoc) */
protected ConnectionEndpointList getLocators() {
return locators;
}
/* (non-Javadoc) */
public void setMaxConnections(Integer maxConnections) {
this.maxConnections = maxConnections;
}
/* (non-Javadoc) */
public Integer getMaxConnections() {
return maxConnections;
}
/* (non-Javadoc) */
public void setMinConnections(Integer minConnections) {
this.minConnections = minConnections;
}
/* (non-Javadoc) */
public Integer getMinConnections() {
return minConnections;
}
/* (non-Javadoc) */
public void setMultiUserAuthentication(Boolean multiUserAuthentication) {
this.multiUserAuthentication = multiUserAuthentication;
}
/* (non-Javadoc) */
public Boolean getMultiUserAuthentication() {
return multiUserAuthentication;
}
/**
* Sets the pool used by this client.
* Sets the {@link Pool} used by this cache client to obtain connections to the GemFire cluster.
*
* @param pool the GemFire pool used by the Client Cache to obtain connections to the GemFire cluster.
* @param pool the GemFire {@link Pool} used by this {@link ClientCache} to obtain connections
* to the GemFire cluster.
* @throws IllegalArgumentException if the {@link Pool} is null.
*/
public void setPool(Pool pool) {
Assert.notNull(pool, "GemFire Pool must not be null");
this.pool = pool;
}
/**
* Sets the pool name used by this client.
* Gets the {@link Pool} used by this cache client to obtain connections to the GemFire cluster.
*
* @param poolName set the name of the GemFire Pool used by the GemFire Client Cache.
* @return the GemFire {@link Pool} used by this {@link ClientCache} to obtain connections
* to the GemFire cluster.
*/
public Pool getPool() {
return pool;
}
/**
* Sets the name of the {@link Pool} used by this cache client to obtain connections to the GemFire cluster.
*
* @param poolName set the name of the GemFire {@link Pool} used by this GemFire {@link ClientCache}.
* @throws IllegalArgumentException if the {@link Pool} name is unspecified.
*/
public void setPoolName(String poolName) {
Assert.hasText(poolName, "Pool 'name' is required");
this.poolName = poolName;
}
/**
* Gets the pool name used by this client.
* Gets the name of the GemFire {@link Pool} used by this GemFire cache client.
*
* @return the name of the GemFire Pool used by the GemFire Client Cache.
* @return the name of the GemFire {@link Pool} used by this GemFire cache client.
*/
public String getPoolName() {
return poolName;
}
/* (non-Javadoc) */
public void setPingInterval(Long pingInterval) {
this.pingInterval = pingInterval;
}
/* (non-Javadoc) */
public Long getPingInterval() {
return pingInterval;
}
/* (non-Javadoc) */
public void setPrSingleHopEnabled(Boolean prSingleHopEnabled) {
this.prSingleHopEnabled = prSingleHopEnabled;
}
/* (non-Javadoc) */
public Boolean getPrSingleHopEnabled() {
return prSingleHopEnabled;
}
/* (non-Javadoc) */
public void setReadTimeout(Integer readTimeout) {
this.readTimeout = readTimeout;
}
/* (non-Javadoc) */
public Integer getReadTimeout() {
return readTimeout;
}
/**
* Sets the readyForEvents property to indicate whether the cache client should notify the server
* that it is ready to receive updates.
@@ -385,7 +641,14 @@ public class ClientCacheFactoryBean extends CacheFactoryBean implements Applicat
return readyForEvents;
}
/* (non-Javadoc) */
/**
* Determines whether this GemFire cache client is ready for events. If 'readyForEvents' was explicitly set,
* then it takes precedence over all other considerations (e.g. durability).
*
* @return a boolean value indicating whether this GemFire cache client is ready for events.
* @see org.springframework.data.gemfire.GemfireUtils#isDurable(ClientCache)
* @see #getReadyForEvents()
*/
public boolean isReadyForEvents() {
Boolean readyForEvents = getReadyForEvents();
@@ -402,11 +665,119 @@ public class ClientCacheFactoryBean extends CacheFactoryBean implements Applicat
}
}
@Override
public final void setUseClusterConfiguration(Boolean useClusterConfiguration) {
throw new UnsupportedOperationException("Shared, cluster configuration is not applicable to clients.");
/* (non-Javadoc) */
public void setRetryAttempts(Integer retryAttempts) {
this.retryAttempts = retryAttempts;
}
/* (non-Javadoc) */
public Integer getRetryAttempts() {
return retryAttempts;
}
/* (non-Javadoc) */
public void setServerGroup(String serverGroup) {
this.serverGroup = serverGroup;
}
/* (non-Javadoc) */
public String getServerGroup() {
return serverGroup;
}
/* (non-Javadoc) */
public void setServers(ConnectionEndpoint[] servers) {
setServers(ConnectionEndpointList.from(servers));
}
/* (non-Javadoc) */
public void setServers(Iterable<ConnectionEndpoint> servers) {
getServers().clear();
addServers(servers);
}
/* (non-Javadoc) */
protected ConnectionEndpointList getServers() {
return servers;
}
/* (non-Javadoc) */
public void setSocketBufferSize(Integer socketBufferSize) {
this.socketBufferSize = socketBufferSize;
}
/* (non-Javadoc) */
public Integer getSocketBufferSize() {
return socketBufferSize;
}
/* (non-Javadoc) */
public void setStatisticsInterval(Integer statisticsInterval) {
this.statisticsInterval = statisticsInterval;
}
/* (non-Javadoc) */
public Integer getStatisticsInterval() {
return statisticsInterval;
}
/* (non-Javadoc) */
public void setSubscriptionAckInterval(Integer subscriptionAckInterval) {
this.subscriptionAckInterval = subscriptionAckInterval;
}
/* (non-Javadoc) */
public Integer getSubscriptionAckInterval() {
return subscriptionAckInterval;
}
/* (non-Javadoc) */
public void setSubscriptionEnabled(Boolean subscriptionEnabled) {
this.subscriptionEnabled = subscriptionEnabled;
}
/* (non-Javadoc) */
public Boolean getSubscriptionEnabled() {
return subscriptionEnabled;
}
/* (non-Javadoc) */
public void setSubscriptionMessageTrackingTimeout(Integer subscriptionMessageTrackingTimeout) {
this.subscriptionMessageTrackingTimeout = subscriptionMessageTrackingTimeout;
}
/* (non-Javadoc) */
public Integer getSubscriptionMessageTrackingTimeout() {
return subscriptionMessageTrackingTimeout;
}
/* (non-Javadoc) */
public void setSubscriptionRedundancy(Integer subscriptionRedundancy) {
this.subscriptionRedundancy = subscriptionRedundancy;
}
/* (non-Javadoc) */
public Integer getSubscriptionRedundancy() {
return subscriptionRedundancy;
}
/* (non-Javadoc) */
public void setThreadLocalConnections(Boolean threadLocalConnections) {
this.threadLocalConnections = threadLocalConnections;
}
/* (non-Javadoc) */
public Boolean getThreadLocalConnections() {
return threadLocalConnections;
}
/* (non-Javadoc) */
@Override
public final void setUseClusterConfiguration(Boolean useClusterConfiguration) {
throw new UnsupportedOperationException("Shared, cluster-based configuration is not applicable for clients.");
}
/* (non-Javadoc) */
@Override
public final Boolean getUseClusterConfiguration() {
return Boolean.FALSE;

View File

@@ -24,7 +24,9 @@ import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.core.io.Resource;
import org.springframework.data.gemfire.DataPolicyConverter;
import org.springframework.data.gemfire.GemfireUtils;
import org.springframework.data.gemfire.RegionLookupFactoryBean;
import org.springframework.data.gemfire.config.GemfireConstants;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
@@ -41,7 +43,6 @@ import com.gemstone.gemfire.cache.client.ClientCache;
import com.gemstone.gemfire.cache.client.ClientRegionFactory;
import com.gemstone.gemfire.cache.client.ClientRegionShortcut;
import com.gemstone.gemfire.cache.client.Pool;
import com.gemstone.gemfire.internal.cache.GemFireCacheImpl;
/**
* Client extension for GemFire Regions.
@@ -53,14 +54,20 @@ import com.gemstone.gemfire.internal.cache.GemFireCacheImpl;
* @see org.springframework.beans.factory.BeanFactoryAware
* @see org.springframework.beans.factory.DisposableBean
* @see org.springframework.data.gemfire.RegionLookupFactoryBean
* @see com.gemstone.gemfire.cache.CacheListener
* @see com.gemstone.gemfire.cache.CacheLoader
* @see com.gemstone.gemfire.cache.CacheWriter
* @see com.gemstone.gemfire.cache.DataPolicy
* @see com.gemstone.gemfire.cache.GemFireCache
* @see com.gemstone.gemfire.cache.Region
* @see com.gemstone.gemfire.cache.RegionAttributes
* @see com.gemstone.gemfire.cache.client.ClientCache
* @see com.gemstone.gemfire.cache.client.ClientRegionFactory
* @see com.gemstone.gemfire.cache.client.ClientRegionShortcut
*/
@SuppressWarnings("unused")
public class ClientRegionFactoryBean<K, V> extends RegionLookupFactoryBean<K, V> implements BeanFactoryAware,
DisposableBean {
public class ClientRegionFactoryBean<K, V> extends RegionLookupFactoryBean<K, V>
implements BeanFactoryAware, DisposableBean {
private static final Log log = LogFactory.getLog(ClientRegionFactoryBean.class);
@@ -99,17 +106,11 @@ public class ClientRegionFactoryBean<K, V> extends RegionLookupFactoryBean<K, V>
@Override
@SuppressWarnings("all")
protected Region<K, V> lookupFallback(GemFireCache cache, String regionName) throws Exception {
Assert.isTrue(cache instanceof ClientCache, String.format("Unable to create Regions from %1$s!", cache));
Assert.isTrue(GemfireUtils.isClient(cache), "A ClientCache is required to create a client Region");
if (cache instanceof GemFireCacheImpl) {
Assert.isTrue(((GemFireCacheImpl) cache).isClient(), "A ClientCache instance is required!");
}
ClientRegionFactory<K, V> clientRegionFactory = ((ClientCache) cache).createClientRegionFactory(
resolveClientRegionShortcut());
ClientCache clientCache = (ClientCache) cache;
ClientRegionFactory<K, V> clientRegionFactory = clientCache.createClientRegionFactory(resolveClientRegionShortcut());
// map Region attributes onto the ClientRegionFactory...
if (attributes != null) {
clientRegionFactory.setCloningEnabled(attributes.getCloningEnabled());
clientRegionFactory.setCompressor(attributes.getCompressor());
@@ -132,19 +133,14 @@ public class ClientRegionFactoryBean<K, V> extends RegionLookupFactoryBean<K, V>
clientRegionFactory.setValueConstraint(attributes.getValueConstraint());
}
addCacheListeners(clientRegionFactory);
String poolName = resolvePoolName();
if (StringUtils.hasText(poolName)) {
// try to eagerly initialize the pool name, if defined as a bean
if (beanFactory.isTypeMatch(poolName, Pool.class)) {
if (log.isDebugEnabled()) {
log.debug(String.format("Found bean definition for pool '%1$s'; Eagerly initializing...", poolName));
}
beanFactory.getBean(poolName, Pool.class);
}
clientRegionFactory.setPoolName(poolName);
clientRegionFactory.setPoolName(eagerlyInitializePool(poolName));
}
addCacheListeners(clientRegionFactory);
if (diskStoreName != null) {
clientRegionFactory.setDiskStoreName(diskStoreName);
}
@@ -169,7 +165,8 @@ public class ClientRegionFactoryBean<K, V> extends RegionLookupFactoryBean<K, V>
return clientRegion;
}
protected ClientRegionShortcut resolveClientRegionShortcut() {
/* (non-Javadoc) */
ClientRegionShortcut resolveClientRegionShortcut() {
ClientRegionShortcut resolvedShortcut = this.shortcut;
if (resolvedShortcut == null) {
@@ -205,6 +202,36 @@ public class ClientRegionFactoryBean<K, V> extends RegionLookupFactoryBean<K, V>
return resolvedShortcut;
}
/* (non-Javadoc) */
String resolvePoolName() {
String poolName = this.poolName;
if (!StringUtils.hasText(poolName)) {
String defaultPoolName = GemfireConstants.DEFAULT_GEMFIRE_POOL_NAME;
poolName = (beanFactory.containsBean(defaultPoolName) ? defaultPoolName : poolName);
}
return poolName;
}
/* (non-Javadoc) */
String eagerlyInitializePool(String poolName) {
try {
if (beanFactory.isTypeMatch(poolName, Pool.class)) {
if (log.isDebugEnabled()) {
log.debug(String.format("Found bean definition for Pool [%1$s]; Eagerly initializing...", poolName));
}
beanFactory.getBean(poolName, Pool.class);
}
}
catch (BeansException ignore) {
log.warn(ignore.getMessage());
}
return poolName;
}
/**
* Validates that the settings for ClientRegionShortcut and the 'persistent' attribute in &lt;gfe:*-region&gt; elements
* are compatible.

View File

@@ -0,0 +1,180 @@
/*
* 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.client;
import java.net.InetSocketAddress;
import java.util.List;
import com.gemstone.gemfire.cache.client.Pool;
import com.gemstone.gemfire.cache.query.QueryService;
/**
* The PoolAdapter class is an abstract, default no-op implementation of the GemFire {@link Pool} interface
* that conveniently enables implementing classes to extend this adapter to adapt their interfaces and serve
* as a {@link Pool}.
*
* For instance, one possible implementation is Spring Data GemFire's {@link PoolFactoryBean}, which can act as
* a {@link Pool} in a context where only the {@link Pool}'s "configuration" and meta-data are required,
* but not actual connections or operating state information (e.g. pendingEventCount).
*
* @author John Blum
* @see org.springframework.data.gemfire.client.PoolFactoryBean
* @see com.gemstone.gemfire.cache.client.Pool
* @since 1.8.0
*/
@SuppressWarnings("unused")
public abstract class PoolAdapter implements Pool {
public static final String NOT_IMPLEMENTED = "Not Implemented";
/* (non-Javadoc) */
public boolean isDestroyed() {
throw new UnsupportedOperationException(NOT_IMPLEMENTED);
}
/* (non-Javadoc) */
public int getFreeConnectionTimeout() {
throw new UnsupportedOperationException(NOT_IMPLEMENTED);
}
/* (non-Javadoc) */
public long getIdleTimeout() {
throw new UnsupportedOperationException(NOT_IMPLEMENTED);
}
/* (non-Javadoc) */
public int getLoadConditioningInterval() {
throw new UnsupportedOperationException(NOT_IMPLEMENTED);
}
/* (non-Javadoc) */
public List<InetSocketAddress> getLocators() {
throw new UnsupportedOperationException(NOT_IMPLEMENTED);
}
/* (non-Javadoc) */
public int getMaxConnections() {
throw new UnsupportedOperationException(NOT_IMPLEMENTED);
}
/* (non-Javadoc) */
public int getMinConnections() {
throw new UnsupportedOperationException(NOT_IMPLEMENTED);
}
/* (non-Javadoc) */
public boolean getMultiuserAuthentication() {
throw new UnsupportedOperationException(NOT_IMPLEMENTED);
}
/* (non-Javadoc) */
public String getName() {
throw new UnsupportedOperationException(NOT_IMPLEMENTED);
}
/* (non-Javadoc) */
public boolean getPRSingleHopEnabled() {
throw new UnsupportedOperationException(NOT_IMPLEMENTED);
}
/* (non-Javadoc) */
public int getPendingEventCount() {
throw new UnsupportedOperationException(NOT_IMPLEMENTED);
}
/* (non-Javadoc) */
public long getPingInterval() {
throw new UnsupportedOperationException(NOT_IMPLEMENTED);
}
/* (non-Javadoc) */
public QueryService getQueryService() {
throw new UnsupportedOperationException(NOT_IMPLEMENTED);
}
/* (non-Javadoc) */
public int getReadTimeout() {
throw new UnsupportedOperationException(NOT_IMPLEMENTED);
}
/* (non-Javadoc) */
public int getRetryAttempts() {
throw new UnsupportedOperationException(NOT_IMPLEMENTED);
}
/* (non-Javadoc) */
public String getServerGroup() {
throw new UnsupportedOperationException(NOT_IMPLEMENTED);
}
/* (non-Javadoc) */
public List<InetSocketAddress> getServers() {
throw new UnsupportedOperationException(NOT_IMPLEMENTED);
}
/* (non-Javadoc) */
public int getSocketBufferSize() {
throw new UnsupportedOperationException(NOT_IMPLEMENTED);
}
/* (non-Javadoc) */
public int getStatisticInterval() {
throw new UnsupportedOperationException(NOT_IMPLEMENTED);
}
/* (non-Javadoc) */
public int getSubscriptionAckInterval() {
throw new UnsupportedOperationException(NOT_IMPLEMENTED);
}
/* (non-Javadoc) */
public boolean getSubscriptionEnabled() {
throw new UnsupportedOperationException(NOT_IMPLEMENTED);
}
/* (non-Javadoc) */
public int getSubscriptionMessageTrackingTimeout() {
throw new UnsupportedOperationException(NOT_IMPLEMENTED);
}
/* (non-Javadoc) */
public int getSubscriptionRedundancy() {
throw new UnsupportedOperationException(NOT_IMPLEMENTED);
}
/* (non-Javadoc) */
public boolean getThreadLocalConnections() {
throw new UnsupportedOperationException(NOT_IMPLEMENTED);
}
/* (non-Javadoc) */
public void destroy() {
throw new UnsupportedOperationException(NOT_IMPLEMENTED);
}
/* (non-Javadoc) */
public void destroy(final boolean keepAlive) {
throw new UnsupportedOperationException(NOT_IMPLEMENTED);
}
/* (non-Javadoc) */
public void releaseThreadLocalConnection() {
throw new UnsupportedOperationException(NOT_IMPLEMENTED);
}
}

View File

@@ -17,41 +17,41 @@
package org.springframework.data.gemfire.client;
import java.net.InetSocketAddress;
import java.util.Collection;
import java.util.Properties;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
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.GemfireUtils;
import org.springframework.data.gemfire.support.ConnectionEndpoint;
import org.springframework.data.gemfire.support.ConnectionEndpointList;
import org.springframework.data.gemfire.util.CollectionUtils;
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 Pool. If a new Pool is created,
* its lifecycle is bound to that of the declaring container.
* 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 the Pool already exists, the existing Pool will be returned as is without any modifications
* and its lifecycle will be unaffected by this 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.
*
* @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
@@ -61,7 +61,6 @@ import com.gemstone.gemfire.distributed.DistributedSystem;
* @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,
@@ -73,16 +72,14 @@ public class PoolFactoryBean implements FactoryBean<Pool>, InitializingBean, Dis
private static final Log log = LogFactory.getLog(PoolFactoryBean.class);
// indicates whether the Pool has been created internally (by this FactoryBean) or not
private volatile boolean springBasedPool = true;
volatile boolean springBasedPool = true;
private BeanFactory beanFactory;
private ConnectionEndpointList locators = new ConnectionEndpointList();
private ConnectionEndpointList servers = new ConnectionEndpointList();
private Pool pool;
private Properties gemfireProperties;
private volatile Pool pool;
private String beanName;
private String name;
@@ -111,18 +108,28 @@ public class PoolFactoryBean implements FactoryBean<Pool>, InitializingBean, Dis
private String serverGroup = PoolFactory.DEFAULT_SERVER_GROUP;
/**
* Constructs and initializes a GemFire {@link Pool}.
*
* @throws Exception if the {@link Pool} creation and initialization fails.
* @see com.gemstone.gemfire.cache.client.Pool
* @see com.gemstone.gemfire.cache.client.PoolFactory
* @see com.gemstone.gemfire.cache.client.PoolManager
* @see #createPoolFactory()
*/
@Override
public void afterPropertiesSet() throws Exception {
if (!StringUtils.hasText(name)) {
Assert.hasText(beanName, "Pool 'name' is required");
name = beanName;
}
// first check the configured pools
// check for an existing, configured Pool with name first
Pool existingPool = PoolManager.find(name);
if (existingPool != null) {
if (log.isDebugEnabled()) {
log.debug(String.format("A Pool with name '%1$s' already exists; using existing Pool.", name));
log.debug(String.format("A Pool with name [%1$s] already exists; using existing Pool.", name));
}
springBasedPool = false;
@@ -130,14 +137,38 @@ public class PoolFactoryBean implements FactoryBean<Pool>, InitializingBean, Dis
}
else {
if (log.isDebugEnabled()) {
log.debug(String.format("No Pool with name '%1$s' was found. Creating a new Pool...", name));
}
if (locators.isEmpty() && servers.isEmpty()) {
throw new IllegalArgumentException("at least one GemFire Locator or Server is required");
log.debug(String.format("No Pool with name [%1$s] was found. Creating new Pool.", name));
}
springBasedPool = true;
}
}
/**
* Destroys the GemFire {@link Pool} if created by this {@link PoolFactoryBean} and releases all system resources
* used by the {@link Pool}.
*
* @throws Exception if the {@link Pool} destruction caused an error.
* @see DisposableBean#destroy()
*/
@Override
public void destroy() throws Exception {
if (springBasedPool && pool != null && !pool.isDestroyed()) {
pool.releaseThreadLocalConnection();
pool.destroy(keepAlive);
pool = null;
if (log.isDebugEnabled()) {
log.debug(String.format("Destroyed Pool [%1$s]", name));
}
}
}
/* (non-Javadoc) */
@Override
public Pool getObject() throws Exception {
if (pool == null) {
eagerlyInitializeClientCacheIfNotPresent();
PoolFactory poolFactory = createPoolFactory();
@@ -168,218 +199,400 @@ public class PoolFactoryBean implements FactoryBean<Pool>, InitializingBean, Dis
poolFactory.addServer(server.getHost(), server.getPort());
}
// eagerly initialize the GemFire DistributedSystem (if needed)
resolveDistributedSystem();
pool = poolFactory.create(name);
}
return pool;
}
/**
* Attempts to eagerly initialize the GemFire {@link ClientCache} if not already present so that the single
* {@link com.gemstone.gemfire.distributed.DistributedSystem} will exists, which is required to create
* a {@link Pool} instance.
*
* @see org.springframework.beans.factory.BeanFactory#getBean(Class)
* @see com.gemstone.gemfire.cache.client.ClientCache
*/
void eagerlyInitializeClientCacheIfNotPresent() {
if (!isDistributedSystemPresent()) {
getBeanFactory().getBean(ClientCache.class);
}
}
/**
* Creates an instance of the GemFire PoolFactory interface to construct, configure and initialize a GemFire Pool.
* Determines whether the GemFire DistributedSystem exists yet or not.
*
* @return a PoolFactory implementation to create Pool.
* @see com.gemstone.gemfire.cache.client.PoolFactory
* @return a boolean value indicating whether the single, GemFire DistributedSystem has been created already.
* @see org.springframework.data.gemfire.GemfireUtils#getDistributedSystem()
* @see org.springframework.data.gemfire.GemfireUtils#isConnected(DistributedSystem)
* @see com.gemstone.gemfire.distributed.DistributedSystem
*/
boolean isDistributedSystemPresent() {
return GemfireUtils.isConnected(GemfireUtils.getDistributedSystem());
}
/**
* Creates an instance of the GemFire {@link PoolFactory} interface to construct, configure and initialize
* a GemFire {@link Pool}.
*
* @return a {@link PoolFactory} implementation to create a {@link Pool}.
* @see com.gemstone.gemfire.cache.client.PoolManager#createFactory()
* @see com.gemstone.gemfire.cache.client.PoolFactory
*/
protected PoolFactory createPoolFactory() {
return PoolManager.createFactory();
}
/**
* Attempts to find an existing, running GemFire {@link DistributedSystem} or proceeds to create
* a new {@link DistributedSystem} if one does not exist.
*
* @see DistributedSystemUtils#getDistributedSystem()
* @see #resolveGemfireProperties()
* @see #doDistributedSystemConnect(Properties)
*/
protected void resolveDistributedSystem() {
if (DistributedSystemUtils.isNotConnected(DistributedSystemUtils.getDistributedSystem())) {
doDistributedSystemConnect(resolveGemfireProperties());
}
}
/**
* Attempts to resolve existing GemFire System properties from the {@link ClientCacheFactoryBean}
* if set by the user.
*
* @return a {@link Properties} object containing GemFire System properties
* or null if no properties were configured.
* @see ClientCacheFactoryBean#resolveProperties()
* @see java.util.Properties
*/
protected Properties resolveGemfireProperties() {
gemfireProperties = (gemfireProperties != null ? gemfireProperties : new Properties());
try {
ClientCacheFactoryBean clientCacheFactoryBean = beanFactory.getBean(ClientCacheFactoryBean.class);
CollectionUtils.mergePropertiesIntoMap(clientCacheFactoryBean.resolveProperties(), gemfireProperties);
}
catch (Exception ignore) {
}
return gemfireProperties;
}
/**
* A workaround to create a Pool if no ClientCache has been created yet. Initialize a cache client-like
* DistributedSystem before initializing the Pool.
*
* @param properties GemFire System Properties.
* @see java.util.Properties
* @see com.gemstone.gemfire.distributed.DistributedSystem#connect(java.util.Properties)
*/
@SuppressWarnings("deprecation")
void doDistributedSystemConnect(Properties properties) {
Properties gemfireProperties = (properties != null ? (Properties) properties.clone() : new Properties());
gemfireProperties.setProperty("locators", "");
gemfireProperties.setProperty("mcast-port", "0");
DistributedSystem.connect(gemfireProperties);
}
public void destroy() throws Exception {
if (springBasedPool && pool != null && !pool.isDestroyed()) {
pool.releaseThreadLocalConnection();
pool.destroy(keepAlive);
pool = null;
if (log.isDebugEnabled()) {
log.debug(String.format("Destroyed Pool '%1$s'.", name));
}
}
}
public Pool getObject() throws Exception {
return pool;
}
/* (non-Javadoc) */
@Override
public Class<?> getObjectType() {
return (pool != null ? pool.getClass() : Pool.class);
}
/* (non-Javadoc) */
@Override
public boolean isSingleton() {
return true;
}
public void setBeanFactory(BeanFactory beanFactory) {
/* (non-Javadoc) */
public void addLocators(ConnectionEndpoint... locators) {
this.locators.add(locators);
}
/* (non-Javadoc) */
public void addLocators(Iterable<ConnectionEndpoint> locators) {
this.locators.add(locators);
}
/* (non-Javadoc) */
public void addServers(ConnectionEndpoint... servers) {
this.servers.add(servers);
}
/* (non-Javadoc) */
public void addServers(Iterable<ConnectionEndpoint> servers) {
this.servers.add(servers);
}
/* (non-Javadoc) */
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
}
/* (non-Javadoc) */
protected BeanFactory getBeanFactory() {
return beanFactory;
}
/* (non-Javadoc) */
public void setBeanName(String name) {
this.beanName = name;
}
/* (non-Javadoc) */
public void setName(String name) {
this.name = name;
}
/* (non-Javadoc) */
String getName() {
return name;
}
/* (non-Javadoc) */
public void setPool(Pool pool) {
this.pool = pool;
}
/* (non-Javadoc) */
public Pool getPool() {
return (pool != null ? pool : new PoolAdapter() {
@Override
public boolean isDestroyed() {
Pool pool = PoolFactoryBean.this.pool;
return (pool != null && pool.isDestroyed());
}
@Override
public int getFreeConnectionTimeout() {
return PoolFactoryBean.this.freeConnectionTimeout;
}
@Override
public long getIdleTimeout() {
return PoolFactoryBean.this.idleTimeout;
}
@Override
public int getLoadConditioningInterval() {
return PoolFactoryBean.this.loadConditioningInterval;
}
@Override
public List<InetSocketAddress> getLocators() {
return PoolFactoryBean.this.locators.toInetSocketAddresses();
}
@Override
public int getMaxConnections() {
return PoolFactoryBean.this.maxConnections;
}
@Override
public int getMinConnections() {
return PoolFactoryBean.this.minConnections;
}
@Override
public boolean getMultiuserAuthentication() {
return PoolFactoryBean.this.multiUserAuthentication;
}
@Override
public String getName() {
String name = PoolFactoryBean.this.name;
name = (StringUtils.hasText(name) ? name : PoolFactoryBean.this.beanName);
return name;
}
@Override
public int getPendingEventCount() {
Pool pool = PoolFactoryBean.this.pool;
if (pool != null) {
return pool.getPendingEventCount();
}
throw new IllegalStateException("The Pool is not initialized");
}
@Override
public long getPingInterval() {
return PoolFactoryBean.this.pingInterval;
}
@Override
public boolean getPRSingleHopEnabled() {
return PoolFactoryBean.this.prSingleHopEnabled;
}
@Override
public QueryService getQueryService() {
Pool pool = PoolFactoryBean.this.pool;
if (pool != null) {
return pool.getQueryService();
}
throw new IllegalStateException("The Pool is not initialized");
}
@Override
public int getReadTimeout() {
return PoolFactoryBean.this.readTimeout;
}
@Override
public int getRetryAttempts() {
return PoolFactoryBean.this.retryAttempts;
}
@Override
public String getServerGroup() {
return PoolFactoryBean.this.serverGroup;
}
@Override
public List<InetSocketAddress> getServers() {
return PoolFactoryBean.this.servers.toInetSocketAddresses();
}
@Override
public int getSocketBufferSize() {
return PoolFactoryBean.this.socketBufferSize;
}
@Override
public int getStatisticInterval() {
return PoolFactoryBean.this.statisticInterval;
}
@Override
public int getSubscriptionAckInterval() {
return PoolFactoryBean.this.subscriptionAckInterval;
}
@Override
public boolean getSubscriptionEnabled() {
return PoolFactoryBean.this.subscriptionEnabled;
}
@Override
public int getSubscriptionMessageTrackingTimeout() {
return PoolFactoryBean.this.subscriptionMessageTrackingTimeout;
}
@Override
public int getSubscriptionRedundancy() {
return PoolFactoryBean.this.subscriptionRedundancy;
}
@Override
public boolean getThreadLocalConnections() {
return PoolFactoryBean.this.threadLocalConnections;
}
@Override
public void destroy() {
destroy(false);
}
@Override
public void destroy(final boolean keepAlive) {
try {
PoolFactoryBean.this.destroy();
}
catch (Exception ignore) {
Pool pool = PoolFactoryBean.this.pool;
if (pool != null) {
pool.destroy(keepAlive);
}
}
}
@Override
public void releaseThreadLocalConnection() {
Pool pool = PoolFactoryBean.this.pool;
if (pool != null) {
pool.releaseThreadLocalConnection();
}
else {
throw new IllegalStateException("The Pool is not initialized");
}
}
});
}
/* (non-Javadoc) */
public void setFreeConnectionTimeout(int freeConnectionTimeout) {
this.freeConnectionTimeout = freeConnectionTimeout;
}
/* (non-Javadoc) */
public void setIdleTimeout(long idleTimeout) {
this.idleTimeout = idleTimeout;
}
/* (non-Javadoc) */
public void setKeepAlive(boolean keepAlive) {
this.keepAlive = keepAlive;
}
@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);
}
/* (non-Javadoc) */
public void setLoadConditioningInterval(int loadConditioningInterval) {
this.loadConditioningInterval = loadConditioningInterval;
}
/* (non-Javadoc) */
public void setLocators(ConnectionEndpoint[] connectionEndpoints) {
setLocators(ConnectionEndpointList.from(connectionEndpoints));
}
/* (non-Javadoc) */
public void setLocators(Iterable<ConnectionEndpoint> connectionEndpoints) {
getLocators().clear();
getLocators().add(connectionEndpoints);
}
/* (non-Javadoc) */
ConnectionEndpointList getLocators() {
return locators;
}
/* (non-Javadoc) */
public void setMaxConnections(int maxConnections) {
this.maxConnections = maxConnections;
}
/* (non-Javadoc) */
public void setMinConnections(int minConnections) {
this.minConnections = minConnections;
}
/* (non-Javadoc) */
public void setMultiUserAuthentication(boolean multiUserAuthentication) {
this.multiUserAuthentication = multiUserAuthentication;
}
/* (non-Javadoc) */
public void setPingInterval(long pingInterval) {
this.pingInterval = pingInterval;
}
public void setProperties(Properties gemfireProperties) {
this.gemfireProperties = gemfireProperties;
}
/* (non-Javadoc) */
public void setPrSingleHopEnabled(boolean prSingleHopEnabled) {
this.prSingleHopEnabled = prSingleHopEnabled;
}
/* (non-Javadoc) */
public void setReadTimeout(int readTimeout) {
this.readTimeout = readTimeout;
}
/* (non-Javadoc) */
public void setRetryAttempts(int retryAttempts) {
this.retryAttempts = retryAttempts;
}
/* (non-Javadoc) */
public void setServerGroup(String serverGroup) {
this.serverGroup = serverGroup;
}
@Deprecated
public void setServers(Collection<InetSocketAddress> servers) {
setServerEndpoints(ConnectionEndpointList.from(servers));
/* (non-Javadoc) */
public void setServers(ConnectionEndpoint[] connectionEndpoints) {
setServers(ConnectionEndpointList.from(connectionEndpoints));
}
public void setServerEndpoints(Iterable<ConnectionEndpoint> endpoints) {
this.servers.add(endpoints);
/* (non-Javadoc) */
public void setServers(Iterable<ConnectionEndpoint> connectionEndpoints) {
getServers().clear();
getServers().add(connectionEndpoints);
}
public void setServerEndpointList(ConnectionEndpointList endpointList) {
setServerEndpoints(endpointList);
/* (non-Javadoc) */
ConnectionEndpointList getServers() {
return servers;
}
/* (non-Javadoc) */
public void setSocketBufferSize(int socketBufferSize) {
this.socketBufferSize = socketBufferSize;
}
/* (non-Javadoc) */
public void setStatisticInterval(int statisticInterval) {
this.statisticInterval = statisticInterval;
}
/* (non-Javadoc) */
public void setSubscriptionAckInterval(int subscriptionAckInterval) {
this.subscriptionAckInterval = subscriptionAckInterval;
}
/* (non-Javadoc) */
public void setSubscriptionEnabled(boolean subscriptionEnabled) {
this.subscriptionEnabled = subscriptionEnabled;
}
/* (non-Javadoc) */
public void setSubscriptionMessageTrackingTimeout(int subscriptionMessageTrackingTimeout) {
this.subscriptionMessageTrackingTimeout = subscriptionMessageTrackingTimeout;
}
/* (non-Javadoc) */
public void setSubscriptionRedundancy(int subscriptionRedundancy) {
this.subscriptionRedundancy = subscriptionRedundancy;
}
/* (non-Javadoc) */
public void setThreadLocalConnections(boolean threadLocalConnections) {
this.threadLocalConnections = threadLocalConnections;
}

View File

@@ -0,0 +1,333 @@
/*
* 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.client.support;
import java.net.InetSocketAddress;
import java.util.Collection;
import java.util.List;
import org.springframework.data.gemfire.util.SpringUtils;
import org.springframework.util.Assert;
import com.gemstone.gemfire.cache.client.Pool;
import com.gemstone.gemfire.cache.query.QueryService;
/**
* The DefaultableDelegatingPoolAdapter class...
*
* @author John Blum
* @since 1.0.0
*/
@SuppressWarnings("unused")
public abstract class DefaultableDelegatingPoolAdapter {
private final Pool delegate;
private Preference preference = Preference.PREFER_POOL;
/* (non-Javadoc) */
public static DefaultableDelegatingPoolAdapter from(Pool delegate) {
return new DefaultableDelegatingPoolAdapter(delegate) { };
}
/* (non-Javadoc) */
protected DefaultableDelegatingPoolAdapter(Pool delegate) {
Assert.notNull(delegate, "'delegate' must not be null");
this.delegate = delegate;
}
/* (non-Javadoc) */
protected Pool getDelegate() {
return delegate;
}
/* (non-Javadoc) */
protected DefaultableDelegatingPoolAdapter setPreference(Preference preference) {
this.preference = preference;
return this;
}
/* (non-Javadoc) */
protected Preference getPreference() {
return this.preference;
}
/* (non-Javadoc) */
protected <T> T defaultIfNull(T defaultValue, ValueProvider<T> valueProvider) {
return (prefersPool() ? SpringUtils.defaultIfNull(valueProvider.getValue(), defaultValue) :
(defaultValue != null ? defaultValue : valueProvider.getValue()));
}
/* (non-Javadoc) */
protected <E, T extends Collection<E>> T defaultIfEmpty(T defaultValue, ValueProvider<T> valueProvider) {
if (prefersPool()) {
T value = valueProvider.getValue();
return (value == null || value.isEmpty() ? defaultValue : value);
}
else {
return (defaultValue == null || defaultValue.isEmpty() ? valueProvider.getValue() : defaultValue);
}
}
/* (non-Javadoc) */
public DefaultableDelegatingPoolAdapter preferDefault() {
return setPreference(Preference.PREFER_DEFAULT);
}
/* (non-Javadoc) */
protected boolean prefersDefault() {
return Preference.PREFER_DEFAULT.equals(getPreference());
}
/* (non-Javadoc) */
public DefaultableDelegatingPoolAdapter preferPool() {
return setPreference(Preference.PREFER_POOL);
}
/* (non-Javadoc) */
protected boolean prefersPool() {
return Preference.PREFER_POOL.equals(getPreference());
}
/* (non-Javadoc) */
public boolean isDestroyed() {
return getDelegate().isDestroyed();
}
/* (non-Javadoc) */
public int getFreeConnectionTimeout(Integer defaultFreeConnectionTimeout) {
return defaultIfNull(defaultFreeConnectionTimeout, new ValueProvider<Integer>() {
@Override public Integer getValue() {
return getDelegate().getFreeConnectionTimeout();
}
});
}
/* (non-Javadoc) */
public long getIdleTimeout(Long defaultIdleTimeout) {
return defaultIfNull(defaultIdleTimeout, new ValueProvider<Long>() {
@Override public Long getValue() {
return getDelegate().getIdleTimeout();
}
});
}
/* (non-Javadoc) */
public int getLoadConditioningInterval(Integer defaultLoadConditioningInterval) {
return defaultIfNull(defaultLoadConditioningInterval, new ValueProvider<Integer>() {
@Override public Integer getValue() {
return getDelegate().getLoadConditioningInterval();
}
});
}
/* (non-Javadoc) */
public List<InetSocketAddress> getLocators(List<InetSocketAddress> defaultLocators) {
return defaultIfEmpty(defaultLocators, new ValueProvider<List<InetSocketAddress>>() {
@Override public List<InetSocketAddress> getValue() {
return getDelegate().getLocators();
}
});
}
/* (non-Javadoc) */
public int getMaxConnections(Integer defaultMaxConnections) {
return defaultIfNull(defaultMaxConnections, new ValueProvider<Integer>() {
@Override public Integer getValue() {
return getDelegate().getMaxConnections();
}
});
}
/* (non-Javadoc) */
public int getMinConnections(Integer defaultMinConnections) {
return defaultIfNull(defaultMinConnections, new ValueProvider<Integer>() {
@Override public Integer getValue() {
return getDelegate().getMinConnections();
}
});
}
/* (non-Javadoc) */
public boolean getMultiuserAuthentication(Boolean defaultMultiUserAuthentication) {
return defaultIfNull(defaultMultiUserAuthentication, new ValueProvider<Boolean>() {
@Override public Boolean getValue() {
return getDelegate().getMultiuserAuthentication();
}
});
}
/* (non-Javadoc) */
public String getName() {
return getDelegate().getName();
}
/* (non-Javadoc) */
public int getPendingEventCount() {
return getDelegate().getPendingEventCount();
}
/* (non-Javadoc) */
public long getPingInterval(Long defaultPingInterval) {
return defaultIfNull(defaultPingInterval, new ValueProvider<Long>() {
@Override public Long getValue() {
return getDelegate().getPingInterval();
}
});
}
/* (non-Javadoc) */
public boolean getPRSingleHopEnabled(Boolean defaultPrSingleHopEnabled) {
return defaultIfNull(defaultPrSingleHopEnabled, new ValueProvider<Boolean>() {
@Override public Boolean getValue() {
return getDelegate().getPRSingleHopEnabled();
}
});
}
/* (non-Javadoc) */
public QueryService getQueryService() {
return getDelegate().getQueryService();
}
/* (non-Javadoc) */
public int getReadTimeout(Integer defaultReadTimeout) {
return defaultIfNull(defaultReadTimeout, new ValueProvider<Integer>() {
@Override public Integer getValue() {
return getDelegate().getReadTimeout();
}
});
}
/* (non-Javadoc) */
public int getRetryAttempts(Integer defaultRetryAttempts) {
return defaultIfNull(defaultRetryAttempts, new ValueProvider<Integer>() {
@Override public Integer getValue() {
return getDelegate().getRetryAttempts();
}
});
}
/* (non-Javadoc) */
public String getServerGroup(String defaultServerGroup) {
return defaultIfNull(defaultServerGroup, new ValueProvider<String>() {
@Override public String getValue() {
return getDelegate().getServerGroup();
}
});
}
/* (non-Javadoc) */
public List<InetSocketAddress> getServers(List<InetSocketAddress> defaultServers) {
return defaultIfEmpty(defaultServers, new ValueProvider<List<InetSocketAddress>>() {
@Override public List<InetSocketAddress> getValue() {
return getDelegate().getServers();
}
});
}
/* (non-Javadoc) */
public int getSocketBufferSize(Integer defaultSocketBufferSize) {
return defaultIfNull(defaultSocketBufferSize, new ValueProvider<Integer>() {
@Override public Integer getValue() {
return getDelegate().getSocketBufferSize();
}
});
}
/* (non-Javadoc) */
public int getStatisticInterval(Integer defaultStatisticInterval) {
return defaultIfNull(defaultStatisticInterval, new ValueProvider<Integer>() {
@Override public Integer getValue() {
return getDelegate().getStatisticInterval();
}
});
}
/* (non-Javadoc) */
public int getSubscriptionAckInterval(Integer defaultSubscriptionAckInterval) {
return defaultIfNull(defaultSubscriptionAckInterval, new ValueProvider<Integer>() {
@Override public Integer getValue() {
return getDelegate().getSubscriptionAckInterval();
}
});
}
/* (non-Javadoc) */
public boolean getSubscriptionEnabled(Boolean defaultSubscriptionEnabled) {
return defaultIfNull(defaultSubscriptionEnabled, new ValueProvider<Boolean>() {
@Override public Boolean getValue() {
return getDelegate().getSubscriptionEnabled();
}
});
}
/* (non-Javadoc) */
public int getSubscriptionMessageTrackingTimeout(Integer defaultSubscriptionMessageTrackingTimeout) {
return defaultIfNull(defaultSubscriptionMessageTrackingTimeout, new ValueProvider<Integer>() {
@Override public Integer getValue() {
return getDelegate().getSubscriptionMessageTrackingTimeout();
}
});
}
/* (non-Javadoc) */
public int getSubscriptionRedundancy(Integer defaultSubscriptionRedundancy) {
return defaultIfNull(defaultSubscriptionRedundancy, new ValueProvider<Integer>() {
@Override public Integer getValue() {
return getDelegate().getSubscriptionRedundancy();
}
});
}
/* (non-Javadoc) */
public boolean getThreadLocalConnections(Boolean defaultThreadLocalConnections) {
return defaultIfNull(defaultThreadLocalConnections, new ValueProvider<Boolean>() {
@Override public Boolean getValue() {
return getDelegate().getThreadLocalConnections();
}
});
}
/* (non-Javadoc) */
public void destroy() {
getDelegate().destroy();
}
/* (non-Javadoc) */
public void destroy(final boolean keepAlive) {
getDelegate().destroy(keepAlive);
}
/* (non-Javadoc) */
public void releaseThreadLocalConnection() {
getDelegate().releaseThreadLocalConnection();
}
/* (non-Javadoc) */
enum Preference {
PREFER_DEFAULT,
PREFER_POOL;
}
/* (non-Javadoc) */
interface ValueProvider<T> {
T getValue();
}
}

View File

@@ -0,0 +1,254 @@
/*
* 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.client.support;
import java.net.InetSocketAddress;
import java.util.List;
import com.gemstone.gemfire.cache.client.Pool;
import com.gemstone.gemfire.cache.query.QueryService;
/**
* DelegatingPoolAdapter is an abstract implementation of GemFire's {@link Pool} interface and extension of
* {@link FactoryDefaultsPoolAdapter} that delegates operations to the provided {@link Pool} instance.
*
* However, this implementation guards against a potentially <code>null</code> {@link Pool} reference by returning
* default factory settings for the {@link Pool}'s configuration properties along with default behavior for operations
* when the {@link Pool} reference is <code>null</code>.
*
* @author John Blum
* @see FactoryDefaultsPoolAdapter
* @see com.gemstone.gemfire.cache.client.Pool
* @since 1.8.0
*/
@SuppressWarnings("unused")
public abstract class DelegatingPoolAdapter extends FactoryDefaultsPoolAdapter {
private final Pool delegate;
/* (non-Javadoc) */
public static DelegatingPoolAdapter from(Pool delegate) {
return new DelegatingPoolAdapter(delegate) { };
}
public DelegatingPoolAdapter(Pool delegate) {
this.delegate = delegate;
}
/* (non-Javadoc) */
protected Pool getDelegate() {
return delegate;
}
/* (non-Javadoc) */
@Override
public boolean isDestroyed() {
Pool delegate = getDelegate();
return (delegate != null ? delegate.isDestroyed() : super.isDestroyed());
}
/* (non-Javadoc) */
@Override
public int getFreeConnectionTimeout() {
Pool delegate = getDelegate();
return (delegate != null ? delegate.getFreeConnectionTimeout() : super.getFreeConnectionTimeout());
}
/* (non-Javadoc) */
@Override
public long getIdleTimeout() {
Pool delegate = getDelegate();
return (delegate != null ? delegate.getIdleTimeout() : super.getIdleTimeout());
}
/* (non-Javadoc) */
@Override
public int getLoadConditioningInterval() {
Pool delegate = getDelegate();
return (delegate != null ? delegate.getLoadConditioningInterval() : super.getLoadConditioningInterval());
}
/* (non-Javadoc) */
@Override
public List<InetSocketAddress> getLocators() {
Pool delegate = getDelegate();
return (delegate != null ? delegate.getLocators() : super.getLocators());
}
/* (non-Javadoc) */
@Override
public int getMaxConnections() {
Pool delegate = getDelegate();
return (delegate != null ? delegate.getMaxConnections() : super.getMaxConnections());
}
/* (non-Javadoc) */
@Override
public int getMinConnections() {
Pool delegate = getDelegate();
return (delegate != null ? delegate.getMinConnections() : super.getMinConnections());
}
/* (non-Javadoc) */
@Override
public boolean getMultiuserAuthentication() {
Pool delegate = getDelegate();
return (delegate != null ? delegate.getMultiuserAuthentication() : super.getMultiuserAuthentication());
}
/* (non-Javadoc) */
@Override
public String getName() {
Pool delegate = getDelegate();
return (delegate != null ? delegate.getName() : super.getName());
}
/* (non-Javadoc) */
@Override
public boolean getPRSingleHopEnabled() {
Pool delegate = getDelegate();
return (delegate != null ? delegate.getPRSingleHopEnabled() : super.getPRSingleHopEnabled());
}
/* (non-Javadoc) */
@Override
public int getPendingEventCount() {
Pool delegate = getDelegate();
return (delegate != null ? delegate.getPendingEventCount() : 0);
}
/* (non-Javadoc) */
@Override
public long getPingInterval() {
Pool delegate = getDelegate();
return (delegate != null ? delegate.getPingInterval() : super.getPingInterval());
}
/* (non-Javadoc) */
@Override
public QueryService getQueryService() {
Pool delegate = getDelegate();
return (delegate != null ? delegate.getQueryService() : super.getQueryService());
}
/* (non-Javadoc) */
@Override
public int getReadTimeout() {
Pool delegate = getDelegate();
return (delegate != null ? delegate.getReadTimeout() : super.getReadTimeout());
}
/* (non-Javadoc) */
@Override
public int getRetryAttempts() {
Pool delegate = getDelegate();
return (delegate != null ? delegate.getRetryAttempts() : super.getRetryAttempts());
}
/* (non-Javadoc) */
@Override
public String getServerGroup() {
Pool delegate = getDelegate();
return (delegate != null ? delegate.getServerGroup() : super.getServerGroup());
}
/* (non-Javadoc) */
@Override
public List<InetSocketAddress> getServers() {
Pool delegate = getDelegate();
return (delegate != null ? delegate.getServers() : super.getServers());
}
/* (non-Javadoc) */
@Override
public int getSocketBufferSize() {
Pool delegate = getDelegate();
return (delegate != null ? delegate.getSocketBufferSize() : super.getSocketBufferSize());
}
/* (non-Javadoc) */
@Override
public int getStatisticInterval() {
Pool delegate = getDelegate();
return (delegate != null ? delegate.getStatisticInterval() : super.getStatisticInterval());
}
/* (non-Javadoc) */
@Override
public int getSubscriptionAckInterval() {
Pool delegate = getDelegate();
return (delegate != null ? delegate.getSubscriptionAckInterval() : super.getSubscriptionAckInterval());
}
/* (non-Javadoc) */
@Override
public boolean getSubscriptionEnabled() {
Pool delegate = getDelegate();
return (delegate != null ? delegate.getSubscriptionEnabled() : super.getSubscriptionEnabled());
}
/* (non-Javadoc) */
@Override
public int getSubscriptionMessageTrackingTimeout() {
Pool delegate = getDelegate();
return (delegate != null ? delegate.getSubscriptionMessageTrackingTimeout()
: super.getSubscriptionMessageTrackingTimeout());
}
/* (non-Javadoc) */
@Override
public int getSubscriptionRedundancy() {
Pool delegate = getDelegate();
return (delegate != null ? delegate.getSubscriptionRedundancy() : super.getSubscriptionRedundancy());
}
/* (non-Javadoc) */
@Override
public boolean getThreadLocalConnections() {
Pool delegate = getDelegate();
return (delegate != null ? delegate.getThreadLocalConnections() : super.getThreadLocalConnections());
}
/* (non-Javadoc) */
@Override
public void destroy() {
Pool delegate = getDelegate();
if (delegate != null) {
delegate.destroy();
}
}
/* (non-Javadoc) */
@Override
public void destroy(final boolean keepAlive) {
Pool delegate = getDelegate();
if (delegate != null) {
delegate.destroy(keepAlive);
}
}
/* (non-Javadoc) */
@Override
public void releaseThreadLocalConnection() {
Pool delegate = getDelegate();
if (delegate != null) {
delegate.releaseThreadLocalConnection();
}
}
}

View File

@@ -0,0 +1,186 @@
/*
* 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.client.support;
import java.net.InetSocketAddress;
import java.util.Collections;
import java.util.List;
import org.springframework.data.gemfire.GemfireUtils;
import org.springframework.data.gemfire.client.PoolAdapter;
import com.gemstone.gemfire.cache.client.PoolFactory;
import com.gemstone.gemfire.cache.query.QueryService;
/**
* FactoryDefaultsPoolAdapter is an abstract implementation of GemFire's {@link com.gemstone.gemfire.cache.client.Pool}
* interface and extension of {@link PoolAdapter} providing default factory values for all configuration properties
* (e.g. freeConnectionTimeout, idleTimeout, etc).
*
* @author John Blum
* @see org.springframework.data.gemfire.client.PoolAdapter
* @see com.gemstone.gemfire.cache.client.PoolFactory
* @see com.gemstone.gemfire.cache.client.Pool
* @since 1.8.0
*/
@SuppressWarnings("unused")
public abstract class FactoryDefaultsPoolAdapter extends PoolAdapter {
protected static final boolean DEFAULT_KEEP_ALIVE = false;
protected static final String DEFAULT_POOL_NAME = "DEFAULT";
protected static final String LOCALHOST = "localhost";
/* (non-Javadoc) */
@Override
public int getFreeConnectionTimeout() {
return PoolFactory.DEFAULT_FREE_CONNECTION_TIMEOUT;
}
/* (non-Javadoc) */
@Override
public long getIdleTimeout() {
return PoolFactory.DEFAULT_IDLE_TIMEOUT;
}
/* (non-Javadoc) */
@Override
public int getLoadConditioningInterval() {
return PoolFactory.DEFAULT_LOAD_CONDITIONING_INTERVAL;
}
/* (non-Javadoc) */
@Override
public List<InetSocketAddress> getLocators() {
return Collections.emptyList();
}
/* (non-Javadoc) */
@Override
public int getMaxConnections() {
return PoolFactory.DEFAULT_MAX_CONNECTIONS;
}
/* (non-Javadoc) */
@Override
public int getMinConnections() {
return PoolFactory.DEFAULT_MIN_CONNECTIONS;
}
/* (non-Javadoc) */
@Override
public boolean getMultiuserAuthentication() {
return PoolFactory.DEFAULT_MULTIUSER_AUTHENTICATION;
}
/* (non-Javadoc) */
@Override
public String getName() {
return DEFAULT_POOL_NAME;
}
/* (non-Javadoc) */
@Override
public boolean getPRSingleHopEnabled() {
return PoolFactory.DEFAULT_PR_SINGLE_HOP_ENABLED;
}
/* (non-Javadoc) */
@Override
public long getPingInterval() {
return PoolFactory.DEFAULT_PING_INTERVAL;
}
/* (non-Javadoc) */
@Override
public QueryService getQueryService() {
return null;
}
/* (non-Javadoc) */
@Override
public int getReadTimeout() {
return PoolFactory.DEFAULT_READ_TIMEOUT;
}
/* (non-Javadoc) */
@Override
public int getRetryAttempts() {
return PoolFactory.DEFAULT_RETRY_ATTEMPTS;
}
/* (non-Javadoc) */
@Override
public String getServerGroup() {
return PoolFactory.DEFAULT_SERVER_GROUP;
}
/* (non-Javadoc) */
@Override
public List<InetSocketAddress> getServers() {
return Collections.singletonList(new InetSocketAddress(LOCALHOST, GemfireUtils.DEFAULT_CACHE_SERVER_PORT));
}
/* (non-Javadoc) */
@Override
public int getSocketBufferSize() {
return PoolFactory.DEFAULT_SOCKET_BUFFER_SIZE;
}
/* (non-Javadoc) */
@Override
public int getStatisticInterval() {
return PoolFactory.DEFAULT_STATISTIC_INTERVAL;
}
/* (non-Javadoc) */
@Override
public int getSubscriptionAckInterval() {
return PoolFactory.DEFAULT_SUBSCRIPTION_ACK_INTERVAL;
}
/* (non-Javadoc) */
@Override
public boolean getSubscriptionEnabled() {
return PoolFactory.DEFAULT_SUBSCRIPTION_ENABLED;
}
/* (non-Javadoc) */
@Override
public int getSubscriptionMessageTrackingTimeout() {
return PoolFactory.DEFAULT_SUBSCRIPTION_MESSAGE_TRACKING_TIMEOUT;
}
/* (non-Javadoc) */
@Override
public int getSubscriptionRedundancy() {
return PoolFactory.DEFAULT_SUBSCRIPTION_REDUNDANCY;
}
/* (non-Javadoc) */
@Override
public boolean getThreadLocalConnections() {
return PoolFactory.DEFAULT_THREAD_LOCAL_CONNECTIONS;
}
/* (non-Javadoc) */
public void destroy() {
destroy(DEFAULT_KEEP_ALIVE);
}
}

View File

@@ -25,7 +25,7 @@ import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.ManagedList;
import org.springframework.beans.factory.support.ManagedMap;
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.CacheFactoryBean;
import org.springframework.util.CollectionUtils;
@@ -38,14 +38,14 @@ import org.w3c.dom.NamedNodeMap;
import com.gemstone.gemfire.internal.datasource.ConfigProperty;
/**
* Parser for &lt;cache;gt; definitions.
* Parser for &lt;cache&gt; bean definitions.
*
* @author Costin Leau
* @author Oliver Gierke
* @author David Turanski
* @author John Blum
*/
class CacheParser extends AbstractSimpleBeanDefinitionParser {
class CacheParser extends AbstractSingleBeanDefinitionParser {
@Override
protected Class<?> getBeanClass(Element element) {
@@ -69,11 +69,11 @@ class CacheParser extends AbstractSimpleBeanDefinitionParser {
ParsingUtils.setPropertyValue(element, builder, "lock-lease");
ParsingUtils.setPropertyValue(element, builder, "lock-timeout");
ParsingUtils.setPropertyValue(element, builder, "message-sync-interval");
ParsingUtils.setPropertyReference(element, builder, "pdx-serializer-ref", "pdxSerializer");
ParsingUtils.setPropertyValue(element, builder, "pdx-read-serialized");
ParsingUtils.setPropertyValue(element, builder, "pdx-ignore-unread-fields");
ParsingUtils.setPropertyValue(element, builder, "pdx-persistent");
parsePdxDiskStore(element, parserContext, builder);
ParsingUtils.setPropertyValue(element, builder, "pdx-ignore-unread-fields");
ParsingUtils.setPropertyValue(element, builder, "pdx-read-serialized");
ParsingUtils.setPropertyValue(element, builder, "pdx-persistent");
ParsingUtils.setPropertyReference(element, builder, "pdx-serializer-ref", "pdxSerializer");
ParsingUtils.setPropertyValue(element, builder, "search-timeout");
ParsingUtils.setPropertyValue(element, builder, "use-cluster-configuration");
@@ -81,10 +81,12 @@ class CacheParser extends AbstractSimpleBeanDefinitionParser {
if (!CollectionUtils.isEmpty(txListeners)) {
ManagedList<Object> transactionListeners = new ManagedList<Object>();
for (Element txListener : txListeners) {
transactionListeners.add(ParsingUtils.parseRefOrNestedBeanDeclaration(
parserContext, txListener, builder));
}
builder.addPropertyValue("transactionListeners", transactionListeners);
}
@@ -103,13 +105,6 @@ class CacheParser extends AbstractSimpleBeanDefinitionParser {
parserContext, gatewayConflictResolver, builder));
}
Element function = DomUtils.getChildElementByTagName(element, "function");
if (function != null) {
builder.addPropertyValue("functions", ParsingUtils.parseRefOrNestedBeanDeclaration(
parserContext, function, builder));
}
parseDynamicRegionFactory(element, builder);
parseJndiBindings(element, builder);
}

View File

@@ -17,8 +17,6 @@
package org.springframework.data.gemfire.config;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.data.gemfire.client.ClientCacheFactoryBean;
import org.w3c.dom.Element;
@@ -46,13 +44,6 @@ class ClientCacheParser extends CacheParser {
ParsingUtils.setPropertyValue(element, builder, "keep-alive");
ParsingUtils.setPropertyValue(element, builder, "pool-name");
ParsingUtils.setPropertyValue(element, builder, "ready-for-events");
registerClientCachePoolGemfirePropertiesSyncingBeanFactoryPostProcessor(getRegistry(parserContext));
}
/* (non-Javadoc) */
void registerClientCachePoolGemfirePropertiesSyncingBeanFactoryPostProcessor(BeanDefinitionRegistry registry) {
BeanDefinitionReaderUtils.registerWithGeneratedName(BeanDefinitionBuilder.genericBeanDefinition(
ClientCachePoolGemfirePropertiesSyncingBeanFactoryPostProcessor.class).getBeanDefinition(), registry);
}
@Override

View File

@@ -40,7 +40,7 @@ import org.springframework.util.StringUtils;
* @see org.springframework.data.gemfire.client.PoolFactoryBean
* @since 1.8.0
*/
@SuppressWarnings("unused")
@Deprecated
class ClientCachePoolGemfirePropertiesSyncingBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
protected static final String PROPERTIES_PROPERTY_NAME = "properties";

View File

@@ -16,9 +16,12 @@
package org.springframework.data.gemfire.config;
import java.beans.PropertyEditorSupport;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.core.convert.converter.Converter;
import org.springframework.data.gemfire.EvictionActionConverter;
import org.springframework.data.gemfire.EvictionPolicyConverter;
import org.springframework.data.gemfire.EvictionPolicyType;
@@ -32,6 +35,8 @@ import org.springframework.data.gemfire.ScopeConverter;
import org.springframework.data.gemfire.client.InterestResultPolicyConverter;
import org.springframework.data.gemfire.server.SubscriptionEvictionPolicy;
import org.springframework.data.gemfire.server.SubscriptionEvictionPolicyConverter;
import org.springframework.data.gemfire.support.ConnectionEndpoint;
import org.springframework.data.gemfire.support.ConnectionEndpointList;
import org.springframework.data.gemfire.wan.OrderPolicyConverter;
import org.springframework.data.gemfire.wan.StartupPolicyConverter;
import org.springframework.data.gemfire.wan.StartupPolicyType;
@@ -56,7 +61,8 @@ import com.gemstone.gemfire.cache.util.Gateway;
public class CustomEditorRegistrationBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(final ConfigurableListableBeanFactory beanFactory) throws BeansException {
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
beanFactory.registerCustomEditor(ConnectionEndpoint[].class, ConnectionEndpointArrayToIterableConverter.class);
beanFactory.registerCustomEditor(EvictionAction.class, EvictionActionConverter.class);
beanFactory.registerCustomEditor(EvictionPolicyType.class, EvictionPolicyConverter.class);
beanFactory.registerCustomEditor(ExpirationAction.class, ExpirationActionConverter.class);
@@ -70,4 +76,13 @@ public class CustomEditorRegistrationBeanFactoryPostProcessor implements BeanFac
beanFactory.registerCustomEditor(SubscriptionEvictionPolicy.class, SubscriptionEvictionPolicyConverter.class);
}
static final class ConnectionEndpointArrayToIterableConverter extends PropertyEditorSupport
implements Converter<ConnectionEndpoint[], Iterable> {
@Override
public Iterable convert(ConnectionEndpoint[] source) {
return ConnectionEndpointList.from(source);
}
}
}

View File

@@ -27,7 +27,7 @@ public interface GemfireConstants {
static final String DEFAULT_GEMFIRE_CACHE_NAME = "gemfireCache";
static final String DEFAULT_GEMFIRE_INDEX_DEFINITION_QUERY_SERVICE = "gemfireIndexDefinitionQueryService";
static final String DEFAULT_GEMFIRE_FUNCTION_SERVICE_NAME = "gemfireFunctionService";
static final String DEFAULT_GEMFIRE_POOL_NAME = "DEFAULT";
static final String DEFAULT_GEMFIRE_POOL_NAME = "gemfirePool";
static final String DEFAULT_GEMFIRE_TRANSACTION_MANAGER_NAME = "gemfireTransactionManager";
@Deprecated

View File

@@ -12,7 +12,10 @@
*/
package org.springframework.data.gemfire.config;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.MutablePropertyValues;
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.BeanDefinitionReaderUtils;
@@ -25,37 +28,37 @@ import org.w3c.dom.Element;
* @author David Turanski
* @author John Blum
*/
public class GemfireDataSourceParser extends AbstractBeanDefinitionParser {
class GemfireDataSourceParser extends AbstractBeanDefinitionParser {
static final String SUBSCRIPTION_ENABLED_ATTRIBUTE_NAME = "subscription-enabled";
static final String SUBSCRIPTION_ENABLED_PROPERTY_NAME = "subscriptionEnabled";
protected final Log log = LogFactory.getLog(getClass());
/* (non-Javadoc)
* @see org.springframework.beans.factory.xml.AbstractBeanDefinitionParser#parseInternal(org.w3c.dom.Element, org.springframework.beans.factory.xml.ParserContext)
*/
@Override
protected AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {
AbstractBeanDefinition poolDefinition = (AbstractBeanDefinition) new PoolParser().parse(element, parserContext);
MutablePropertyValues poolProperties = poolDefinition.getPropertyValues();
poolProperties.add("name", GemfireConstants.DEFAULT_GEMFIRE_POOL_NAME);
if (!element.hasAttribute("subscription-enabled")) {
poolProperties.add("subscriptionEnabled", true);
}
parserContext.getRegistry().registerBeanDefinition(GemfireConstants.DEFAULT_GEMFIRE_POOL_NAME, poolDefinition);
AbstractBeanDefinition clientCacheDefinition = (AbstractBeanDefinition) new ClientCacheParser()
.parse(element, parserContext);
MutablePropertyValues clientCacheProperties = clientCacheDefinition.getPropertyValues();
clientCacheProperties.add("pool", poolDefinition);
BeanDefinition clientCacheDefinition = new ClientCacheParser().parse(element, parserContext);
parserContext.getRegistry().registerBeanDefinition(GemfireConstants.DEFAULT_GEMFIRE_CACHE_NAME,
clientCacheDefinition);
System.out.printf("Registered GemFire Client Cache bean '%1$s' of type '%2$s'%n",
GemfireConstants.DEFAULT_GEMFIRE_CACHE_NAME, clientCacheDefinition.getBeanClassName());
BeanDefinition poolDefinition = new PoolParser().parse(element, parserContext);
MutablePropertyValues poolProperties = poolDefinition.getPropertyValues();
if (!element.hasAttribute(SUBSCRIPTION_ENABLED_ATTRIBUTE_NAME)) {
poolProperties.add(SUBSCRIPTION_ENABLED_PROPERTY_NAME, true);
}
parserContext.getRegistry().registerBeanDefinition(GemfireConstants.DEFAULT_GEMFIRE_POOL_NAME, poolDefinition);
if (log.isDebugEnabled()) {
log.debug(String.format("Registered GemFire ClientCache bean [%1$s] of type [%2$s]%n",
GemfireConstants.DEFAULT_GEMFIRE_CACHE_NAME, clientCacheDefinition.getBeanClassName()));
}
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(
GemfireDataSourcePostProcessor.class);

View File

@@ -23,15 +23,19 @@ import java.util.regex.Pattern;
import org.springframework.beans.factory.BeanDefinitionStoreException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.MethodInvokingBean;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionReaderUtils;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.ManagedList;
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.data.gemfire.GemfireUtils;
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.data.gemfire.util.SpringUtils;
import org.springframework.util.StringUtils;
import org.springframework.util.xml.DomUtils;
import org.w3c.dom.Element;
@@ -45,8 +49,8 @@ import org.w3c.dom.Element;
*/
class PoolParser extends AbstractSingleBeanDefinitionParser {
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 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("\\$\\{.+\\}");
@@ -64,11 +68,11 @@ class PoolParser extends AbstractSingleBeanDefinitionParser {
}
@Override
protected void doParse(Element element, BeanDefinitionBuilder builder) {
protected void doParse(Element element, ParserContext parserContext, 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, "load-conditioning-interval");
ParsingUtils.setPropertyValue(element, builder, "max-connections");
ParsingUtils.setPropertyValue(element, builder, "min-connections");
ParsingUtils.setPropertyValue(element, builder, "multi-user-authentication");
@@ -102,21 +106,21 @@ class PoolParser extends AbstractSingleBeanDefinitionParser {
}
}
locators.addAll(parseLocators(element, builder));
servers.addAll(parseServers(element, builder));
locators.addAll(parseLocators(element, getRegistry(parserContext)));
servers.addAll(parseServers(element, getRegistry(parserContext)));
// 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
// 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)) {
locators.add(buildConnection(DEFAULT_HOST, String.valueOf(DEFAULT_LOCATOR_PORT), false));
servers.add(buildConnection(DEFAULT_HOST, String.valueOf(DEFAULT_SERVER_PORT), false));
}
if (!locators.isEmpty()) {
builder.addPropertyValue("locatorEndpoints", locators);
builder.addPropertyValue("locators", locators);
}
if (!servers.isEmpty()) {
builder.addPropertyValue("serverEndpoints", servers);
builder.addPropertyValue("servers", servers);
}
}
@@ -131,6 +135,17 @@ class PoolParser extends AbstractSingleBeanDefinitionParser {
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);
@@ -209,11 +224,6 @@ class PoolParser extends AbstractSingleBeanDefinitionParser {
return digits.toString();
}
/* (non-Javadoc) */
boolean isPropertyPlaceholder(String value) {
return PROPERTY_PLACEHOLDER_PATTERN.matcher(value).matches();
}
/* (non-Javadoc) */
BeanDefinition parseLocator(Element element) {
return buildConnection(element.getAttribute(HOST_ATTRIBUTE_NAME),
@@ -221,13 +231,24 @@ class PoolParser extends AbstractSingleBeanDefinitionParser {
}
/* (non-Javadoc) */
List<BeanDefinition> parseLocators(Element element, BeanDefinitionBuilder builder) {
List<BeanDefinition> parseLocators(Element element, BeanDefinitionRegistry registry) {
List<BeanDefinition> beanDefinitions = Collections.emptyList();
String locatorsAttributeValue = element.getAttribute(LOCATORS_ATTRIBUTE_NAME);
if (isPropertyPlaceholder(locatorsAttributeValue)) {
builder.addPropertyValue("locatorEndpointList", buildConnections(locatorsAttributeValue, false));
BeanDefinitionBuilder addLocatorsMethodInvokingBeanBuilder = BeanDefinitionBuilder.genericBeanDefinition(
MethodInvokingBean.class);
addLocatorsMethodInvokingBeanBuilder.addPropertyReference("targetObject", resolveDereferencedId(element));
addLocatorsMethodInvokingBeanBuilder.addPropertyValue("targetMethod", "addLocators");
addLocatorsMethodInvokingBeanBuilder.addPropertyValue("arguments",
buildConnections(locatorsAttributeValue, false));
AbstractBeanDefinition addLocatorsMethodInvokingBean =
addLocatorsMethodInvokingBeanBuilder.getBeanDefinition();
BeanDefinitionReaderUtils.registerWithGeneratedName(addLocatorsMethodInvokingBean, registry);
}
else {
beanDefinitions = parseConnections(locatorsAttributeValue, false);
@@ -243,13 +264,24 @@ class PoolParser extends AbstractSingleBeanDefinitionParser {
}
/* (non-Javadoc) */
List<BeanDefinition> parseServers(Element element, BeanDefinitionBuilder builder) {
List<BeanDefinition> parseServers(Element element, BeanDefinitionRegistry registry) {
List<BeanDefinition> beanDefinitions = Collections.emptyList();
String serversAttributeValue = element.getAttribute(SERVERS_ATTRIBUTE_NAME);
if (isPropertyPlaceholder(serversAttributeValue)) {
builder.addPropertyValue("serverEndpointList", buildConnections(serversAttributeValue, true));
BeanDefinitionBuilder addServersMethodInvokingBeanBuilder = BeanDefinitionBuilder.genericBeanDefinition(
MethodInvokingBean.class);
addServersMethodInvokingBeanBuilder.addPropertyReference("targetObject", resolveDereferencedId(element));
addServersMethodInvokingBeanBuilder.addPropertyValue("targetMethod", "addServers");
addServersMethodInvokingBeanBuilder.addPropertyValue("arguments",
buildConnections(serversAttributeValue, true));
AbstractBeanDefinition addServersMethodInvokingBean =
addServersMethodInvokingBeanBuilder.getBeanDefinition();
BeanDefinitionReaderUtils.registerWithGeneratedName(addServersMethodInvokingBean, registry);
}
else {
beanDefinitions = parseConnections(serversAttributeValue, true);
@@ -258,6 +290,17 @@ class PoolParser extends AbstractSingleBeanDefinitionParser {
return beanDefinitions;
}
/* (non-Javadoc) */
String resolveId(Element element) {
String id = element.getAttribute(ID_ATTRIBUTE);
return (StringUtils.hasText(id) ? id : GemfireConstants.DEFAULT_GEMFIRE_POOL_NAME);
}
/* (non-Javadoc) */
String resolveDereferencedId(Element element) {
return SpringUtils.dereferenceBean(resolveId(element));
}
/* (non-Javadoc) */
@Override
protected String resolveId(Element element, AbstractBeanDefinition definition, ParserContext parserContext)
@@ -267,8 +310,6 @@ class PoolParser extends AbstractSingleBeanDefinitionParser {
if (!StringUtils.hasText(id)) {
id = GemfireConstants.DEFAULT_GEMFIRE_POOL_NAME;
// for backward compatibility
parserContext.getRegistry().registerAlias(GemfireConstants.DEFAULT_GEMFIRE_POOL_NAME, "gemfirePool");
parserContext.getRegistry().registerAlias(GemfireConstants.DEFAULT_GEMFIRE_POOL_NAME, "gemfire-pool");
}

View File

@@ -24,6 +24,9 @@ import java.util.concurrent.Executor;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
@@ -31,6 +34,8 @@ import org.springframework.context.SmartLifecycle;
import org.springframework.core.task.SimpleAsyncTaskExecutor;
import org.springframework.core.task.TaskExecutor;
import org.springframework.data.gemfire.GemfireQueryException;
import org.springframework.data.gemfire.GemfireUtils;
import org.springframework.data.gemfire.config.GemfireConstants;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.ErrorHandler;
@@ -67,7 +72,8 @@ import com.gemstone.gemfire.cache.query.QueryService;
* @see com.gemstone.gemfire.cache.query.QueryService
*/
@SuppressWarnings("unused")
public class ContinuousQueryListenerContainer implements BeanNameAware, InitializingBean, DisposableBean, SmartLifecycle {
public class ContinuousQueryListenerContainer implements BeanFactoryAware, BeanNameAware,
InitializingBean, DisposableBean, SmartLifecycle {
// Default Thread name prefix is "ContinuousQueryListenerContainer-".
public static final String DEFAULT_THREAD_NAME_PREFIX = String.format("%1$s-", ClassUtils.getShortName(
@@ -81,6 +87,8 @@ public class ContinuousQueryListenerContainer implements BeanNameAware, Initiali
private int phase = Integer.MAX_VALUE;
private BeanFactory beanFactory;
private ErrorHandler errorHandler;
private Executor taskExecutor;
@@ -97,7 +105,7 @@ public class ContinuousQueryListenerContainer implements BeanNameAware, Initiali
private String poolName;
public void afterPropertiesSet() {
initQueryService();
initQueryService(eagerlyInitializePool(resolvePoolName()));
initExecutor();
initContinuousQueries(continuousQueryDefinitions);
initialized = true;
@@ -107,12 +115,36 @@ public class ContinuousQueryListenerContainer implements BeanNameAware, Initiali
}
}
private void initQueryService() {
if (StringUtils.hasText(poolName)) {
Pool pool = PoolManager.find(poolName);
Assert.notNull(pool, String.format("No GemFire Pool with name '%1$s' was found.", poolName));
queryService = pool.getQueryService();
/* (non-Javadoc) */
private String resolvePoolName() {
String poolName = this.poolName;
if (!StringUtils.hasText(poolName)) {
String defaultPoolName = GemfireConstants.DEFAULT_GEMFIRE_POOL_NAME;
poolName = (beanFactory != null && beanFactory.containsBean(defaultPoolName) ? defaultPoolName
: GemfireUtils.DEFAULT_POOL_NAME);
}
return poolName;
}
/* (non-Javadoc) */
private String eagerlyInitializePool(String poolName) {
try {
if (beanFactory != null && beanFactory.isTypeMatch(poolName, Pool.class)) {
beanFactory.getBean(poolName, Pool.class);
}
}
catch (BeansException ignore) {
Assert.notNull(PoolManager.find(poolName), String.format("No GemFire Pool with name [%1$s] was found.",
poolName));
}
return poolName;
}
private void initQueryService(String poolName) {
queryService = PoolManager.find(poolName).getQueryService();
}
private void initExecutor() {
@@ -281,6 +313,17 @@ public class ContinuousQueryListenerContainer implements BeanNameAware, Initiali
this.autoStartup = autoStartup;
}
/**
* Sets the {@link BeanFactory} containing this bean.
*
* @param beanFactory the Spring {@link BeanFactory} containing this bean.
* @throws BeansException if an initialization error occurs.
*/
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
}
/**
* Set the name of the bean in the bean factory that created this bean.
* <p>Invoked after population of normal bean properties but before an

View File

@@ -150,6 +150,18 @@ public class ConnectionEndpoint implements Cloneable, Comparable<ConnectionEndpo
return port;
}
/**
* Converts this {@link ConnectionEndpoint} into an {@link InetSocketAddress} representation.
*
* @return an {@link InetSocketAddress} representation of this {@link ConnectionEndpoint}.
* @see java.net.InetSocketAddress
* @see #getHost()
* @see #getPort()
*/
public InetSocketAddress toInetSocketAddress() {
return new InetSocketAddress(getHost(), getPort());
}
/* (non-Javadoc) */
@Override
@SuppressWarnings("all")

View File

@@ -17,6 +17,7 @@
package org.springframework.data.gemfire.support;
import java.net.InetSocketAddress;
import java.util.AbstractList;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -25,6 +26,7 @@ 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.
@@ -36,15 +38,28 @@ import org.springframework.data.gemfire.util.CollectionUtils;
* @since 1.6.3
*/
@SuppressWarnings("unused")
public class ConnectionEndpointList implements Iterable<ConnectionEndpoint> {
public class ConnectionEndpointList extends AbstractList<ConnectionEndpoint> {
private final List<ConnectionEndpoint> connectionEndpoints;
/**
* Converts the array of InetSocketAddresses into an instance of ConnectionEndpointList.
* Factory method for creating a {@link ConnectionEndpointList} from an array of {@link ConnectionEndpoint}s.
*
* @param socketAddresses the array of InetSocketAddresses used to initialize an instance of ConnectionEndpointList.
* @return a ConnectionEndpointList representing the array of InetSocketAddresses.
* @param connectionEndpoints the array of {@link ConnectionEndpoint}s used to initialize
* the {@link ConnectionEndpointList}.
* @return a {@link ConnectionEndpointList} initialized with the array of {@link ConnectionEndpoint}s.
* @see org.springframework.data.gemfire.support.ConnectionEndpoint
*/
public static ConnectionEndpointList from(ConnectionEndpoint... connectionEndpoints) {
return new ConnectionEndpointList(connectionEndpoints);
}
/**
* Converts an array of {@link InetSocketAddress} into an instance of {@link ConnectionEndpointList}.
*
* @param socketAddresses the array of {@link InetSocketAddress} used to initialize
* an instance of {@link ConnectionEndpointList}.
* @return a {@link ConnectionEndpointList} initialized with the array of {@link InetSocketAddress}.
* @see java.net.InetSocketAddress
* @see #from(Iterable)
*/
@@ -53,11 +68,13 @@ public class ConnectionEndpointList implements Iterable<ConnectionEndpoint> {
}
/**
* Converts the Iterable collection of InetSocketAddresses into an instance of ConnectionEndpointList.
* Converts an {@link Iterable} collection of {@link InetSocketAddress} into an instance
* of {@link ConnectionEndpointList}.
*
* @param socketAddresses in Iterable collection of InetSocketAddresses used to initialize an instance
* of ConnectionEndpointList.
* @return a ConnectionEndpointList representing the array of InetSocketAddresses.
* @param socketAddresses in {@link Iterable} collection of {@link InetSocketAddress} used to initialize
* an instance of {@link ConnectionEndpointList}.
* @return a {@link ConnectionEndpointList} initialized with the array of {@link InetSocketAddress}.
* @see java.lang.Iterable
* @see java.net.InetSocketAddress
*/
public static ConnectionEndpointList from(Iterable<InetSocketAddress> socketAddresses) {
@@ -119,6 +136,12 @@ public class ConnectionEndpointList implements Iterable<ConnectionEndpoint> {
add(connectionEndpoints);
}
/* (non-Javadoc) */
@Override
public boolean add(ConnectionEndpoint connectionEndpoint) {
return (add(SpringUtils.toArray(connectionEndpoint)) == this);
}
/**
* Adds the array of ConnectionEndpoints to this list.
*
@@ -148,6 +171,14 @@ public class ConnectionEndpointList implements Iterable<ConnectionEndpoint> {
return this;
}
/**
* Clears the current list of {@link ConnectionEndpoint}s.
*/
@Override
public void clear() {
this.connectionEndpoints.clear();
}
/**
* Finds all ConnectionEndpoints in this list with the specified hostname.
*
@@ -186,17 +217,75 @@ public class ConnectionEndpointList implements Iterable<ConnectionEndpoint> {
return new ConnectionEndpointList(connectionEndpoints);
}
/**
* Finds the first {@link ConnectionEndpoint} in the collection with the given host.
*
* @param host a String indicating the hostname of the {@link ConnectionEndpoint} to find.
* @return the first {@link ConnectionEndpoint} in this collection with the given host,
* or null if no {@link ConnectionEndpoint} exists with the given hostname.
* @see #findBy(String)
*/
public ConnectionEndpoint findOne(String host) {
ConnectionEndpointList connectionEndpoints = findBy(host);
return (connectionEndpoints.isEmpty() ? null : connectionEndpoints.connectionEndpoints.get(0));
}
/**
* Finds the first {@link ConnectionEndpoint} in the collection with the given port.
*
* @param port an integer indicating the port number of the {@link ConnectionEndpoint} to find.
* @return the first {@link ConnectionEndpoint} in this collection with the given port,
* or null if no {@link ConnectionEndpoint} exists with the given port number.
* @see #findBy(int)
*/
public ConnectionEndpoint findOne(int port) {
ConnectionEndpointList connectionEndpoints = findBy(port);
return (connectionEndpoints.isEmpty() ? null : connectionEndpoints.connectionEndpoints.get(0));
}
/**
* Gets the {@link ConnectionEndpoint} at the given index in this list.
*
* @param index an integer value indicating the index of the {@link ConnectionEndpoint} of interest.
* @return the {@link ConnectionEndpoint} at index in this list.
* @throws IndexOutOfBoundsException if the index is not within the bounds of this list.
* @see org.springframework.data.gemfire.support.ConnectionEndpoint
* @see java.util.AbstractList#get(int)
*/
@Override
public ConnectionEndpoint get(int index) {
return connectionEndpoints.get(index);
}
/**
* Sets the element at the given index in this list to the given {@link ConnectionEndpoint}.
*
* @param index the index in the list at which to set the {@link ConnectionEndpoint}.
* @param element the {@link ConnectionEndpoint} to set in this list at the given index.
* @return the old {@link ConnectionEndpoint} at index in this list or null if no {@link ConnectionEndpoint}
* at index existed.
* @throws IndexOutOfBoundsException if the index is not within the bounds of this list.
* @see org.springframework.data.gemfire.support.ConnectionEndpoint
* @see java.util.AbstractList#set(int, Object)
*/
@Override
public ConnectionEndpoint set(int index, ConnectionEndpoint element) {
return connectionEndpoints.set(index, element);
}
/**
* Determines whether this collection contains any ConnectionEndpoints.
*
* @return a boolean value indicating whether this collection contains any ConnectionEndpoints.
*/
@Override
public boolean isEmpty() {
return connectionEndpoints.isEmpty();
}
/* (non-Javadoc) */
@Override
@SuppressWarnings("all")
public Iterator<ConnectionEndpoint> iterator() {
return Collections.unmodifiableList(connectionEndpoints).iterator();
}
@@ -206,10 +295,40 @@ public class ConnectionEndpointList implements Iterable<ConnectionEndpoint> {
*
* @return an integer value indicating the number of ConnectionEndpoints contained in this collection.
*/
@Override
public int size() {
return connectionEndpoints.size();
}
/**
* Converts this collection of {@link ConnectionEndpoint}s into an array of {@link ConnectionEndpoint}s.
*
* @return an array of {@link ConnectionEndpoint}s representing this collection.
*/
@Override
@SuppressWarnings("all")
public ConnectionEndpoint[] toArray() {
return connectionEndpoints.toArray(new ConnectionEndpoint[connectionEndpoints.size()]);
}
/**
* Converts this collection of {@link ConnectionEndpoint}s into a {@link List} of {@link InetSocketAddress}es.
*
* @return a {@link List} of {@link InetSocketAddress}es representing this collection of {@link ConnectionEndpoint}s.
* @see org.springframework.data.gemfire.support.ConnectionEndpoint#toInetSocketAddress()
* @see java.net.InetSocketAddress
* @see java.util.List
*/
public List<InetSocketAddress> toInetSocketAddresses() {
List<InetSocketAddress> inetSocketAddresses = new ArrayList<InetSocketAddress>(size());
for (ConnectionEndpoint connectionEndpoint : this) {
inetSocketAddresses.add(connectionEndpoint.toInetSocketAddress());
}
return inetSocketAddresses;
}
/* (non-Javadoc) */
@Override
public String toString() {

View File

@@ -0,0 +1,129 @@
/*
* Copyright 2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.springframework.data.gemfire.util;
import org.springframework.util.StringUtils;
import com.gemstone.gemfire.cache.Cache;
import com.gemstone.gemfire.cache.CacheClosedException;
import com.gemstone.gemfire.cache.CacheFactory;
import com.gemstone.gemfire.cache.GemFireCache;
import com.gemstone.gemfire.cache.client.ClientCache;
import com.gemstone.gemfire.cache.client.ClientCacheFactory;
import com.gemstone.gemfire.distributed.DistributedSystem;
import com.gemstone.gemfire.internal.cache.GemFireCacheImpl;
/**
* CacheUtils is an abstract utility class encapsulating common operations for working with GemFire Cache
* and ClientCache instances.
*
* @author John Blum
* @see org.springframework.data.gemfire.util.DistributedSystemUtils
* @see com.gemstone.gemfire.cache.Cache
* @see com.gemstone.gemfire.cache.CacheFactory
* @see com.gemstone.gemfire.cache.GemFireCache
* @see com.gemstone.gemfire.cache.Region
* @see com.gemstone.gemfire.cache.client.ClientCache
* @see com.gemstone.gemfire.cache.client.ClientCacheFactory
* @see com.gemstone.gemfire.distributed.DistributedSystem
* @see com.gemstone.gemfire.internal.cache.GemFireCacheImpl
* @since 1.8.0
*/
@SuppressWarnings("unused")
public abstract class CacheUtils extends DistributedSystemUtils {
public static final String DEFAULT_POOL_NAME = "DEFAULT";
/* (non-Javadoc) */
@SuppressWarnings("all")
public static boolean isClient(GemFireCache cache) {
boolean client = (cache instanceof ClientCache);
if (cache instanceof GemFireCacheImpl) {
client &= ((GemFireCacheImpl) cache).isClient();
}
return client;
}
/* (non-Javadoc) */
public static boolean isDurable(ClientCache clientCache) {
DistributedSystem distributedSystem = getDistributedSystem(clientCache);
// NOTE technically the following code snippet would be more useful/valuable but is not "testable"!
//((InternalDistributedSystem) distributedSystem).getConfig().getDurableClientId();
return (isConnected(distributedSystem) && StringUtils.hasText(distributedSystem.getProperties()
.getProperty(DURABLE_CLIENT_ID_PROPERTY_NAME, null)));
}
/* (non-Javadoc) */
@SuppressWarnings("all")
public static boolean isPeer(GemFireCache cache) {
boolean peer = (cache instanceof Cache);
if (cache instanceof GemFireCacheImpl) {
peer &= !((GemFireCacheImpl) cache).isClient();
}
return peer;
}
/* (non-Javadoc) */
public static boolean closeCache() {
try {
CacheFactory.getAnyInstance().close();
return true;
}
catch (Exception ignore) {
return false;
}
}
/* (non-Javadoc) */
public static boolean closeClientCache() {
try {
ClientCacheFactory.getAnyInstance().close();
return true;
}
catch (Exception ignore) {
return false;
}
}
/* (non-Javadoc) */
public static Cache getCache() {
try {
return CacheFactory.getAnyInstance();
}
catch (CacheClosedException ignore) {
return null;
}
}
/* (non-Javadoc) */
public static ClientCache getClientCache() {
try {
return ClientCacheFactory.getAnyInstance();
}
catch (CacheClosedException ignore) {
return null;
}
}
}

View File

@@ -34,10 +34,13 @@ import com.gemstone.gemfire.internal.DistributionLocator;
* @author John Blum
* @see com.gemstone.gemfire.cache.GemFireCache
* @see com.gemstone.gemfire.distributed.DistributedSystem
* @see com.gemstone.gemfire.distributed.internal.DistributionConfig
* @see com.gemstone.gemfire.distributed.internal.InternalDistributedSystem
* @see com.gemstone.gemfire.internal.DistributionLocator
* @since 1.7.0
*/
@SuppressWarnings("unused")
public abstract class DistributedSystemUtils {
public abstract class DistributedSystemUtils extends SpringUtils {
public static final int DEFAULT_CACHE_SERVER_PORT = CacheServer.DEFAULT_PORT;
public static final int DEFAULT_LOCATOR_PORT = DistributionLocator.DEFAULT_LOCATOR_PORT;
@@ -46,7 +49,9 @@ public abstract class DistributedSystemUtils {
public static final String DURABLE_CLIENT_TIMEOUT_PROPERTY_NAME = DistributionConfig.DURABLE_CLIENT_TIMEOUT_NAME;
/* (non-Javadoc) */
public static Properties configureDurableClient(Properties gemfireProperties, String durableClientId, Integer durableClientTimeout) {
public static Properties configureDurableClient(Properties gemfireProperties,
String durableClientId, Integer durableClientTimeout) {
if (StringUtils.hasText(durableClientId)) {
Assert.notNull(gemfireProperties, "gemfireProperties must not be null");

View File

@@ -0,0 +1,68 @@
/*
* Copyright 2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.springframework.data.gemfire.util;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.util.StringUtils;
/**
* SpringUtils is a utility class encapsulating common functionality on objects and other class types.
*
* @author John Blum
* @since 1.8.0
*/
@SuppressWarnings("unused")
public abstract class SpringUtils {
/* (non-Javadoc) */
public static String defaultIfEmpty(String value, String defaultValue) {
return (StringUtils.hasText(value) ? value : defaultValue);
}
/* (non-Javadoc) */
public static <T> T defaultIfNull(T value, T defaultValue) {
return (value != null ? value : defaultValue);
}
/* (non-Javadoc) */
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;
}
}