SGF-63
+ split ClientRegionFactory from RegionFactoryBean to cope with the different APIs used for configuring regions
This commit is contained in:
@@ -22,6 +22,8 @@ import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.data.gemfire.client.ClientRegionFactoryBean;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
@@ -32,6 +34,7 @@ import com.gemstone.gemfire.cache.CacheListener;
|
||||
import com.gemstone.gemfire.cache.CacheLoader;
|
||||
import com.gemstone.gemfire.cache.CacheWriter;
|
||||
import com.gemstone.gemfire.cache.DataPolicy;
|
||||
import com.gemstone.gemfire.cache.GemFireCache;
|
||||
import com.gemstone.gemfire.cache.Region;
|
||||
import com.gemstone.gemfire.cache.RegionAttributes;
|
||||
import com.gemstone.gemfire.cache.RegionFactory;
|
||||
@@ -41,6 +44,9 @@ import com.gemstone.gemfire.cache.Scope;
|
||||
* FactoryBean for creating generic GemFire {@link Region}s. Will try to first locate the region (by name)
|
||||
* and, in case none if found, proceed to creating one using the given settings.
|
||||
*
|
||||
* Note that this factory bean allows for very flexible creation of GemFire {@link Region}. For "client" regions
|
||||
* however, see {@link ClientRegionFactoryBean} which offers easier configuration and defaults.
|
||||
*
|
||||
* @author Costin Leau
|
||||
*/
|
||||
public class RegionFactoryBean<K, V> extends RegionLookupFactoryBean<K, V> implements DisposableBean {
|
||||
@@ -68,12 +74,16 @@ public class RegionFactoryBean<K, V> extends RegionLookupFactoryBean<K, V> imple
|
||||
|
||||
|
||||
@Override
|
||||
protected Region<K, V> lookupFallback(Cache cache, String regionName) throws Exception {
|
||||
protected Region<K, V> lookupFallback(GemFireCache cache, String regionName) throws Exception {
|
||||
Assert.isTrue(cache instanceof Cache, "Unable to create regions from " + cache);
|
||||
|
||||
Cache c = (Cache) cache;
|
||||
|
||||
if (attributes != null)
|
||||
AttributesFactory.validateAttributes(attributes);
|
||||
|
||||
RegionFactory<K, V> regionFactory = (attributes != null ? cache.createRegionFactory(attributes)
|
||||
: cache.<K, V> createRegionFactory());
|
||||
final RegionFactory<K, V> regionFactory = (attributes != null ? c.createRegionFactory(attributes)
|
||||
: c.<K, V> createRegionFactory());
|
||||
|
||||
if (!ObjectUtils.isEmpty(cacheListeners)) {
|
||||
for (CacheListener<K, V> listener : cacheListeners) {
|
||||
|
||||
@@ -25,7 +25,7 @@ import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.gemstone.gemfire.cache.Cache;
|
||||
import com.gemstone.gemfire.cache.GemFireCache;
|
||||
import com.gemstone.gemfire.cache.Region;
|
||||
|
||||
/**
|
||||
@@ -40,7 +40,7 @@ public class RegionLookupFactoryBean<K, V> implements FactoryBean<Region<K, V>>,
|
||||
protected final Log log = LogFactory.getLog(getClass());
|
||||
|
||||
private String beanName;
|
||||
private Cache cache;
|
||||
private GemFireCache cache;
|
||||
private String name;
|
||||
|
||||
Region<K, V> region;
|
||||
@@ -68,7 +68,7 @@ public class RegionLookupFactoryBean<K, V> implements FactoryBean<Region<K, V>>,
|
||||
* @param regionName region name
|
||||
* @throws Exception
|
||||
*/
|
||||
protected Region<K, V> lookupFallback(Cache cache, String regionName) throws Exception {
|
||||
protected Region<K, V> lookupFallback(GemFireCache cache, String regionName) throws Exception {
|
||||
throw new BeanInitializationException("Cannot find region [" + regionName + "] in cache " + cache);
|
||||
}
|
||||
|
||||
@@ -94,7 +94,7 @@ public class RegionLookupFactoryBean<K, V> implements FactoryBean<Region<K, V>>,
|
||||
* @see org.springframework.data.gemfire.CacheFactoryBean
|
||||
* @param cache the cache to set
|
||||
*/
|
||||
public void setCache(Cache cache) {
|
||||
public void setCache(GemFireCache cache) {
|
||||
this.cache = cache;
|
||||
}
|
||||
|
||||
|
||||
@@ -16,16 +16,27 @@
|
||||
|
||||
package org.springframework.data.gemfire.client;
|
||||
|
||||
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.data.gemfire.RegionFactoryBean;
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.data.gemfire.RegionLookupFactoryBean;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.gemstone.gemfire.cache.AttributesFactory;
|
||||
import com.gemstone.gemfire.cache.CacheClosedException;
|
||||
import com.gemstone.gemfire.cache.CacheListener;
|
||||
import com.gemstone.gemfire.cache.DataPolicy;
|
||||
import com.gemstone.gemfire.cache.GemFireCache;
|
||||
import com.gemstone.gemfire.cache.Region;
|
||||
import com.gemstone.gemfire.cache.RegionAttributes;
|
||||
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;
|
||||
|
||||
/**
|
||||
@@ -33,13 +44,110 @@ import com.gemstone.gemfire.cache.client.Pool;
|
||||
*
|
||||
* @author Costin Leau
|
||||
*/
|
||||
public class ClientRegionFactoryBean<K, V> extends RegionFactoryBean<K, V> implements BeanFactoryAware {
|
||||
public class ClientRegionFactoryBean<K, V> extends RegionLookupFactoryBean<K, V> implements BeanFactoryAware,
|
||||
DisposableBean {
|
||||
|
||||
private static final Log log = LogFactory.getLog(ClientRegionFactoryBean.class);
|
||||
|
||||
private boolean destroy = false;
|
||||
private boolean close = true;
|
||||
private Resource snapshot;
|
||||
|
||||
private CacheListener<K, V> cacheListeners[];
|
||||
private Interest<K>[] interests;
|
||||
private String poolName;
|
||||
private BeanFactory beanFactory;
|
||||
private ClientRegionShortcut shortcut = null;
|
||||
private DataPolicy dataPolicy;
|
||||
|
||||
private RegionAttributes<K, V> attributes;
|
||||
|
||||
private Region<K, V> region;
|
||||
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
super.afterPropertiesSet();
|
||||
postProcess(region);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Region<K, V> lookupFallback(GemFireCache cache, String regionName) throws Exception {
|
||||
Assert.isTrue(cache instanceof ClientCache, "Unable to create regions from " + cache);
|
||||
|
||||
ClientCache c = (ClientCache) cache;
|
||||
|
||||
// first look at shortcut
|
||||
ClientRegionShortcut s = null;
|
||||
|
||||
if (shortcut == null) {
|
||||
if (dataPolicy != null) {
|
||||
if (DataPolicy.EMPTY.equals(dataPolicy)) {
|
||||
s = ClientRegionShortcut.PROXY;
|
||||
}
|
||||
else if (DataPolicy.PERSISTENT_REPLICATE.equals(dataPolicy)) {
|
||||
s = ClientRegionShortcut.LOCAL_PERSISTENT;
|
||||
}
|
||||
}
|
||||
s = ClientRegionShortcut.LOCAL;
|
||||
}
|
||||
|
||||
ClientRegionFactory<K, V> factory = c.createClientRegionFactory(s);
|
||||
|
||||
// map the attributes onto the client
|
||||
if (attributes != null) {
|
||||
CacheListener<K, V>[] listeners = attributes.getCacheListeners();
|
||||
if (!ObjectUtils.isEmpty(cacheListeners)) {
|
||||
for (CacheListener<K, V> listener : cacheListeners) {
|
||||
factory.addCacheListener(listener);
|
||||
}
|
||||
}
|
||||
factory.setCloningEnabled(attributes.getCloningEnabled());
|
||||
factory.setConcurrencyLevel(attributes.getConcurrencyLevel());
|
||||
factory.setCustomEntryIdleTimeout(attributes.getCustomEntryIdleTimeout());
|
||||
factory.setCustomEntryTimeToLive(attributes.getCustomEntryTimeToLive());
|
||||
factory.setDiskStoreName(attributes.getDiskStoreName());
|
||||
factory.setDiskSynchronous(attributes.isDiskSynchronous());
|
||||
factory.setEntryIdleTimeout(attributes.getEntryIdleTimeout());
|
||||
factory.setEntryTimeToLive(attributes.getEntryTimeToLive());
|
||||
factory.setEvictionAttributes(attributes.getEvictionAttributes());
|
||||
factory.setInitialCapacity(attributes.getInitialCapacity());
|
||||
factory.setKeyConstraint(attributes.getKeyConstraint());
|
||||
factory.setLoadFactor(attributes.getLoadFactor());
|
||||
factory.setPoolName(attributes.getPoolName());
|
||||
factory.setRegionIdleTimeout(attributes.getRegionIdleTimeout());
|
||||
factory.setRegionTimeToLive(attributes.getRegionTimeToLive());
|
||||
factory.setStatisticsEnabled(attributes.getStatisticsEnabled());
|
||||
factory.setValueConstraint(attributes.getValueConstraint());
|
||||
}
|
||||
|
||||
if (!ObjectUtils.isEmpty(cacheListeners)) {
|
||||
for (CacheListener<K, V> listener : cacheListeners) {
|
||||
factory.addCacheListener(listener);
|
||||
}
|
||||
}
|
||||
|
||||
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("Found bean definition for pool '" + poolName + "'. Eagerly initializing it...");
|
||||
}
|
||||
beanFactory.getBean(poolName, Pool.class);
|
||||
}
|
||||
|
||||
factory.setPoolName(poolName);
|
||||
}
|
||||
|
||||
Region<K, V> reg = factory.create(regionName);
|
||||
log.info("Created new cache region [" + regionName + "]");
|
||||
if (snapshot != null) {
|
||||
reg.loadSnapshot(snapshot.getInputStream());
|
||||
}
|
||||
|
||||
return reg;
|
||||
}
|
||||
|
||||
protected void postProcess(Region<K, V> region) {
|
||||
if (!ObjectUtils.isEmpty(interests)) {
|
||||
for (Interest<K> interest : interests) {
|
||||
@@ -54,22 +162,6 @@ public class ClientRegionFactoryBean<K, V> extends RegionFactoryBean<K, V> imple
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void postProcess(AttributesFactory<K, V> attrFactory) {
|
||||
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("Found bean definition for pool '" + poolName + "'. Eagerly initializing it...");
|
||||
}
|
||||
beanFactory.getBean(poolName, Pool.class);
|
||||
}
|
||||
|
||||
attrFactory.setPoolName(poolName);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() throws Exception {
|
||||
Region<K, V> region = getObject();
|
||||
// unregister interests
|
||||
@@ -89,7 +181,21 @@ public class ClientRegionFactoryBean<K, V> extends RegionFactoryBean<K, V> imple
|
||||
log.warn("Cannot unregister cache interests", ex);
|
||||
}
|
||||
|
||||
super.destroy();
|
||||
if (region != null) {
|
||||
if (close) {
|
||||
if (!region.getCache().isClosed()) {
|
||||
try {
|
||||
region.close();
|
||||
} catch (CacheClosedException cce) {
|
||||
// nothing to see folks, move on.
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (destroy) {
|
||||
region.destroyRegion();
|
||||
}
|
||||
}
|
||||
region = null;
|
||||
}
|
||||
|
||||
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
|
||||
@@ -132,4 +238,92 @@ public class ClientRegionFactoryBean<K, V> extends RegionFactoryBean<K, V> imple
|
||||
Assert.notNull(pool, "pool cannot be null");
|
||||
setPoolName(pool.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the client using a GemFire {@link ClientRegionShortcut}.
|
||||
* The recommended way for creating clients since it covers all the major scenarios with minimal
|
||||
* configuration.
|
||||
*
|
||||
* @param shortcut
|
||||
*/
|
||||
public void setShortcut(ClientRegionShortcut shortcut) {
|
||||
this.shortcut = shortcut;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether the region referred by this factory bean,
|
||||
* will be destroyed on shutdown (default false).
|
||||
* Note: destroy and close are mutually exclusive. Enabling one will automatically disable the other.
|
||||
*
|
||||
* @param destroy whether or not to destroy the region
|
||||
*
|
||||
* @see #setClose(boolean)
|
||||
*/
|
||||
public void setDestroy(boolean destroy) {
|
||||
this.destroy = destroy;
|
||||
|
||||
if (destroy) {
|
||||
close = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether the region referred by this factory bean,
|
||||
* will be closed on shutdown (default true).
|
||||
* Note: destroy and close are mutually exclusive. Enabling one will automatically disable the other.
|
||||
*
|
||||
* @param close whether to close or not the region
|
||||
* @see #setDestroy(boolean)
|
||||
*/
|
||||
public void setClose(boolean close) {
|
||||
this.close = close;
|
||||
if (close) {
|
||||
destroy = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the snapshots used for loading a newly <i>created</i> region.
|
||||
* That is, the snapshot will be used <i>only</i> when a new region is created - if the region
|
||||
* already exists, no loading will be performed.
|
||||
*
|
||||
* @see #setName(String)
|
||||
* @param snapshot the snapshot to set
|
||||
*/
|
||||
public void setSnapshot(Resource snapshot) {
|
||||
this.snapshot = snapshot;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the cache listeners used for the region used by this factory.
|
||||
* Used only when a new region is created.Overrides the settings
|
||||
* specified through {@link #setAttributes(RegionAttributes)}.
|
||||
*
|
||||
* @param cacheListeners the cacheListeners to set on a newly created region
|
||||
*/
|
||||
public void setCacheListeners(CacheListener<K, V>[] cacheListeners) {
|
||||
this.cacheListeners = cacheListeners;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the data policy. Used only when a new region is created.
|
||||
*
|
||||
* @param dataPolicy the region data policy
|
||||
*/
|
||||
public void setDataPolicy(DataPolicy dataPolicy) {
|
||||
this.dataPolicy = dataPolicy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the region attributes used for the region used by this factory.
|
||||
* Allows maximum control in specifying the region settings.
|
||||
* Used only when a new region is created.
|
||||
* Note that using this method allows for advanced customization of the region - while it provides a lot of flexibility,
|
||||
* note that it's quite easy to create misconfigured regions (especially in a client/server scenario).
|
||||
*
|
||||
* @param attributes the attributes to set on a newly created region
|
||||
*/
|
||||
public void setAttributes(RegionAttributes<K, V> attributes) {
|
||||
this.attributes = attributes;
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,6 @@
|
||||
package org.springframework.data.gemfire.config;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.ManagedList;
|
||||
@@ -30,10 +29,7 @@ import org.springframework.util.StringUtils;
|
||||
import org.springframework.util.xml.DomUtils;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import com.gemstone.gemfire.cache.CacheFactory;
|
||||
import com.gemstone.gemfire.cache.DataPolicy;
|
||||
import com.gemstone.gemfire.cache.Region;
|
||||
import com.gemstone.gemfire.cache.Scope;
|
||||
|
||||
/**
|
||||
* Parser for <client-region;gt; definitions.
|
||||
@@ -57,11 +53,11 @@ class ClientRegionParser extends AliasReplacingBeanDefinitionParser {
|
||||
// setting the cache/DS to a be 'loner' isn't feasible
|
||||
// so to prevent both client and p2p communication in the region,
|
||||
// the scope is fixed to local
|
||||
builder.addPropertyValue("scope", Scope.LOCAL);
|
||||
|
||||
ParsingUtils.setPropertyValue(element, builder, "data-policy", "dataPolicy");
|
||||
ParsingUtils.setPropertyValue(element, builder, "name", "name");
|
||||
ParsingUtils.setPropertyValue(element, builder, "pool-name", "poolName");
|
||||
ParsingUtils.setPropertyValue(element, builder, "shortcut", "shortcut");
|
||||
|
||||
|
||||
// set the persistent policy
|
||||
String attr = element.getAttribute("persistent");
|
||||
@@ -70,15 +66,8 @@ class ClientRegionParser extends AliasReplacingBeanDefinitionParser {
|
||||
|
||||
if (Boolean.parseBoolean(attr)) {
|
||||
// check first for GemFire 6.5
|
||||
if (ConcurrentMap.class.isAssignableFrom(Region.class)) {
|
||||
builder.addPropertyValue("dataPolicy", DataPolicy.PERSISTENT_REPLICATE);
|
||||
frozenDataPolicy = true;
|
||||
}
|
||||
else {
|
||||
parserContext.getReaderContext().error(
|
||||
"Can define persistent partitions only from GemFire 6.5 onwards - current version is ["
|
||||
+ CacheFactory.getVersion() + "]", element);
|
||||
}
|
||||
builder.addPropertyValue("dataPolicy", DataPolicy.PERSISTENT_REPLICATE);
|
||||
frozenDataPolicy = true;
|
||||
}
|
||||
|
||||
attr = element.getAttribute("cache-ref");
|
||||
|
||||
Reference in New Issue
Block a user