SGF-547 - Configure Eviction with annotations.
This commit is contained in:
@@ -16,15 +16,15 @@
|
||||
|
||||
package org.springframework.data.gemfire;
|
||||
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
|
||||
import com.gemstone.gemfire.cache.EvictionAction;
|
||||
import com.gemstone.gemfire.cache.EvictionAttributes;
|
||||
import com.gemstone.gemfire.cache.util.ObjectSizer;
|
||||
import com.gemstone.gemfire.internal.cache.lru.LRUCapacityController;
|
||||
import com.gemstone.gemfire.internal.cache.lru.MemLRUCapacityController;
|
||||
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
|
||||
/**
|
||||
* Simple utility class used for defining nested factory-method like definitions w/o polluting the container with useless beans.
|
||||
*
|
||||
@@ -53,6 +53,9 @@ public class EvictionAttributesFactoryBean implements FactoryBean<EvictionAttrib
|
||||
|
||||
private ObjectSizer objectSizer = null;
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public void afterPropertiesSet() {
|
||||
evictionAttributes = createAttributes();
|
||||
}
|
||||
@@ -75,17 +78,23 @@ public class EvictionAttributesFactoryBean implements FactoryBean<EvictionAttrib
|
||||
}
|
||||
}
|
||||
|
||||
/* non-Javadoc */
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public EvictionAttributes getObject() {
|
||||
return evictionAttributes;
|
||||
}
|
||||
|
||||
/* non-Javadoc */
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public Class<?> getObjectType() {
|
||||
return (evictionAttributes != null ? evictionAttributes.getClass() : EvictionAttributes.class);
|
||||
}
|
||||
|
||||
/* non-Javadoc */
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public boolean isSingleton() {
|
||||
return true;
|
||||
}
|
||||
@@ -169,5 +178,4 @@ public class EvictionAttributesFactoryBean implements FactoryBean<EvictionAttrib
|
||||
public EvictionPolicyType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -16,12 +16,12 @@
|
||||
|
||||
package org.springframework.data.gemfire;
|
||||
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
|
||||
import com.gemstone.gemfire.cache.AttributesFactory;
|
||||
import com.gemstone.gemfire.cache.RegionAttributes;
|
||||
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
|
||||
/**
|
||||
* Spring-friendly bean for creating {@link RegionAttributes}. Eliminates the need of using a XML 'factory-method' tag.
|
||||
*
|
||||
@@ -32,22 +32,39 @@ import com.gemstone.gemfire.cache.RegionAttributes;
|
||||
* @see com.gemstone.gemfire.cache.AttributesFactory
|
||||
* @see com.gemstone.gemfire.cache.RegionAttributes
|
||||
*/
|
||||
@SuppressWarnings({ "deprecation", "unused" })
|
||||
public class RegionAttributesFactoryBean extends AttributesFactory implements FactoryBean<RegionAttributes>,
|
||||
InitializingBean {
|
||||
@SuppressWarnings({ "unused" })
|
||||
public class RegionAttributesFactoryBean extends AttributesFactory
|
||||
implements FactoryBean<RegionAttributes>, InitializingBean {
|
||||
|
||||
private RegionAttributes attributes;
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
attributes = super.create();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
@Override
|
||||
public RegionAttributes getObject() throws Exception {
|
||||
return attributes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
@Override
|
||||
public Class<?> getObjectType() {
|
||||
return (attributes != null ? attributes.getClass() : RegionAttributes.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
@Override
|
||||
public boolean isSingleton() {
|
||||
return true;
|
||||
@@ -56,10 +73,4 @@ public class RegionAttributesFactoryBean extends AttributesFactory implements Fa
|
||||
public void setIndexUpdateType(final IndexMaintenancePolicyType indexUpdateType) {
|
||||
indexUpdateType.setIndexMaintenance(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
attributes = super.create();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -18,17 +18,6 @@ package org.springframework.data.gemfire;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.context.SmartLifecycle;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.data.gemfire.client.ClientRegionFactoryBean;
|
||||
import org.springframework.data.gemfire.support.RegionShortcutWrapper;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
import com.gemstone.gemfire.cache.AttributesFactory;
|
||||
import com.gemstone.gemfire.cache.Cache;
|
||||
import com.gemstone.gemfire.cache.CacheListener;
|
||||
@@ -36,6 +25,7 @@ import com.gemstone.gemfire.cache.CacheLoader;
|
||||
import com.gemstone.gemfire.cache.CacheWriter;
|
||||
import com.gemstone.gemfire.cache.DataPolicy;
|
||||
import com.gemstone.gemfire.cache.EvictionAction;
|
||||
import com.gemstone.gemfire.cache.EvictionAttributes;
|
||||
import com.gemstone.gemfire.cache.GemFireCache;
|
||||
import com.gemstone.gemfire.cache.PartitionAttributes;
|
||||
import com.gemstone.gemfire.cache.PartitionAttributesFactory;
|
||||
@@ -48,6 +38,18 @@ import com.gemstone.gemfire.cache.asyncqueue.AsyncEventQueue;
|
||||
import com.gemstone.gemfire.cache.wan.GatewaySender;
|
||||
import com.gemstone.gemfire.internal.cache.UserSpecifiedRegionAttributes;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.context.SmartLifecycle;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.data.gemfire.client.ClientRegionFactoryBean;
|
||||
import org.springframework.data.gemfire.support.RegionShortcutWrapper;
|
||||
import org.springframework.data.gemfire.util.ArrayUtils;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
/**
|
||||
* Base class for FactoryBeans used to create GemFire {@link Region}s. Will try
|
||||
* to first locate the region (by name) and, in case none if found, proceed to
|
||||
@@ -74,6 +76,8 @@ public abstract class RegionFactoryBean<K, V> extends RegionLookupFactoryBean<K,
|
||||
private Boolean enableGateway;
|
||||
private Boolean persistent;
|
||||
|
||||
private AsyncEventQueue[] asyncEventQueues;
|
||||
|
||||
private CacheListener<K, V>[] cacheListeners;
|
||||
|
||||
private CacheLoader<K, V> cacheLoader;
|
||||
@@ -82,8 +86,9 @@ public abstract class RegionFactoryBean<K, V> extends RegionLookupFactoryBean<K,
|
||||
|
||||
private DataPolicy dataPolicy;
|
||||
|
||||
private Object[] asyncEventQueues;
|
||||
private Object[] gatewaySenders;
|
||||
private EvictionAttributes evictionAttributes;
|
||||
|
||||
private GatewaySender[] gatewaySenders;
|
||||
|
||||
private RegionAttributes<K, V> attributes;
|
||||
|
||||
@@ -96,14 +101,20 @@ public abstract class RegionFactoryBean<K, V> extends RegionLookupFactoryBean<K,
|
||||
private String diskStoreName;
|
||||
private String hubId;
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
super.afterPropertiesSet();
|
||||
postProcess(getRegion());
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings("deprecation")
|
||||
@SuppressWarnings({ "unchecked" })
|
||||
protected Region<K, V> lookupFallback(GemFireCache gemfireCache, String regionName) throws Exception {
|
||||
Assert.isTrue(gemfireCache instanceof Cache, String.format("Unable to create Regions from '%1$s'.",
|
||||
gemfireCache));
|
||||
@@ -134,16 +145,12 @@ public abstract class RegionFactoryBean<K, V> extends RegionLookupFactoryBean<K,
|
||||
}
|
||||
}
|
||||
|
||||
if (!ObjectUtils.isEmpty(asyncEventQueues)) {
|
||||
for (Object asyncEventQueue : asyncEventQueues) {
|
||||
regionFactory.addAsyncEventQueueId(((AsyncEventQueue) asyncEventQueue).getId());
|
||||
}
|
||||
for (AsyncEventQueue asyncEventQueue : ArrayUtils.nullSafeArray(asyncEventQueues, AsyncEventQueue.class)) {
|
||||
regionFactory.addAsyncEventQueueId(asyncEventQueue.getId());
|
||||
}
|
||||
|
||||
if (!ObjectUtils.isEmpty(cacheListeners)) {
|
||||
for (CacheListener<K, V> listener : cacheListeners) {
|
||||
regionFactory.addCacheListener(listener);
|
||||
}
|
||||
for (CacheListener<K, V> listener : ArrayUtils.nullSafeArray(cacheListeners, CacheListener.class)) {
|
||||
regionFactory.addCacheListener(listener);
|
||||
}
|
||||
|
||||
if (cacheLoader != null) {
|
||||
@@ -160,6 +167,10 @@ public abstract class RegionFactoryBean<K, V> extends RegionLookupFactoryBean<K,
|
||||
regionFactory.setDiskStoreName(diskStoreName);
|
||||
}
|
||||
|
||||
if (evictionAttributes != null) {
|
||||
regionFactory.setEvictionAttributes(evictionAttributes);
|
||||
}
|
||||
|
||||
if (scope != null) {
|
||||
regionFactory.setScope(scope);
|
||||
}
|
||||
@@ -206,7 +217,7 @@ public abstract class RegionFactoryBean<K, V> extends RegionLookupFactoryBean<K,
|
||||
* @see com.gemstone.gemfire.cache.Cache#createRegionFactory(com.gemstone.gemfire.cache.RegionShortcut)
|
||||
* @see com.gemstone.gemfire.cache.RegionFactory
|
||||
*/
|
||||
protected RegionFactory<K, V> createRegionFactory(final Cache cache) {
|
||||
protected RegionFactory<K, V> createRegionFactory(Cache cache) {
|
||||
if (shortcut != null) {
|
||||
RegionFactory<K, V> regionFactory = mergeRegionAttributes(
|
||||
cache.<K, V>createRegionFactory(shortcut), attributes);
|
||||
@@ -236,14 +247,14 @@ public abstract class RegionFactoryBean<K, V> extends RegionLookupFactoryBean<K,
|
||||
* @see com.gemstone.gemfire.cache.DataPolicy
|
||||
*/
|
||||
@SuppressWarnings({ "deprecation", "unchecked" })
|
||||
DataPolicy getDataPolicy(final RegionFactory regionFactory) {
|
||||
DataPolicy getDataPolicy(RegionFactory regionFactory) {
|
||||
return ((RegionAttributes) getFieldValue(getFieldValue(regionFactory, "attrsFactory", AttributesFactory.class),
|
||||
"regionAttributes", null)).getDataPolicy();
|
||||
}
|
||||
|
||||
/* (non-Javadoc) */
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T> T getFieldValue(final Object source, final String fieldName, final Class<T> targetType) {
|
||||
private <T> T getFieldValue(Object source, String fieldName, Class<T> targetType) {
|
||||
Field field = ReflectionUtils.findField(source.getClass(), fieldName, targetType);
|
||||
ReflectionUtils.makeAccessible(field);
|
||||
return (T) ReflectionUtils.getField(field, source);
|
||||
@@ -269,8 +280,8 @@ public abstract class RegionFactoryBean<K, V> extends RegionLookupFactoryBean<K,
|
||||
* @see com.gemstone.gemfire.cache.RegionFactory
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
protected <K, V> RegionFactory<K, V> mergeRegionAttributes(final RegionFactory<K, V> regionFactory,
|
||||
final RegionAttributes<K, V> regionAttributes) {
|
||||
protected <K, V> RegionFactory<K, V> mergeRegionAttributes(RegionFactory<K, V> regionFactory,
|
||||
RegionAttributes<K, V> regionAttributes) {
|
||||
|
||||
if (regionAttributes != null) {
|
||||
// NOTE this validation may not be strictly required depending on how the RegionAttributes were "created",
|
||||
@@ -314,6 +325,7 @@ public abstract class RegionFactoryBean<K, V> extends RegionLookupFactoryBean<K,
|
||||
return regionFactory;
|
||||
}
|
||||
|
||||
/* (non-Javadoc) */
|
||||
protected <K, V> void mergePartitionAttributes(final RegionFactory<K, V> regionFactory,
|
||||
final RegionAttributes<K, V> regionAttributes) {
|
||||
|
||||
@@ -351,7 +363,7 @@ public abstract class RegionFactoryBean<K, V> extends RegionLookupFactoryBean<K,
|
||||
* @see com.gemstone.gemfire.cache.AttributesFactory#validateAttributes(:RegionAttributes)
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
void validateRegionAttributes(final RegionAttributes regionAttributes) {
|
||||
void validateRegionAttributes(RegionAttributes regionAttributes) {
|
||||
com.gemstone.gemfire.cache.AttributesFactory.validateAttributes(regionAttributes);
|
||||
}
|
||||
|
||||
@@ -447,7 +459,8 @@ public abstract class RegionFactoryBean<K, V> extends RegionLookupFactoryBean<K,
|
||||
* @param regionFactory the GemFire RegionFactory used to create the Region for post-processing.
|
||||
* @see com.gemstone.gemfire.cache.RegionFactory
|
||||
*/
|
||||
protected void postProcess(RegionFactory<K, V> regionFactory) {
|
||||
protected RegionFactory<K, V> postProcess(RegionFactory<K, V> regionFactory) {
|
||||
return regionFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -457,7 +470,8 @@ public abstract class RegionFactoryBean<K, V> extends RegionLookupFactoryBean<K,
|
||||
* @param region the GemFire Region to post-process.
|
||||
* @see com.gemstone.gemfire.cache.Region
|
||||
*/
|
||||
protected void postProcess(Region<K, V> region) {
|
||||
protected Region<K, V> postProcess(Region<K, V> region) {
|
||||
return region;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -547,7 +561,7 @@ public abstract class RegionFactoryBean<K, V> extends RegionLookupFactoryBean<K,
|
||||
*
|
||||
* @param asyncEventQueues defined as Object for backwards compatibility with Gemfire 6.
|
||||
*/
|
||||
public void setAsyncEventQueues(Object[] asyncEventQueues) {
|
||||
public void setAsyncEventQueues(AsyncEventQueue[] asyncEventQueues) {
|
||||
this.asyncEventQueues = asyncEventQueues;
|
||||
}
|
||||
|
||||
@@ -674,12 +688,16 @@ public abstract class RegionFactoryBean<K, V> extends RegionLookupFactoryBean<K,
|
||||
this.enableGateway = enableGateway;
|
||||
}
|
||||
|
||||
public void setEvictionAttributes(EvictionAttributes evictionAttributes) {
|
||||
this.evictionAttributes = evictionAttributes;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param gatewaySenders defined as Object for backward compatibility with
|
||||
* Gemfire 6
|
||||
*/
|
||||
public void setGatewaySenders(Object[] gatewaySenders) {
|
||||
public void setGatewaySenders(GatewaySender[] gatewaySenders) {
|
||||
this.gatewaySenders = gatewaySenders;
|
||||
}
|
||||
|
||||
@@ -730,11 +748,11 @@ public abstract class RegionFactoryBean<K, V> extends RegionLookupFactoryBean<K,
|
||||
this.snapshot = snapshot;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.context.Lifecycle#start()
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings("all")
|
||||
public void start() {
|
||||
if (!ObjectUtils.isEmpty(gatewaySenders)) {
|
||||
synchronized (gatewaySenders) {
|
||||
@@ -750,9 +768,17 @@ public abstract class RegionFactoryBean<K, V> extends RegionLookupFactoryBean<K,
|
||||
this.running = true;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.context.Lifecycle#stop()
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
@Override
|
||||
public void stop(Runnable callback) {
|
||||
stop();
|
||||
callback.run();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
@Override
|
||||
public void stop() {
|
||||
@@ -767,41 +793,27 @@ public abstract class RegionFactoryBean<K, V> extends RegionLookupFactoryBean<K,
|
||||
this.running = false;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.context.Lifecycle#isRunning()
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
@Override
|
||||
public boolean isRunning() {
|
||||
return this.running;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.context.Phased#getPhase()
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
@Override
|
||||
public int getPhase() {
|
||||
return Integer.MAX_VALUE;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.context.SmartLifecycle#isAutoStartup()
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
@Override
|
||||
public boolean isAutoStartup() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.context.SmartLifecycle#stop(java.lang.Runnable)
|
||||
*/
|
||||
@Override
|
||||
public void stop(Runnable callback) {
|
||||
stop();
|
||||
callback.run();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -16,6 +16,9 @@
|
||||
|
||||
package org.springframework.data.gemfire;
|
||||
|
||||
import com.gemstone.gemfire.cache.GemFireCache;
|
||||
import com.gemstone.gemfire.cache.Region;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.factory.BeanInitializationException;
|
||||
@@ -25,9 +28,6 @@ import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.gemstone.gemfire.cache.GemFireCache;
|
||||
import com.gemstone.gemfire.cache.Region;
|
||||
|
||||
/**
|
||||
* Simple FactoryBean for retrieving generic GemFire {@link Region}s. If lookups are not enabled or the Region
|
||||
* does not exist, an exception is thrown. For declaring and configuring new Regions, see {@link RegionFactoryBean}.
|
||||
@@ -49,33 +49,37 @@ public abstract class RegionLookupFactoryBean<K, V> implements FactoryBean<Regio
|
||||
private GemFireCache cache;
|
||||
|
||||
private Region<?, ?> parent;
|
||||
|
||||
private volatile Region<K, V> region;
|
||||
|
||||
private String beanName;
|
||||
private String name;
|
||||
private String regionName;
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings("all")
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
Assert.notNull(cache, "the 'cache' reference property must be set");
|
||||
Assert.notNull(this.cache, "A 'Cache' reference must be set");
|
||||
|
||||
String regionName = (StringUtils.hasText(this.regionName) ? this.regionName
|
||||
: (StringUtils.hasText(name) ? name : beanName));
|
||||
String regionName = resolveRegionName();
|
||||
|
||||
Assert.hasText(regionName, "'regionName', 'name' or 'beanName' property must be set");
|
||||
|
||||
synchronized (cache) {
|
||||
//region = (getParent() != null ? getParent().getSubregion(regionName) : cache.getRegion(regionName));
|
||||
synchronized (this.cache) {
|
||||
if (isLookupEnabled()) {
|
||||
if (getParent() != null) {
|
||||
region = getParent().getSubregion(regionName);
|
||||
this.region = getParent().getSubregion(regionName);
|
||||
}
|
||||
else {
|
||||
region = cache.getRegion(regionName);
|
||||
this.region = this.cache.getRegion(regionName);
|
||||
}
|
||||
}
|
||||
|
||||
if (region != null) {
|
||||
log.info(String.format("found Region (%1$s) in Cache (%2$s)", regionName, cache.getName()));
|
||||
log.info(String.format("Found Region [%1$s] in Cache [%2$s]", regionName, cache.getName()));
|
||||
}
|
||||
else {
|
||||
region = lookupFallback(cache, regionName);
|
||||
@@ -84,36 +88,69 @@ public abstract class RegionLookupFactoryBean<K, V> implements FactoryBean<Regio
|
||||
}
|
||||
|
||||
/**
|
||||
* Fallback method in case the named Region does not exist. By default, this implementation throws an exception.
|
||||
*
|
||||
* @param cache a reference to the GemFire Cache.
|
||||
* @param regionName the name of the GemFire Cache Region.
|
||||
* @return the Region in the GemFire Cache with the given name.
|
||||
* @throws Exception if the lookup operation fails.
|
||||
* @deprecated call {@link #lookupRegion(GemFireCache, String)} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
protected Region<K, V> lookupFallback(GemFireCache cache, String regionName) throws Exception {
|
||||
throw new BeanInitializationException(String.format("Cannot find Region [%1$s] in Cache [%2$s].",
|
||||
regionName, cache));
|
||||
return lookupRegion(cache, regionName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to perform a lookup when the named {@link Region} does not exist. By default, this implementation
|
||||
* throws an exception.
|
||||
*
|
||||
* @param cache reference to the GemFire cache.
|
||||
* @param regionName name of the GemFire {@link Region}.
|
||||
* @return the {@link Region} in the GemFire cache with the given name.
|
||||
* @throws BeanInitializationException if the lookup operation fails.
|
||||
* @see com.gemstone.gemfire.cache.Region
|
||||
*/
|
||||
protected Region<K, V> lookupRegion(GemFireCache cache, String regionName) throws Exception {
|
||||
throw new BeanInitializationException(String.format(
|
||||
"Region [%1$s] in Cache [%2$s] not found", regionName, cache));
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
@Override
|
||||
public Region<K, V> getObject() throws Exception {
|
||||
return getRegion();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
@Override
|
||||
public Class<?> getObjectType() {
|
||||
Region localRegion = getRegion();
|
||||
return (localRegion != null ? localRegion.getClass() : Region.class);
|
||||
Region region = getRegion();
|
||||
return (region != null ? region.getClass() : Region.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
@Override
|
||||
public boolean isSingleton() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name of the Cache Region based on the bean 'id' attribute. If no Region is found for the given name,
|
||||
* a new one will be created.
|
||||
* Resolves the name of the GemFire {@link Region}.
|
||||
*
|
||||
* @param name the name of this bean (Region) in the application context (bean factory).
|
||||
* @return a {@link String} indicating the name of the GemFire {@link Region}.
|
||||
* @see com.gemstone.gemfire.cache.Region#getName()
|
||||
*/
|
||||
public String resolveRegionName() {
|
||||
return (StringUtils.hasText(this.regionName) ? this.regionName
|
||||
: (StringUtils.hasText(this.name) ? this.name : this.beanName));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name of the {@link Region} based on the bean 'id' attribute. If no {@link Region} is found
|
||||
* with the given name, a new one will be created.
|
||||
*
|
||||
* @param name name of this {@link Region} bean in the Spring {@link org.springframework.context.ApplicationContext}.
|
||||
* @see org.springframework.beans.factory.BeanNameAware#setBeanName(String)
|
||||
*/
|
||||
public void setBeanName(String name) {
|
||||
@@ -121,9 +158,9 @@ public abstract class RegionLookupFactoryBean<K, V> implements FactoryBean<Regio
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a reference to the Cache used to create the Region.
|
||||
* Sets a reference to the {@link GemFireCache} used to create the {@link Region}.
|
||||
*
|
||||
* @param cache a reference to the Cache.
|
||||
* @param cache reference to the {@link GemFireCache}.
|
||||
* @see org.springframework.data.gemfire.CacheFactoryBean
|
||||
* @see com.gemstone.gemfire.cache.GemFireCache
|
||||
*/
|
||||
@@ -131,60 +168,6 @@ public abstract class RegionLookupFactoryBean<K, V> implements FactoryBean<Regio
|
||||
this.cache = cache;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name of the Cache Region based on the bean 'name' attribute. If no Region is found with the given name,
|
||||
* a new one will be created. If no name is given, the value of the 'beanName' property will be used.
|
||||
*
|
||||
* @param name the region name
|
||||
* @see #setBeanName(String)
|
||||
* @see com.gemstone.gemfire.cache.Region#getFullPath()
|
||||
*/
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a reference to the parent Region if this FactoryBean represents a GemFire Cache Sub-Region.
|
||||
*
|
||||
* @param parent a reference to the parent Region if this Region is a Sub-Region.
|
||||
* @see com.gemstone.gemfire.cache.Region
|
||||
*/
|
||||
public void setParent(Region<?, ?> parent) {
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a reference to the parent Region if this FactoryBean represents a GemFire Cache Sub-Region.
|
||||
*
|
||||
* @return a reference to the parent Region or null if this Region is not a Sub-Region.
|
||||
* @see com.gemstone.gemfire.cache.Region
|
||||
*/
|
||||
protected Region<?, ?> getParent() {
|
||||
return parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the reference to the GemFire Region obtained by this Spring FactoryBean during the lookup operation.
|
||||
*
|
||||
* @return a reference to the GemFire Region found during lookup.
|
||||
* @see com.gemstone.gemfire.cache.Region
|
||||
*/
|
||||
protected Region<K, V> getRegion() {
|
||||
return region;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name of the Cache Region as expected by GemFire. If no Region is found with the given name, a new one
|
||||
* will be created. If no name is given, the value of the 'name' property will be used.
|
||||
*
|
||||
* @param regionName a String indicating the name of the Region in GemFire.
|
||||
* @see #setName(String)
|
||||
* @see com.gemstone.gemfire.cache.Region#getName()
|
||||
*/
|
||||
public void setRegionName(String regionName) {
|
||||
this.regionName = regionName;
|
||||
}
|
||||
|
||||
/* (non-Javadoc) */
|
||||
boolean isLookupEnabled() {
|
||||
return Boolean.TRUE.equals(getLookupEnabled());
|
||||
@@ -200,4 +183,60 @@ public abstract class RegionLookupFactoryBean<K, V> implements FactoryBean<Regio
|
||||
return lookupEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name of the cache {@link Region} based on the bean 'name' attribute. If no {@link Region} is found
|
||||
* with the given name, a new one will be created. If no name is given, the value of the 'beanName' property
|
||||
* will be used.
|
||||
*
|
||||
* @param name {@link Region} name.
|
||||
* @see #setBeanName(String)
|
||||
*/
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a reference to the parent {@link Region} to indicated this {@link FactoryBean} represents a GemFire cache
|
||||
* {@link Region Sub-Region}.
|
||||
*
|
||||
* @param parent reference to the parent {@link Region}.
|
||||
* @see com.gemstone.gemfire.cache.Region
|
||||
*/
|
||||
public void setParent(Region<?, ?> parent) {
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reference to the parent {@link Region} indicating this {@link FactoryBean} represents a GemFire cache
|
||||
* {@link Region Sub-Region}.
|
||||
*
|
||||
* @return a reference to the parent {@link Region} or {@literal null} if this {@link Region}
|
||||
* is not a {@link Region Sub-Region}.
|
||||
* @see com.gemstone.gemfire.cache.Region
|
||||
*/
|
||||
protected Region<?, ?> getParent() {
|
||||
return this.parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reference to the GemFire {@link Region} resolved by this Spring {@link FactoryBean}
|
||||
* during the lookup operation; maybe a new {@link Region}.
|
||||
*
|
||||
* @return a reference to the GemFire {@link Region} resolved during lookup.
|
||||
* @see com.gemstone.gemfire.cache.Region
|
||||
*/
|
||||
protected Region<K, V> getRegion() {
|
||||
return this.region;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name of the cache {@link Region}. If no {@link Region} is found with the given name,
|
||||
* a new one will be created. If no name is given, the value of the 'name' property will be used.
|
||||
*
|
||||
* @param regionName name of the {@link Region}.
|
||||
* @see #setName(String)
|
||||
*/
|
||||
public void setRegionName(String regionName) {
|
||||
this.regionName = regionName;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,25 +16,11 @@
|
||||
|
||||
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.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.xml.GemfireConstants;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
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.EvictionAttributes;
|
||||
import com.gemstone.gemfire.cache.GemFireCache;
|
||||
import com.gemstone.gemfire.cache.Region;
|
||||
import com.gemstone.gemfire.cache.RegionAttributes;
|
||||
@@ -43,8 +29,25 @@ import com.gemstone.gemfire.cache.client.ClientRegionFactory;
|
||||
import com.gemstone.gemfire.cache.client.ClientRegionShortcut;
|
||||
import com.gemstone.gemfire.cache.client.Pool;
|
||||
|
||||
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.DisposableBean;
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
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.xml.GemfireConstants;
|
||||
import org.springframework.data.gemfire.util.ArrayUtils;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Client extension for GemFire Regions.
|
||||
* Spring {@link FactoryBean} used to create a GemFire client {@link Region}.
|
||||
*
|
||||
* @author Costin Leau
|
||||
* @author David Turanski
|
||||
@@ -53,9 +56,6 @@ import com.gemstone.gemfire.cache.client.Pool;
|
||||
* @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
|
||||
@@ -87,6 +87,8 @@ public class ClientRegionFactoryBean<K, V> extends RegionLookupFactoryBean<K, V>
|
||||
|
||||
private DataPolicy dataPolicy;
|
||||
|
||||
private EvictionAttributes evictionAttributes;
|
||||
|
||||
private Interest<K>[] interests;
|
||||
|
||||
private RegionAttributes<K, V> attributes;
|
||||
@@ -96,75 +98,61 @@ public class ClientRegionFactoryBean<K, V> extends RegionLookupFactoryBean<K, V>
|
||||
private String diskStoreName;
|
||||
private String poolName;
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
super.afterPropertiesSet();
|
||||
postProcess(getRegion());
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings("all")
|
||||
protected Region<K, V> lookupFallback(GemFireCache cache, String regionName) throws Exception {
|
||||
Assert.isTrue(GemfireUtils.isClient(cache), "A ClientCache is required to create a client Region");
|
||||
|
||||
ClientRegionFactory<K, V> clientRegionFactory = ((ClientCache) cache).createClientRegionFactory(
|
||||
resolveClientRegionShortcut());
|
||||
|
||||
if (attributes != null) {
|
||||
clientRegionFactory.setCloningEnabled(attributes.getCloningEnabled());
|
||||
clientRegionFactory.setCompressor(attributes.getCompressor());
|
||||
clientRegionFactory.setConcurrencyChecksEnabled(attributes.getConcurrencyChecksEnabled());
|
||||
clientRegionFactory.setConcurrencyLevel(attributes.getConcurrencyLevel());
|
||||
clientRegionFactory.setCustomEntryIdleTimeout(attributes.getCustomEntryIdleTimeout());
|
||||
clientRegionFactory.setCustomEntryTimeToLive(attributes.getCustomEntryTimeToLive());
|
||||
clientRegionFactory.setDiskStoreName(attributes.getDiskStoreName());
|
||||
clientRegionFactory.setDiskSynchronous(attributes.isDiskSynchronous());
|
||||
clientRegionFactory.setEntryIdleTimeout(attributes.getEntryIdleTimeout());
|
||||
clientRegionFactory.setEntryTimeToLive(attributes.getEntryTimeToLive());
|
||||
clientRegionFactory.setEvictionAttributes(attributes.getEvictionAttributes());
|
||||
clientRegionFactory.setInitialCapacity(attributes.getInitialCapacity());
|
||||
clientRegionFactory.setKeyConstraint(attributes.getKeyConstraint());
|
||||
clientRegionFactory.setLoadFactor(attributes.getLoadFactor());
|
||||
clientRegionFactory.setPoolName(attributes.getPoolName());
|
||||
clientRegionFactory.setRegionIdleTimeout(attributes.getRegionIdleTimeout());
|
||||
clientRegionFactory.setRegionTimeToLive(attributes.getRegionTimeToLive());
|
||||
clientRegionFactory.setStatisticsEnabled(attributes.getStatisticsEnabled());
|
||||
clientRegionFactory.setValueConstraint(attributes.getValueConstraint());
|
||||
}
|
||||
|
||||
String poolName = resolvePoolName();
|
||||
|
||||
if (StringUtils.hasText(poolName)) {
|
||||
clientRegionFactory.setPoolName(eagerlyInitializePool(poolName));
|
||||
}
|
||||
ClientRegionFactory<K, V> clientRegionFactory =
|
||||
((ClientCache) cache).createClientRegionFactory(resolveClientRegionShortcut());
|
||||
|
||||
setAttributes(clientRegionFactory);
|
||||
addCacheListeners(clientRegionFactory);
|
||||
setDiskStoreName(clientRegionFactory);
|
||||
setEvictionAttributes(clientRegionFactory);
|
||||
setPoolName(clientRegionFactory);
|
||||
|
||||
if (diskStoreName != null) {
|
||||
clientRegionFactory.setDiskStoreName(diskStoreName);
|
||||
}
|
||||
|
||||
Region<K, V> clientRegion = (getParent() != null ? clientRegionFactory.createSubregion(getParent(), regionName)
|
||||
: clientRegionFactory.create(regionName));
|
||||
|
||||
if (log.isInfoEnabled()) {
|
||||
if (getParent() != null) {
|
||||
log.info(String.format("Created new Client Cache sub-Region [%1$s] under parent Region [%2$s].",
|
||||
regionName, getParent().getName()));
|
||||
}
|
||||
else {
|
||||
log.info(String.format("Created new Client Cache Region [%1$s].", regionName));
|
||||
}
|
||||
}
|
||||
|
||||
if (snapshot != null) {
|
||||
clientRegion.loadSnapshot(snapshot.getInputStream());
|
||||
}
|
||||
|
||||
return clientRegion;
|
||||
return logCreateRegionEvent(create(clientRegionFactory, regionName));
|
||||
}
|
||||
|
||||
/* (non-Javadoc) */
|
||||
private Region<K, V> create(ClientRegionFactory<K, V> clientRegionFactory, String regionName) {
|
||||
return (getParent() != null ? clientRegionFactory.createSubregion(getParent(), regionName)
|
||||
: clientRegionFactory.create(regionName));
|
||||
}
|
||||
|
||||
/* (non-Javadoc) */
|
||||
private Region<K, V> logCreateRegionEvent(Region<K, V> region) {
|
||||
if (log.isInfoEnabled()) {
|
||||
if (getParent() != null) {
|
||||
log.info(String.format("Created new client cache Sub-Region [%1$s] under parent Region [%2$s].",
|
||||
region.getName(), getParent().getName()));
|
||||
}
|
||||
else {
|
||||
log.info(String.format("Created new client cache Region [%s].", region.getName()));
|
||||
}
|
||||
}
|
||||
|
||||
return region;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves the {@link ClientRegionShortcut} used to configure the data policy of the client {@link Region}.
|
||||
*
|
||||
* @return a {@link ClientRegionShortcut} used to configure the data policy of the client {@link Region}.
|
||||
* @see com.gemstone.gemfire.cache.client.ClientRegionShortcut
|
||||
*/
|
||||
ClientRegionShortcut resolveClientRegionShortcut() {
|
||||
ClientRegionShortcut resolvedShortcut = this.shortcut;
|
||||
|
||||
@@ -182,10 +170,10 @@ public class ClientRegionFactoryBean<K, V> extends RegionLookupFactoryBean<K, V>
|
||||
resolvedShortcut = ClientRegionShortcut.LOCAL_PERSISTENT;
|
||||
}
|
||||
else {
|
||||
// NOTE the Data Policy validation is based on the ClientRegionShortcut initialization logic
|
||||
// NOTE the DataPolicy validation is based on the ClientRegionShortcut initialization logic
|
||||
// in com.gemstone.gemfire.internal.cache.GemFireCacheImpl.initializeClientRegionShortcuts
|
||||
throw new IllegalArgumentException(String.format(
|
||||
"Data Policy '%1$s' is invalid for Client Regions.", this.dataPolicy));
|
||||
throw new IllegalArgumentException(String.format("Data Policy '%s' is invalid for Client Regions",
|
||||
this.dataPolicy));
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -194,43 +182,13 @@ public class ClientRegionFactoryBean<K, V> extends RegionLookupFactoryBean<K, V>
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE the ClientRegionShortcut and Persistent attribute will be compatible if the shortcut was derived from
|
||||
// the Data Policy.
|
||||
// NOTE the ClientRegionShortcut and Persistent attribute will be compatible if the shortcut
|
||||
// was derived from the Data Policy.
|
||||
assertClientRegionShortcutAndPersistentAttributeAreCompatible(resolvedShortcut);
|
||||
|
||||
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 <gfe:*-region> elements
|
||||
* are compatible.
|
||||
@@ -241,17 +199,17 @@ public class ClientRegionFactoryBean<K, V> extends RegionLookupFactoryBean<K, V>
|
||||
* @see #isNotPersistent()
|
||||
* @see com.gemstone.gemfire.cache.client.ClientRegionShortcut
|
||||
*/
|
||||
protected void assertClientRegionShortcutAndPersistentAttributeAreCompatible(final ClientRegionShortcut resolvedShortcut) {
|
||||
private void assertClientRegionShortcutAndPersistentAttributeAreCompatible(ClientRegionShortcut resolvedShortcut) {
|
||||
final boolean persistentNotSpecified = (this.persistent == null);
|
||||
|
||||
if (ClientRegionShortcut.LOCAL_PERSISTENT.equals(resolvedShortcut)
|
||||
|| ClientRegionShortcut.LOCAL_PERSISTENT_OVERFLOW.equals(resolvedShortcut)) {
|
||||
|| ClientRegionShortcut.LOCAL_PERSISTENT_OVERFLOW.equals(resolvedShortcut)) {
|
||||
Assert.isTrue(persistentNotSpecified || isPersistent(), String.format(
|
||||
"Client Region Shortcut '%1$s' is invalid when persistent is false.", resolvedShortcut));
|
||||
"Client Region Shortcut '%s' is invalid when persistent is false", resolvedShortcut));
|
||||
}
|
||||
else {
|
||||
Assert.isTrue(persistentNotSpecified || isNotPersistent(), String.format(
|
||||
"Client Region Shortcut '%1$s' is invalid when persistent is true.", resolvedShortcut));
|
||||
"Client Region Shortcut '%s' is invalid when persistent is true", resolvedShortcut));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -265,43 +223,147 @@ public class ClientRegionFactoryBean<K, V> extends RegionLookupFactoryBean<K, V>
|
||||
* @see #isNotPersistent()
|
||||
* @see com.gemstone.gemfire.cache.DataPolicy
|
||||
*/
|
||||
protected void assertDataPolicyAndPersistentAttributeAreCompatible(final DataPolicy resolvedDataPolicy) {
|
||||
private void assertDataPolicyAndPersistentAttributeAreCompatible(DataPolicy resolvedDataPolicy) {
|
||||
if (resolvedDataPolicy.withPersistence()) {
|
||||
Assert.isTrue(isPersistentUnspecified() || isPersistent(), String.format(
|
||||
"Data Policy '%1$s' is invalid when persistent is false.", resolvedDataPolicy));
|
||||
"Data Policy '%s' is invalid when persistent is false", resolvedDataPolicy));
|
||||
}
|
||||
else {
|
||||
// NOTE otherwise, the Data Policy is without persistence, so...
|
||||
Assert.isTrue(isPersistentUnspecified() || isNotPersistent(), String.format(
|
||||
"Data Policy '%1$s' is invalid when persistent is true.", resolvedDataPolicy));
|
||||
"Data Policy '%s' is invalid when persistent is true", resolvedDataPolicy));
|
||||
}
|
||||
}
|
||||
|
||||
private void addCacheListeners(ClientRegionFactory<K, V> factory) {
|
||||
if (attributes != null) {
|
||||
CacheListener<K, V>[] cacheListeners = attributes.getCacheListeners();
|
||||
/* (non-Javadoc) */
|
||||
private ClientRegionFactory<K, V> setAttributes(ClientRegionFactory<K, V> clientRegionFactory) {
|
||||
RegionAttributes<K, V> localAttributes = this.attributes;
|
||||
|
||||
if (!ObjectUtils.isEmpty(cacheListeners)) {
|
||||
for (CacheListener<K, V> cacheListener : cacheListeners) {
|
||||
factory.addCacheListener(cacheListener);
|
||||
if (localAttributes != null) {
|
||||
clientRegionFactory.setCloningEnabled(localAttributes.getCloningEnabled());
|
||||
clientRegionFactory.setCompressor(localAttributes.getCompressor());
|
||||
clientRegionFactory.setConcurrencyChecksEnabled(localAttributes.getConcurrencyChecksEnabled());
|
||||
clientRegionFactory.setConcurrencyLevel(localAttributes.getConcurrencyLevel());
|
||||
clientRegionFactory.setCustomEntryIdleTimeout(localAttributes.getCustomEntryIdleTimeout());
|
||||
clientRegionFactory.setCustomEntryTimeToLive(localAttributes.getCustomEntryTimeToLive());
|
||||
clientRegionFactory.setDiskStoreName(localAttributes.getDiskStoreName());
|
||||
clientRegionFactory.setDiskSynchronous(localAttributes.isDiskSynchronous());
|
||||
clientRegionFactory.setEntryIdleTimeout(localAttributes.getEntryIdleTimeout());
|
||||
clientRegionFactory.setEntryTimeToLive(localAttributes.getEntryTimeToLive());
|
||||
clientRegionFactory.setEvictionAttributes(localAttributes.getEvictionAttributes());
|
||||
clientRegionFactory.setInitialCapacity(localAttributes.getInitialCapacity());
|
||||
clientRegionFactory.setKeyConstraint(localAttributes.getKeyConstraint());
|
||||
clientRegionFactory.setLoadFactor(localAttributes.getLoadFactor());
|
||||
clientRegionFactory.setPoolName(localAttributes.getPoolName());
|
||||
clientRegionFactory.setRegionIdleTimeout(localAttributes.getRegionIdleTimeout());
|
||||
clientRegionFactory.setRegionTimeToLive(localAttributes.getRegionTimeToLive());
|
||||
clientRegionFactory.setStatisticsEnabled(localAttributes.getStatisticsEnabled());
|
||||
clientRegionFactory.setValueConstraint(localAttributes.getValueConstraint());
|
||||
}
|
||||
|
||||
return clientRegionFactory;
|
||||
}
|
||||
|
||||
/* (non-Javadoc) */
|
||||
@SuppressWarnings("unchecked")
|
||||
private ClientRegionFactory<K, V> addCacheListeners(ClientRegionFactory<K, V> clientRegionFactory) {
|
||||
for (CacheListener<K, V> cacheListener : this.<K, V>attributesCacheListeners()) {
|
||||
clientRegionFactory.addCacheListener(cacheListener);
|
||||
}
|
||||
|
||||
for (CacheListener<K, V> cacheListener : ArrayUtils.nullSafeArray(this.cacheListeners, CacheListener.class)) {
|
||||
clientRegionFactory.addCacheListener(cacheListener);
|
||||
}
|
||||
|
||||
return clientRegionFactory;
|
||||
}
|
||||
|
||||
/* (non-Javadoc) */
|
||||
@SuppressWarnings("unchecked")
|
||||
private <K, V> CacheListener<K, V>[] attributesCacheListeners() {
|
||||
return (this.attributes != null
|
||||
? ArrayUtils.nullSafeArray(this.attributes.getCacheListeners(), CacheListener.class)
|
||||
: new CacheListener[0]);
|
||||
}
|
||||
|
||||
/* (non-Javadoc) */
|
||||
private ClientRegionFactory<K, V> setDiskStoreName(ClientRegionFactory<K, V> clientRegionFactory) {
|
||||
if (StringUtils.hasText(this.diskStoreName)) {
|
||||
clientRegionFactory.setDiskStoreName(this.diskStoreName);
|
||||
}
|
||||
|
||||
return clientRegionFactory;
|
||||
}
|
||||
|
||||
/* (non-Javadoc) */
|
||||
private ClientRegionFactory<K, V> setEvictionAttributes(ClientRegionFactory<K, V> clientRegionFactory) {
|
||||
if (this.evictionAttributes != null) {
|
||||
clientRegionFactory.setEvictionAttributes(this.evictionAttributes);
|
||||
}
|
||||
|
||||
return clientRegionFactory;
|
||||
}
|
||||
|
||||
/* (non-Javadoc) */
|
||||
private ClientRegionFactory<K, V> setPoolName(ClientRegionFactory<K, V> clientRegionFactory) {
|
||||
String poolName = resolvePoolName();
|
||||
|
||||
if (StringUtils.hasText(poolName)) {
|
||||
clientRegionFactory.setPoolName(eagerlyInitializePool(poolName));
|
||||
}
|
||||
|
||||
return clientRegionFactory;
|
||||
}
|
||||
|
||||
/* (non-Javadoc) */
|
||||
private String resolvePoolName() {
|
||||
String poolName = this.poolName;
|
||||
|
||||
if (!StringUtils.hasText(poolName)) {
|
||||
String defaultPoolName = GemfireConstants.DEFAULT_GEMFIRE_POOL_NAME;
|
||||
poolName = (this.beanFactory.containsBean(defaultPoolName) ? defaultPoolName : poolName);
|
||||
}
|
||||
|
||||
return poolName;
|
||||
}
|
||||
|
||||
/* (non-Javadoc) */
|
||||
private String eagerlyInitializePool(String poolName) {
|
||||
try {
|
||||
if (this.beanFactory.isTypeMatch(poolName, Pool.class)) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug(String.format("Found bean definition for Pool [%1$s]; Eagerly initializing...", poolName));
|
||||
}
|
||||
|
||||
this.beanFactory.getBean(poolName, Pool.class);
|
||||
}
|
||||
}
|
||||
catch (BeansException ignore) {
|
||||
log.warn(ignore.getMessage());
|
||||
}
|
||||
|
||||
if (!ObjectUtils.isEmpty(cacheListeners)) {
|
||||
for (CacheListener<K, V> cacheListener : cacheListeners) {
|
||||
factory.addCacheListener(cacheListener);
|
||||
}
|
||||
}
|
||||
return poolName;
|
||||
}
|
||||
|
||||
protected void postProcess(final Region<K, V> region) {
|
||||
/* (non-Javadoc) */
|
||||
protected void postProcess(Region<K, V> region) throws Exception {
|
||||
loadSnapshot(region);
|
||||
registerInterests(region);
|
||||
setCacheLoader(region);
|
||||
setCacheWriter(region);
|
||||
}
|
||||
|
||||
private void registerInterests(final Region<K, V> region) {
|
||||
/* (non-Javadoc) */
|
||||
private Region<K, V> loadSnapshot(Region<K, V> region) throws Exception {
|
||||
if (snapshot != null) {
|
||||
region.loadSnapshot(snapshot.getInputStream());
|
||||
}
|
||||
|
||||
return region;
|
||||
}
|
||||
|
||||
/* (non-Javadoc) */
|
||||
private Region<K, V> registerInterests(Region<K, V> region) {
|
||||
if (!ObjectUtils.isEmpty(interests)) {
|
||||
for (Interest<K> interest : interests) {
|
||||
if (interest instanceof RegexInterest) {
|
||||
@@ -314,20 +376,31 @@ public class ClientRegionFactoryBean<K, V> extends RegionLookupFactoryBean<K, V>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return region;
|
||||
}
|
||||
|
||||
private void setCacheLoader(final Region<K, V> region) {
|
||||
/* (non-Javadoc) */
|
||||
private Region<K, V> setCacheLoader(Region<K, V> region) {
|
||||
if (cacheLoader != null) {
|
||||
region.getAttributesMutator().setCacheLoader(this.cacheLoader);
|
||||
}
|
||||
|
||||
return region;
|
||||
}
|
||||
|
||||
private void setCacheWriter(final Region<K, V> region) {
|
||||
/* (non-Javadoc) */
|
||||
private Region<K, V> setCacheWriter(Region<K, V> region) {
|
||||
if (cacheWriter != null) {
|
||||
region.getAttributesMutator().setCacheWriter(this.cacheWriter);
|
||||
}
|
||||
|
||||
return region;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
@Override
|
||||
public void destroy() throws Exception {
|
||||
Region<K, V> region = getObject();
|
||||
@@ -368,43 +441,7 @@ public class ClientRegionFactoryBean<K, V> extends RegionLookupFactoryBean<K, V>
|
||||
this.beanFactory = beanFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the interests for this client region. Both key and regex interest are
|
||||
* supported.
|
||||
*
|
||||
* @param interests the interests to set
|
||||
*/
|
||||
public void setInterests(Interest<K>[] interests) {
|
||||
this.interests = interests;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the interests
|
||||
*/
|
||||
Interest<K>[] getInterests() {
|
||||
return interests;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the pool used by this client.
|
||||
*
|
||||
* @param pool the GemFire client pool.
|
||||
*/
|
||||
public void setPool(Pool pool) {
|
||||
Assert.notNull(pool, "pool cannot be null");
|
||||
setPoolName(pool.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the pool name used by this client.
|
||||
*
|
||||
* @param poolName a String specify the name of the GemFire client pool.
|
||||
*/
|
||||
public void setPoolName(String poolName) {
|
||||
Assert.hasText(poolName, "pool name is required");
|
||||
this.poolName = poolName;
|
||||
}
|
||||
|
||||
/* (non-Javadoc) */
|
||||
final boolean isClose() {
|
||||
return close;
|
||||
}
|
||||
@@ -422,23 +459,6 @@ public class ClientRegionFactoryBean<K, V> extends RegionLookupFactoryBean<K, V>
|
||||
this.destroy = (this.destroy && !close); // retain previous value iff close is false.
|
||||
}
|
||||
|
||||
final boolean isDestroy() {
|
||||
return destroy;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
this.close = (this.close && !destroy); // retain previous value iff destroy is false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the cache listeners used for the region used by this factory. Used
|
||||
* only when a new region is created.Overrides the settings specified
|
||||
@@ -495,6 +515,24 @@ public class ClientRegionFactoryBean<K, V> extends RegionLookupFactoryBean<K, V>
|
||||
setDataPolicy(resolvedDataPolicy);
|
||||
}
|
||||
|
||||
/* (non-Javadoc) */
|
||||
final boolean isDestroy() {
|
||||
return destroy;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
this.close = (this.close && !destroy); // retain previous value iff destroy is false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name of disk store to use for overflow and persistence
|
||||
*
|
||||
@@ -504,6 +542,25 @@ public class ClientRegionFactoryBean<K, V> extends RegionLookupFactoryBean<K, V>
|
||||
this.diskStoreName = diskStoreName;
|
||||
}
|
||||
|
||||
public void setEvictionAttributes(EvictionAttributes evictionAttributes) {
|
||||
this.evictionAttributes = evictionAttributes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the interests for this client region. Both key and regex interest are
|
||||
* supported.
|
||||
*
|
||||
* @param interests the interests to set
|
||||
*/
|
||||
public void setInterests(Interest<K>[] interests) {
|
||||
this.interests = interests;
|
||||
}
|
||||
|
||||
/* (non-Javadoc) */
|
||||
Interest<K>[] getInterests() {
|
||||
return this.interests;
|
||||
}
|
||||
|
||||
protected boolean isPersistentUnspecified() {
|
||||
return (persistent == null);
|
||||
}
|
||||
@@ -521,26 +578,44 @@ public class ClientRegionFactoryBean<K, V> extends RegionLookupFactoryBean<K, V>
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the client using a GemFire {@link ClientRegionShortcut}. The
|
||||
* recommended way for creating clients since it covers all the major
|
||||
* scenarios with minimal configuration.
|
||||
* Sets the {@link Pool} used by this client {@link Region}.
|
||||
*
|
||||
* @param shortcut the ClientRegionShortcut to use.
|
||||
* @param pool GemFire client {@link Pool}.
|
||||
* @see com.gemstone.gemfire.cache.client.Pool
|
||||
*/
|
||||
public void setPool(Pool pool) {
|
||||
Assert.notNull(pool, "Pool cannot be null");
|
||||
setPoolName(pool.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link Pool} name used by this client {@link Region}.
|
||||
*
|
||||
* @param poolName String specifying the name of the GemFire client {@link Pool}.
|
||||
*/
|
||||
public void setPoolName(String poolName) {
|
||||
Assert.hasText(poolName, "Pool name is required");
|
||||
this.poolName = poolName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the client {@link Region} using a GemFire {@link ClientRegionShortcut}.
|
||||
*
|
||||
* @param shortcut {@link ClientRegionShortcut} used to initialize this client {@link Region}.
|
||||
*/
|
||||
public void setShortcut(ClientRegionShortcut shortcut) {
|
||||
this.shortcut = shortcut;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* Specifies the data snapshots used for loading a newly <i>created</i> {@link Region}.
|
||||
* The snapshot will be used <i>only</i> when a new {@link Region} is created.
|
||||
* If the {@link Region} already exists, no loading will be performed.
|
||||
*
|
||||
* @param snapshot the snapshot to set
|
||||
* @see #setName(String)
|
||||
* @param snapshot {@link Resource} referencing the snapshot used to load the {@link Region} with data.
|
||||
* @see org.springframework.core.io.Resource
|
||||
*/
|
||||
public void setSnapshot(Resource snapshot) {
|
||||
this.snapshot = snapshot;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* Copyright 2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.springframework.data.gemfire.config.annotation;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Inherited;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import com.gemstone.gemfire.cache.EvictionAttributes;
|
||||
import com.gemstone.gemfire.cache.Region;
|
||||
import com.gemstone.gemfire.cache.util.ObjectSizer;
|
||||
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.data.gemfire.EvictionActionType;
|
||||
import org.springframework.data.gemfire.EvictionPolicyType;
|
||||
|
||||
/**
|
||||
* The {@link EnableEviction} annotation marks a Spring {@link org.springframework.context.annotation.Configuration @Configuration}
|
||||
* annotated class to enable {@link Region} Eviction.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.springframework.context.annotation.Import
|
||||
* @see org.springframework.data.gemfire.config.annotation.EvictionConfiguration
|
||||
* @see com.gemstone.gemfire.cache.Region
|
||||
* @since 1.9.0
|
||||
*/
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Inherited
|
||||
@Documented
|
||||
@Import(EvictionConfiguration.class)
|
||||
@SuppressWarnings({ "unused" })
|
||||
public @interface EnableEviction {
|
||||
|
||||
/**
|
||||
* Defines individual {@link Region} Eviction policies or customizes the default Eviction policy applied
|
||||
* to all {@link Region Regions}.
|
||||
*
|
||||
* Defaults to empty.
|
||||
*/
|
||||
EvictionPolicy[] policies() default {};
|
||||
|
||||
/**
|
||||
* Definition for a specific Eviction policy that can be applied to 1 or more {@link Region Regions}.
|
||||
*
|
||||
* An Eviction policy defines the maximum (a.k.a. threshold) along with {@link ObjectSizer} used to size
|
||||
* {@link Region} entry values and the action applied when {@link Region} entries are to be evicted.
|
||||
*
|
||||
* Additionally, the Eviction policy defines the algorithm used (eviction based on entry count, JVM Heap percentage
|
||||
* or system memory size used) to determine when an Eviction should occur.
|
||||
*/
|
||||
@interface EvictionPolicy {
|
||||
|
||||
/**
|
||||
* Action to take on an {@link Region} entry when evicted.
|
||||
*
|
||||
* Defaults to {@link EvictionActionType#LOCAL_DESTROY}.
|
||||
*
|
||||
* @see org.springframework.data.gemfire.EvictionActionType
|
||||
*/
|
||||
EvictionActionType action() default EvictionActionType.LOCAL_DESTROY;
|
||||
|
||||
/**
|
||||
* Threshold applied for entry count Eviction.
|
||||
*
|
||||
* Defaults to {@link EvictionAttributes#DEFAULT_ENTRIES_MAXIMUM}
|
||||
*/
|
||||
int maximum() default EvictionAttributes.DEFAULT_ENTRIES_MAXIMUM;
|
||||
|
||||
/**
|
||||
* Name of a Spring bean of type {@link ObjectSizer} defined in the Spring context used
|
||||
* to size {@link Region} entry values.
|
||||
*
|
||||
* Defaults to empty.
|
||||
*
|
||||
* @see com.gemstone.gemfire.cache.util.ObjectSizer
|
||||
*/
|
||||
String objectSizerName() default "";
|
||||
|
||||
/**
|
||||
* Names of {@link Region Regions} for which this Eviction policy applies.
|
||||
*
|
||||
* Defaults to empty.
|
||||
*/
|
||||
String[] regionNames() default {};
|
||||
|
||||
/**
|
||||
* Eviction alorithm used during Eviction.
|
||||
*
|
||||
* Defaults to {@link EvictionPolicyType#ENTRY_COUNT}.
|
||||
*
|
||||
* @see org.springframework.data.gemfire.EvictionPolicyType
|
||||
*/
|
||||
EvictionPolicyType type() default EvictionPolicyType.ENTRY_COUNT;
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,466 @@
|
||||
/*
|
||||
* Copyright 2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.springframework.data.gemfire.config.annotation;
|
||||
|
||||
import static org.springframework.data.gemfire.config.annotation.EnableEviction.EvictionPolicy;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import com.gemstone.gemfire.cache.EvictionAttributes;
|
||||
import com.gemstone.gemfire.cache.Region;
|
||||
import com.gemstone.gemfire.cache.util.ObjectSizer;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.ImportAware;
|
||||
import org.springframework.core.annotation.AnnotationAttributes;
|
||||
import org.springframework.core.type.AnnotationMetadata;
|
||||
import org.springframework.data.gemfire.EvictionActionType;
|
||||
import org.springframework.data.gemfire.EvictionAttributesFactoryBean;
|
||||
import org.springframework.data.gemfire.EvictionPolicyType;
|
||||
import org.springframework.data.gemfire.RegionFactoryBean;
|
||||
import org.springframework.data.gemfire.RegionLookupFactoryBean;
|
||||
import org.springframework.data.gemfire.client.ClientRegionFactoryBean;
|
||||
import org.springframework.data.gemfire.util.ArrayUtils;
|
||||
import org.springframework.data.gemfire.util.CollectionUtils;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* The {@link EvictionConfiguration} class is a Spring {@link Configuration @Configuration} annotated class to enable
|
||||
* Eviction policy configuration on GemFire/Geode {@link Region Regions}.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.springframework.beans.factory.config.BeanPostProcessor
|
||||
* @see org.springframework.context.ApplicationContext
|
||||
* @see org.springframework.context.ApplicationContextAware
|
||||
* @see org.springframework.context.annotation.Bean
|
||||
* @see org.springframework.context.annotation.Configuration
|
||||
* @see org.springframework.context.annotation.ImportAware
|
||||
* @see org.springframework.data.gemfire.EvictionActionType
|
||||
* @see org.springframework.data.gemfire.EvictionAttributesFactoryBean
|
||||
* @see org.springframework.data.gemfire.EvictionPolicyType
|
||||
* @see org.springframework.data.gemfire.RegionFactoryBean
|
||||
* @see org.springframework.data.gemfire.client.ClientRegionFactoryBean
|
||||
* @see com.gemstone.gemfire.cache.EvictionAttributes
|
||||
* @see com.gemstone.gemfire.cache.Region
|
||||
* @since 1.9.0
|
||||
*/
|
||||
@Configuration
|
||||
public class EvictionConfiguration implements ApplicationContextAware, ImportAware {
|
||||
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
private EvictionPolicyConfigurer evictionPolicyConfigurer;
|
||||
|
||||
/**
|
||||
* Determines whether the Spring bean is an instance of {@link RegionFactoryBean}
|
||||
* or {@link ClientRegionFactoryBean}.
|
||||
*
|
||||
* @param bean Spring bean to evaluate.
|
||||
* @return a boolean value indicating whether the Spring bean is an instance of {@link RegionFactoryBean}.
|
||||
* @see org.springframework.data.gemfire.RegionFactoryBean
|
||||
* @see org.springframework.data.gemfire.client.ClientRegionFactoryBean
|
||||
*/
|
||||
protected static boolean isRegionFactoryBean(Object bean) {
|
||||
return (bean instanceof RegionFactoryBean || bean instanceof ClientRegionFactoryBean);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link Annotation} {@link Class type} that enables and configures Eviction.
|
||||
*
|
||||
* @return the {@link Annotation} {@link Class type} to enable and configure Eviction.
|
||||
* @see java.lang.annotation.Annotation
|
||||
* @see java.lang.Class
|
||||
*/
|
||||
protected Class<? extends Annotation> getAnnotationType() {
|
||||
return EnableEviction.class;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the {@link Annotation} type that enables and configures Eviction.
|
||||
*
|
||||
* @return the name of the {@link Annotation} type that enables and configures Eviction.
|
||||
* @see java.lang.Class#getName()
|
||||
* @see #getAnnotationType()
|
||||
*/
|
||||
protected String getAnnotationTypeName() {
|
||||
return getAnnotationType().getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the simple name of the {@link Annotation} type that enables and configures Eviction.
|
||||
*
|
||||
* @return the simple name of the {@link Annotation} type that enables and configures Eviction.
|
||||
* @see java.lang.Class#getSimpleName()
|
||||
* @see #getAnnotationType()
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
protected String getAnnotationTypeSimpleName() {
|
||||
return getAnnotationType().getSimpleName();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
@Override
|
||||
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
|
||||
this.applicationContext = applicationContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
@Override
|
||||
public void setImportMetadata(AnnotationMetadata importMetadata) {
|
||||
if (importMetadata.hasAnnotation(getAnnotationTypeName())) {
|
||||
Map<String, Object> enableEvictionAttributes =
|
||||
importMetadata.getAnnotationAttributes(getAnnotationTypeName());
|
||||
|
||||
AnnotationAttributes[] policies = (AnnotationAttributes[]) enableEvictionAttributes.get("policies");
|
||||
|
||||
for (AnnotationAttributes evictionPolicyAttributes
|
||||
: ArrayUtils.nullSafeArray(policies, AnnotationAttributes.class)) {
|
||||
|
||||
this.evictionPolicyConfigurer = ComposableEvictionPolicyConfigurer.compose(
|
||||
this.evictionPolicyConfigurer, EvictionPolicyMetaData.from(evictionPolicyAttributes,
|
||||
this.applicationContext));
|
||||
}
|
||||
|
||||
this.evictionPolicyConfigurer = (this.evictionPolicyConfigurer != null ? this.evictionPolicyConfigurer
|
||||
: EvictionPolicyMetaData.fromDefaults());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reference to the configured {@link EvictionPolicyConfigurer} used to configure the Eviction policy
|
||||
* of a {@link Region}.
|
||||
*
|
||||
* @return a reference to the configured {@link EvictionPolicyConfigurer}.
|
||||
* @see org.springframework.data.gemfire.config.annotation.EvictionConfiguration.EvictionPolicyConfigurer
|
||||
*/
|
||||
protected EvictionPolicyConfigurer getEvictionPolicyConfigurer() {
|
||||
Assert.state(this.evictionPolicyConfigurer != null,
|
||||
"EvictionPolicyConfigurer was not properly configured and initialized");
|
||||
|
||||
return this.evictionPolicyConfigurer;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@SuppressWarnings("unused")
|
||||
public BeanPostProcessor evictionBeanPostProcessor() {
|
||||
return new BeanPostProcessor() {
|
||||
@Override
|
||||
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
|
||||
return (isRegionFactoryBean(bean) ? getEvictionPolicyConfigurer().configure(bean) : bean);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
|
||||
return bean;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link EvictionPolicyConfigurer} configures the Eviction policy of a GemFire {@link Region}.
|
||||
*/
|
||||
protected interface EvictionPolicyConfigurer {
|
||||
|
||||
/**
|
||||
* Configure the Eviction policy on the given SDG {@link RegionFactoryBean} or {@link ClientRegionFactoryBean}
|
||||
* used to create a GemFire {@link Region}.
|
||||
*
|
||||
* @param regionFactoryBean {@link RegionFactoryBean} or {@link ClientRegionFactoryBean} used to create
|
||||
* a GemFire {@link Region}.
|
||||
* @return the given {@code regionFactoryBean}.
|
||||
* @see org.springframework.data.gemfire.RegionFactoryBean
|
||||
* @see org.springframework.data.gemfire.client.ClientRegionFactoryBean
|
||||
*/
|
||||
Object configure(Object regionFactoryBean);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link ComposableEvictionPolicyConfigurer} is a {@link EvictionPolicyConfigurer} implementation that composes
|
||||
* multiple {@link EvictionPolicyConfigurer} objects into a composition using the Composite Software Design Pattern
|
||||
* making the composition appear as a single {@link EvictionPolicyConfigurer}.
|
||||
*
|
||||
* @see org.springframework.data.gemfire.config.annotation.EvictionConfiguration.EvictionPolicyConfigurer
|
||||
*/
|
||||
protected static class ComposableEvictionPolicyConfigurer implements EvictionPolicyConfigurer {
|
||||
|
||||
private final EvictionPolicyConfigurer one;
|
||||
private final EvictionPolicyConfigurer two;
|
||||
|
||||
/**
|
||||
* Composes the array of {@link EvictionPolicyConfigurer} objects into a single
|
||||
* {@link EvictionPolicyConfigurer} implementation using the Composite Software Design Pattern.
|
||||
*
|
||||
* @param array array of {@link EvictionPolicyConfigurer} objects to compose.
|
||||
* @return an {@link EvictionPolicyConfigurer} implementation composed from the array
|
||||
* of {@link EvictionPolicyConfigurer} objects.
|
||||
* @see org.springframework.data.gemfire.config.annotation.EvictionConfiguration.EvictionPolicyConfigurer
|
||||
* @see #compose(Iterable)
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
protected static EvictionPolicyConfigurer compose(EvictionPolicyConfigurer[] array) {
|
||||
return compose(Arrays.asList(ArrayUtils.nullSafeArray(array, EvictionPolicyConfigurer.class)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Composes the {@link Iterable} of {@link EvictionPolicyConfigurer} objects into a single
|
||||
* {@link EvictionPolicyConfigurer} implementation using the Composite Software Design Pattern.
|
||||
*
|
||||
* @param iterable {@link Iterable} of {@link EvictionPolicyConfigurer} objects to compose.
|
||||
* @return an {@link EvictionPolicyConfigurer} implementation composed from the {@link Iterable}
|
||||
* of {@link EvictionPolicyConfigurer} objects.
|
||||
* @see org.springframework.data.gemfire.config.annotation.EvictionConfiguration.EvictionPolicyConfigurer
|
||||
* @see #compose(EvictionPolicyConfigurer, EvictionPolicyConfigurer)
|
||||
*/
|
||||
protected static EvictionPolicyConfigurer compose(Iterable<EvictionPolicyConfigurer> iterable) {
|
||||
EvictionPolicyConfigurer current = null;
|
||||
|
||||
for (EvictionPolicyConfigurer evictionPolicyConfigurer : CollectionUtils.nullSafeIterable(iterable)) {
|
||||
current = compose(current, evictionPolicyConfigurer);
|
||||
}
|
||||
|
||||
return current;
|
||||
}
|
||||
|
||||
/**
|
||||
* Composes two {@link EvictionPolicyConfigurer} objects into a composition object
|
||||
* implementing the {@link EvictionPolicyConfigurer} interface.
|
||||
*
|
||||
* @param one first {@link EvictionPolicyConfigurer} object to compose.
|
||||
* @param two second {@link EvictionPolicyConfigurer} object to compose.
|
||||
* @return an {@link EvictionPolicyConfigurer} object implementation composed of
|
||||
* multiple {@link EvictionPolicyConfigurer} objects using the Composite Software Design Pattern.
|
||||
*/
|
||||
protected static EvictionPolicyConfigurer compose(EvictionPolicyConfigurer one, EvictionPolicyConfigurer two) {
|
||||
return (one == null ? two : (two == null ? one : new ComposableEvictionPolicyConfigurer(one, two)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new instance of the {@link ComposableEvictionPolicyConfigurer} initialized with the two
|
||||
* {@link EvictionPolicyConfigurer} objects.
|
||||
*
|
||||
* @param one first {@link EvictionPolicyConfigurer} object to compose.
|
||||
* @param two second {@link EvictionPolicyConfigurer} object to compose.
|
||||
*/
|
||||
private ComposableEvictionPolicyConfigurer(EvictionPolicyConfigurer one, EvictionPolicyConfigurer two) {
|
||||
this.one = one;
|
||||
this.two = two;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
@Override
|
||||
public Object configure(Object regionFactoryBean) {
|
||||
return two.configure(one.configure(regionFactoryBean));
|
||||
}
|
||||
}
|
||||
|
||||
protected static class EvictionPolicyMetaData implements EvictionPolicyConfigurer {
|
||||
|
||||
protected static final String[] ALL_REGIONS = new String[0];
|
||||
|
||||
private final EvictionAttributes evictionAttributes;
|
||||
|
||||
private final Set<String> regionNames = new HashSet<String>();
|
||||
|
||||
protected static EvictionPolicyMetaData from(AnnotationAttributes evictionPolicyAttributes,
|
||||
ApplicationContext applicationContext) {
|
||||
|
||||
return from((Integer) evictionPolicyAttributes.get("maximum"),
|
||||
evictionPolicyAttributes.<EvictionPolicyType>getEnum("type"),
|
||||
evictionPolicyAttributes.<EvictionActionType>getEnum("action"),
|
||||
resolveObjectSizer(evictionPolicyAttributes.getString("objectSizerName"), applicationContext),
|
||||
evictionPolicyAttributes.getStringArray("regionNames"));
|
||||
}
|
||||
|
||||
protected static EvictionPolicyMetaData from(EvictionPolicy evictionPolicy,
|
||||
ApplicationContext applicationContext) {
|
||||
|
||||
return from(evictionPolicy.maximum(), evictionPolicy.type(), evictionPolicy.action(),
|
||||
resolveObjectSizer(evictionPolicy.objectSizerName(), applicationContext), evictionPolicy.regionNames());
|
||||
}
|
||||
|
||||
protected static EvictionPolicyMetaData from(int maximum, EvictionPolicyType type, EvictionActionType action,
|
||||
ObjectSizer objectSizer, String... regionNames) {
|
||||
|
||||
EvictionAttributesFactoryBean factoryBean = new EvictionAttributesFactoryBean();
|
||||
|
||||
factoryBean.setAction(action.getEvictionAction());
|
||||
factoryBean.setObjectSizer(objectSizer);
|
||||
factoryBean.setThreshold(resolveThreshold(maximum, type));
|
||||
factoryBean.setType(type);
|
||||
factoryBean.afterPropertiesSet();
|
||||
|
||||
return new EvictionPolicyMetaData(factoryBean.getObject(), regionNames);
|
||||
}
|
||||
|
||||
protected static EvictionPolicyMetaData fromDefaults() {
|
||||
return new EvictionPolicyMetaData(EvictionAttributes.createLRUEntryAttributes());
|
||||
}
|
||||
|
||||
protected static ObjectSizer resolveObjectSizer(String objectSizerName, ApplicationContext applicationContext) {
|
||||
boolean resolvable = StringUtils.hasText(objectSizerName)
|
||||
&& applicationContext.containsBean(objectSizerName);
|
||||
|
||||
return (resolvable ? applicationContext.getBean(objectSizerName, ObjectSizer.class) : null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves the Eviction policy threshold (a.k.a. maximum) based on the {@link EvictionPolicyType}.
|
||||
*
|
||||
* For instance {@link EvictionPolicyType#HEAP_PERCENTAGE} does not support maximum/threshold since
|
||||
* the settings are determined by the GemFire/Geode cache critical heap percentage and eviction heap percentage
|
||||
* System property settings.
|
||||
*
|
||||
* @param maximum integer value specifying the configured Eviction threshold.
|
||||
* @param type {@link EvictionPolicyType} specifying the type of Eviction algorithm.
|
||||
* @return a resolved value for the Eviction maximum/threshold.
|
||||
* @see org.springframework.data.gemfire.EvictionPolicyType
|
||||
*/
|
||||
protected static Integer resolveThreshold(int maximum, EvictionPolicyType type) {
|
||||
return (EvictionPolicyType.HEAP_PERCENTAGE.equals(type) ? null : maximum);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an instance of {@link EvictionPolicyMetaData} initialized with the given
|
||||
* {@link EvictionAttributes} applying to all {@link Region Regions}.
|
||||
*
|
||||
* @param evictionAttributes {@link EvictionAttributes} specifying the Eviction policy configuration
|
||||
* for a {@link Region}.
|
||||
* @see com.gemstone.gemfire.cache.EvictionAttributes
|
||||
* @see #EvictionPolicyMetaData(EvictionAttributes, String[])
|
||||
*/
|
||||
protected EvictionPolicyMetaData(EvictionAttributes evictionAttributes) {
|
||||
this(evictionAttributes, ALL_REGIONS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an instance of {@link EvictionPolicyMetaData} initialized with the given
|
||||
* {@link EvictionAttributes} to apply to the specific {@link Region Regions}.
|
||||
*
|
||||
* @param evictionAttributes {@link EvictionAttributes} specifying the Eviction policy configuration
|
||||
* for a {@link Region}.
|
||||
* @param regionNames names of {@link Region Regions} on which the Eviction policy is applied.
|
||||
* @see com.gemstone.gemfire.cache.EvictionAttributes
|
||||
*/
|
||||
protected EvictionPolicyMetaData(EvictionAttributes evictionAttributes, String[] regionNames) {
|
||||
Assert.notNull(evictionAttributes, "EvictionAttributes must not be null");
|
||||
|
||||
this.evictionAttributes = evictionAttributes;
|
||||
Collections.addAll(this.regionNames, ArrayUtils.nullSafeArray(regionNames, String.class));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an instance of the {@link EvictionAttributes} specifying the Eviction policy configuration
|
||||
* captured in this Eviction policy meta-data.
|
||||
*
|
||||
* @return an instance of the {@link EvictionAttributes} specifying the {@link Region}
|
||||
* Eviction policy configuration.
|
||||
* @throws IllegalStateException if the {@link EvictionAttributes} were not properly initialized.
|
||||
* @see com.gemstone.gemfire.cache.EvictionAttributes
|
||||
*/
|
||||
protected EvictionAttributes getEvictionAttributes() {
|
||||
Assert.state(this.evictionAttributes != null,
|
||||
"EvictionAttributes was not properly configured and initialized");
|
||||
|
||||
return this.evictionAttributes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the given {@link Object} (e.g. Spring bean) is accepted for Eviction policy configuration.
|
||||
*
|
||||
* @param regionFactoryBean {@link Object} being evaluated as an Eviction policy configuration candidate.
|
||||
* @return a boolean value indicating whether the {@link Object} is accepted for Eviction policy configuration.
|
||||
* @see #isRegionFactoryBean(Object)
|
||||
* @see #resolveRegionName(Object)
|
||||
* @see #accepts(String)
|
||||
*/
|
||||
protected boolean accepts(Object regionFactoryBean) {
|
||||
return (isRegionFactoryBean(regionFactoryBean) && accepts(resolveRegionName(regionFactoryBean)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the {@link Region} identified by name is accepted for Eviction policy configuration.
|
||||
*
|
||||
* @param regionName name of the {@link Region} targeted for Eviction policy configuration.
|
||||
* @return a boolean value if the named {@link Region} is accepted for Eviction policy configuration.
|
||||
*/
|
||||
protected boolean accepts(String regionName) {
|
||||
return (this.regionNames.isEmpty() || this.regionNames.contains(regionName));
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves the name of a given {@link Region} from the corresponding {@link RegionLookupFactoryBean} object.
|
||||
*
|
||||
* @param regionFactoryBean {@link RegionLookupFactoryBean} from which to resolve the {@link Region} name.
|
||||
* @return the resolved name of the {@link Region} created from the given {@link RegionLookupFactoryBean}.
|
||||
* @see org.springframework.data.gemfire.RegionLookupFactoryBean#resolveRegionName()
|
||||
*/
|
||||
protected String resolveRegionName(Object regionFactoryBean) {
|
||||
return (regionFactoryBean instanceof RegionLookupFactoryBean
|
||||
? ((RegionLookupFactoryBean) regionFactoryBean).resolveRegionName() : null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the {@link EvictionAttributes} on the {@link RegionFactoryBean} or {@link ClientRegionFactoryBean}
|
||||
* used to create the targeted {@link Region}.
|
||||
*
|
||||
* @param regionFactoryBean {@link RegionFactoryBean} or {@link ClientRegionFactoryBean} on which to
|
||||
* set the {@link EvictionAttributes} encapsulating the Eviction policy for the targeted {@link Region}.
|
||||
* @return the {@code regionFactoryBean}.
|
||||
* @see org.springframework.data.gemfire.RegionFactoryBean#setEvictionAttributes(EvictionAttributes)
|
||||
* @see org.springframework.data.gemfire.client.ClientRegionFactoryBean#setEvictionAttributes(EvictionAttributes)
|
||||
* @see com.gemstone.gemfire.cache.EvictionAttributes
|
||||
* @see #getEvictionAttributes()
|
||||
*/
|
||||
protected Object setEvictionAttributes(Object regionFactoryBean) {
|
||||
if (regionFactoryBean instanceof RegionFactoryBean) {
|
||||
((RegionFactoryBean) regionFactoryBean).setEvictionAttributes(getEvictionAttributes());
|
||||
}
|
||||
else {
|
||||
((ClientRegionFactoryBean) regionFactoryBean).setEvictionAttributes(getEvictionAttributes());
|
||||
}
|
||||
|
||||
return regionFactoryBean;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
@Override
|
||||
public Object configure(Object regionFactoryBean) {
|
||||
return (accepts(regionFactoryBean) ? setEvictionAttributes(regionFactoryBean) : regionFactoryBean);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -28,6 +28,10 @@ import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import com.gemstone.gemfire.cache.DataPolicy;
|
||||
import com.gemstone.gemfire.cache.Region;
|
||||
import com.gemstone.gemfire.cache.Scope;
|
||||
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Ignore;
|
||||
@@ -52,10 +56,6 @@ import org.springframework.data.gemfire.test.support.ZipUtils;
|
||||
import org.springframework.util.FileSystemUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import com.gemstone.gemfire.cache.DataPolicy;
|
||||
import com.gemstone.gemfire.cache.Region;
|
||||
import com.gemstone.gemfire.cache.Scope;
|
||||
|
||||
/**
|
||||
* The CacheClusterConfigurationIntegrationTest class is a test suite of test cases testing the integration of
|
||||
* Spring Data GemFire with GemFire 8's new shared, persistent, cluster configuration service.
|
||||
@@ -82,15 +82,15 @@ public class CacheClusterConfigurationIntegrationTest {
|
||||
@Rule
|
||||
public TestRule watchman = new TestWatcher() {
|
||||
@Override
|
||||
protected void failed(final Throwable t, final Description description) {
|
||||
protected void failed(Throwable throwable, Description description) {
|
||||
System.err.println(String.format("Test '%1$s' failed...", description.getDisplayName()));
|
||||
System.err.println(ThrowableUtils.toString(t));
|
||||
System.err.println(ThrowableUtils.toString(throwable));
|
||||
System.err.println("Locator process log file contents were...");
|
||||
System.err.println(getLocatorProcessOutput(description));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void finished(final Description description) {
|
||||
protected void finished(Description description) {
|
||||
if (Boolean.valueOf(System.getProperty("spring.gemfire.fork.clean", Boolean.TRUE.toString()))) {
|
||||
try {
|
||||
FileUtils.write(new File(locatorWorkingDirectory.getParent(),
|
||||
@@ -103,7 +103,7 @@ public class CacheClusterConfigurationIntegrationTest {
|
||||
}
|
||||
}
|
||||
|
||||
private String getLocatorProcessOutput(final Description description) {
|
||||
private String getLocatorProcessOutput(Description description) {
|
||||
try {
|
||||
String locatorProcessOutputString = StringUtils.collectionToDelimitedString(locatorProcessOutput,
|
||||
FileUtils.LINE_SEPARATOR, String.format("[%1$s] - ", description.getMethodName()), "");
|
||||
@@ -132,6 +132,8 @@ public class CacheClusterConfigurationIntegrationTest {
|
||||
List<String> arguments = new ArrayList<String>();
|
||||
|
||||
arguments.add("-Dgemfire.name=" + locatorName);
|
||||
arguments.add("-Dgemfire.mcast-port=0");
|
||||
arguments.add("-Dgemfire.log-level=error");
|
||||
arguments.add("-Dspring.gemfire.enable-cluster-configuration=true");
|
||||
arguments.add("-Dspring.gemfire.load-cluster-configuration=true");
|
||||
|
||||
@@ -192,11 +194,11 @@ public class CacheClusterConfigurationIntegrationTest {
|
||||
return baseLocation.concat(File.separator).concat(configLocation);
|
||||
}
|
||||
|
||||
protected Region getRegion(final ConfigurableApplicationContext applicationContext, final String regionBeanName) {
|
||||
protected Region getRegion(ConfigurableApplicationContext applicationContext, String regionBeanName) {
|
||||
return applicationContext.getBean(regionBeanName, Region.class);
|
||||
}
|
||||
|
||||
protected ConfigurableApplicationContext newApplicationContext(final String... configLocations) {
|
||||
protected ConfigurableApplicationContext newApplicationContext(String... configLocations) {
|
||||
ConfigurableApplicationContext applicationContext = new ClassPathXmlApplicationContext(configLocations);
|
||||
applicationContext.registerShutdownHook();
|
||||
return applicationContext;
|
||||
@@ -205,7 +207,7 @@ public class CacheClusterConfigurationIntegrationTest {
|
||||
@Test
|
||||
@Ignore
|
||||
// TODO re-enable the test once the GemFire Cluster Configuration Service race condition has been properly fixed!
|
||||
public void testClusterConfiguration() {
|
||||
public void clusterConfigurationTest() {
|
||||
ConfigurableApplicationContext applicationContext = newApplicationContext(
|
||||
getLocation("cacheUsingClusterConfigurationIntegrationTest.xml"));
|
||||
|
||||
@@ -226,17 +228,18 @@ public class CacheClusterConfigurationIntegrationTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLocalOnlyConfiguration() {
|
||||
public void localConfigurationTest() {
|
||||
try {
|
||||
newApplicationContext(getLocation("cacheUsingLocalOnlyConfigurationIntegrationTest.xml"));
|
||||
|
||||
fail("Loading the 'cacheUsingLocalOnlyConfigurationIntegrationTest.xml' Spring ApplicationContext"
|
||||
+ " configuration file should have resulted in an Exception due to the Region lookup on"
|
||||
+ " 'ClusterConfigRegion' when GemFire Cluster Configuration is disabled!");
|
||||
}
|
||||
catch (BeanCreationException expected) {
|
||||
assertTrue(expected.getCause() instanceof BeanInitializationException);
|
||||
assertTrue(expected.getCause().getMessage().contains("Cannot find Region [ClusterConfigRegion] in Cache"));
|
||||
assertTrue(expected.getCause().getMessage().matches(
|
||||
"Region \\[ClusterConfigRegion\\] in Cache \\[.*\\] not found"));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -15,9 +15,9 @@
|
||||
*/
|
||||
package org.springframework.data.gemfire.client;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.equalTo;
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.CoreMatchers.notNullValue;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.notNullValue;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
@@ -37,14 +37,6 @@ import static org.mockito.Mockito.when;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.data.gemfire.TestUtils;
|
||||
import org.springframework.data.gemfire.config.xml.GemfireConstants;
|
||||
|
||||
import com.gemstone.gemfire.cache.DataPolicy;
|
||||
import com.gemstone.gemfire.cache.EvictionAttributes;
|
||||
import com.gemstone.gemfire.cache.ExpirationAttributes;
|
||||
@@ -57,6 +49,14 @@ import com.gemstone.gemfire.cache.client.ClientRegionShortcut;
|
||||
import com.gemstone.gemfire.cache.client.Pool;
|
||||
import com.gemstone.gemfire.compression.Compressor;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.data.gemfire.TestUtils;
|
||||
import org.springframework.data.gemfire.config.xml.GemfireConstants;
|
||||
|
||||
/**
|
||||
* @author David Turanski
|
||||
* @author John Blum
|
||||
@@ -79,7 +79,7 @@ public class ClientRegionFactoryBeanTest {
|
||||
@Test
|
||||
@SuppressWarnings({ "deprecation", "unchecked" })
|
||||
public void testLookupFallbackUsingDefaultShortcut() throws Exception {
|
||||
final String testRegionName = "TestRegion";
|
||||
String testRegionName = "TestRegion";
|
||||
|
||||
ClientCache mockClientCache = mock(ClientCache.class);
|
||||
ClientRegionFactory mockClientRegionFactory = mock(ClientRegionFactory.class);
|
||||
@@ -119,9 +119,12 @@ public class ClientRegionFactoryBeanTest {
|
||||
when(mockPool.getName()).thenReturn("TestPoolTwo");
|
||||
when(mockSnapshot.getInputStream()).thenReturn(mock(InputStream.class));
|
||||
|
||||
EvictionAttributes evictionAttributes = EvictionAttributes.createLRUEntryAttributes();
|
||||
|
||||
factoryBean.setAttributes(mockRegionAttributes);
|
||||
factoryBean.setBeanFactory(mockBeanFactory);
|
||||
factoryBean.setDiskStoreName("TestDiskStoreTwo");
|
||||
factoryBean.setEvictionAttributes(evictionAttributes);
|
||||
factoryBean.setPersistent(false);
|
||||
factoryBean.setPoolName("TestPoolTwo");
|
||||
factoryBean.setSnapshot(mockSnapshot);
|
||||
@@ -142,7 +145,7 @@ public class ClientRegionFactoryBeanTest {
|
||||
verify(mockClientRegionFactory, times(1)).setDiskSynchronous(eq(false));
|
||||
verify(mockClientRegionFactory, times(1)).setEntryIdleTimeout(any(ExpirationAttributes.class));
|
||||
verify(mockClientRegionFactory, times(1)).setEntryTimeToLive(any(ExpirationAttributes.class));
|
||||
verify(mockClientRegionFactory, times(1)).setEvictionAttributes(any(EvictionAttributes.class));
|
||||
verify(mockClientRegionFactory, times(1)).setEvictionAttributes(eq(evictionAttributes));
|
||||
verify(mockClientRegionFactory, times(1)).setInitialCapacity(eq(101));
|
||||
verify(mockClientRegionFactory, times(1)).setKeyConstraint(eq(Long.class));
|
||||
verify(mockClientRegionFactory, times(1)).setLoadFactor(eq(0.75f));
|
||||
@@ -154,7 +157,7 @@ public class ClientRegionFactoryBeanTest {
|
||||
verify(mockClientRegionFactory, times(1)).setPoolName(eq("TestPoolTwo"));
|
||||
verify(mockClientRegionFactory, times(1)).setDiskStoreName(eq("TestDiskStoreTwo"));
|
||||
verify(mockClientRegionFactory, times(1)).create(eq(testRegionName));
|
||||
verify(mockRegion, times(1)).loadSnapshot(any(InputStream.class));
|
||||
verify(mockRegion, never()).loadSnapshot(any(InputStream.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -430,7 +433,7 @@ public class ClientRegionFactoryBeanTest {
|
||||
factoryBean.resolveClientRegionShortcut();
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
assertEquals("Client Region Shortcut 'CACHING_PROXY' is invalid when persistent is true.",
|
||||
assertEquals("Client Region Shortcut 'CACHING_PROXY' is invalid when persistent is true",
|
||||
expected.getMessage());
|
||||
throw expected;
|
||||
}
|
||||
@@ -457,7 +460,7 @@ public class ClientRegionFactoryBeanTest {
|
||||
factoryBean.resolveClientRegionShortcut();
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
assertEquals("Client Region Shortcut 'LOCAL_PERSISTENT' is invalid when persistent is false.",
|
||||
assertEquals("Client Region Shortcut 'LOCAL_PERSISTENT' is invalid when persistent is false",
|
||||
expected.getMessage());
|
||||
throw expected;
|
||||
}
|
||||
@@ -504,7 +507,7 @@ public class ClientRegionFactoryBeanTest {
|
||||
factoryBean.resolveClientRegionShortcut();
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
assertEquals("Data Policy 'NORMAL' is invalid when persistent is true.", expected.getMessage());
|
||||
assertEquals("Data Policy 'NORMAL' is invalid when persistent is true", expected.getMessage());
|
||||
throw expected;
|
||||
}
|
||||
}
|
||||
@@ -530,7 +533,7 @@ public class ClientRegionFactoryBeanTest {
|
||||
factoryBean.resolveClientRegionShortcut();
|
||||
}
|
||||
catch (IllegalArgumentException expected) {
|
||||
assertEquals("Data Policy 'PERSISTENT_REPLICATE' is invalid when persistent is false.", expected.getMessage());
|
||||
assertEquals("Data Policy 'PERSISTENT_REPLICATE' is invalid when persistent is false", expected.getMessage());
|
||||
throw expected;
|
||||
}
|
||||
}
|
||||
@@ -686,5 +689,4 @@ public class ClientRegionFactoryBeanTest {
|
||||
|
||||
clientRegionFactoryBean.destroy();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,277 @@
|
||||
/*
|
||||
* Copyright 2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
package org.springframework.data.gemfire.config.annotation;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Matchers.anyString;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.springframework.data.gemfire.config.annotation.EnableEviction.EvictionPolicy;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import com.gemstone.gemfire.cache.Cache;
|
||||
import com.gemstone.gemfire.cache.EvictionAttributes;
|
||||
import com.gemstone.gemfire.cache.Region;
|
||||
import com.gemstone.gemfire.cache.RegionAttributes;
|
||||
import com.gemstone.gemfire.cache.RegionFactory;
|
||||
import com.gemstone.gemfire.cache.util.ObjectSizer;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Test;
|
||||
import org.mockito.invocation.InvocationOnMock;
|
||||
import org.mockito.stubbing.Answer;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.gemfire.EvictionActionType;
|
||||
import org.springframework.data.gemfire.EvictionAttributesFactoryBean;
|
||||
import org.springframework.data.gemfire.EvictionPolicyType;
|
||||
import org.springframework.data.gemfire.PartitionedRegionFactoryBean;
|
||||
import org.springframework.data.gemfire.ReplicatedRegionFactoryBean;
|
||||
import org.springframework.data.gemfire.util.ArrayUtils;
|
||||
|
||||
/**
|
||||
* Unit tests for the {@link EnableEviction} annotation and {@link EvictionConfiguration} class.
|
||||
*
|
||||
* @author John Blum
|
||||
* @see org.junit.Test
|
||||
* @see org.mockito.Mockito
|
||||
* @see org.springframework.data.gemfire.config.annotation.EnableEviction
|
||||
* @see org.springframework.data.gemfire.config.annotation.EvictionConfiguration
|
||||
* @see org.springframework.data.gemfire.EvictionAttributesFactoryBean
|
||||
* @see com.gemstone.gemfire.cache.Region
|
||||
* @see com.gemstone.gemfire.cache.EvictionAttributes
|
||||
* @since 1.9.0
|
||||
*/
|
||||
public class EnableEvictionConfigurationUnitTests {
|
||||
|
||||
private ConfigurableApplicationContext applicationContext;
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
if (applicationContext != null) {
|
||||
applicationContext.close();
|
||||
}
|
||||
}
|
||||
|
||||
protected void assertEvictionAttributes(Region region, EvictionAttributes expectedEvictionAttributes) {
|
||||
assertThat(region).isNotNull();
|
||||
assertThat(region.getAttributes()).isNotNull();
|
||||
assertEvictionAttributes(region.getAttributes().getEvictionAttributes(), expectedEvictionAttributes);
|
||||
}
|
||||
|
||||
protected void assertEvictionAttributes(EvictionAttributes actualEvictionAttributes,
|
||||
EvictionAttributes expectedEvictionAttributes) {
|
||||
|
||||
assertThat(actualEvictionAttributes).isNotNull();
|
||||
assertThat(actualEvictionAttributes.getAction()).isEqualTo(expectedEvictionAttributes.getAction());
|
||||
assertThat(actualEvictionAttributes.getAlgorithm()).isEqualTo(expectedEvictionAttributes.getAlgorithm());
|
||||
assertThat(actualEvictionAttributes.getObjectSizer()).isEqualTo(expectedEvictionAttributes.getObjectSizer());
|
||||
|
||||
if (!EvictionPolicyType.HEAP_PERCENTAGE.equals(
|
||||
EvictionPolicyType.valueOf(actualEvictionAttributes.getAlgorithm()))) {
|
||||
assertThat(actualEvictionAttributes.getMaximum()).isEqualTo(expectedEvictionAttributes.getMaximum());
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
protected <K, V> Region<K, V> getRegion(String beanName) {
|
||||
return applicationContext.getBean(beanName, Region.class);
|
||||
}
|
||||
|
||||
protected AnnotationConfigApplicationContext newApplicationContext(Class<?>... annotatedClasses) {
|
||||
return new AnnotationConfigApplicationContext(annotatedClasses);
|
||||
}
|
||||
|
||||
protected EvictionAttributes newEvictionAttributes(Integer maximum, EvictionPolicyType type, EvictionActionType action,
|
||||
ObjectSizer... objectSizer) {
|
||||
|
||||
EvictionAttributesFactoryBean evictionAttributesFactory = new EvictionAttributesFactoryBean();
|
||||
|
||||
evictionAttributesFactory.setAction(action.getEvictionAction());
|
||||
evictionAttributesFactory.setObjectSizer(ArrayUtils.getFirst(objectSizer));
|
||||
evictionAttributesFactory.setThreshold(maximum);
|
||||
evictionAttributesFactory.setType(type);
|
||||
evictionAttributesFactory.afterPropertiesSet();
|
||||
|
||||
return evictionAttributesFactory.getObject();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void usesDefaultEvictionPolicyConfiguration() {
|
||||
applicationContext = newApplicationContext(DefaultEvictionPolicyConfiguration.class);
|
||||
|
||||
EvictionAttributes defaultEvictionAttributes = EvictionAttributes.createLRUEntryAttributes();
|
||||
|
||||
assertEvictionAttributes(applicationContext.getBean("PartitionRegion", Region.class), defaultEvictionAttributes);
|
||||
assertEvictionAttributes(applicationContext.getBean("ReplicateRegion", Region.class), defaultEvictionAttributes);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void usesCustomEvictionPolicyConfiguration() {
|
||||
applicationContext = newApplicationContext(CustomEvictionPolicyConfiguration.class);
|
||||
|
||||
ObjectSizer mockObjectSizer = applicationContext.getBean("mockObjectSizer", ObjectSizer.class);
|
||||
|
||||
EvictionAttributes customEvictionAttributes = newEvictionAttributes(65536, EvictionPolicyType.MEMORY_SIZE,
|
||||
EvictionActionType.OVERFLOW_TO_DISK, mockObjectSizer);
|
||||
|
||||
assertEvictionAttributes(applicationContext.getBean("PartitionRegion", Region.class), customEvictionAttributes);
|
||||
assertEvictionAttributes(applicationContext.getBean("ReplicateRegion", Region.class), customEvictionAttributes);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void usesRegionSpecificEvictionPolicyConfiguration() {
|
||||
applicationContext = newApplicationContext(RegionSpecificEvictionPolicyConfiguration.class);
|
||||
|
||||
ObjectSizer mockObjectSizer = applicationContext.getBean("mockObjectSizer", ObjectSizer.class);
|
||||
|
||||
EvictionAttributes partitionRegionEvictionAttributes = newEvictionAttributes(null,
|
||||
EvictionPolicyType.HEAP_PERCENTAGE, EvictionActionType.OVERFLOW_TO_DISK, mockObjectSizer);
|
||||
|
||||
EvictionAttributes replicateRegionEvictionAttributes = newEvictionAttributes(10000,
|
||||
EvictionPolicyType.ENTRY_COUNT, EvictionActionType.LOCAL_DESTROY);
|
||||
|
||||
assertEvictionAttributes(applicationContext.getBean("PartitionRegion", Region.class),
|
||||
partitionRegionEvictionAttributes);
|
||||
|
||||
assertEvictionAttributes(applicationContext.getBean("ReplicateRegion", Region.class),
|
||||
replicateRegionEvictionAttributes);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void usesLastMatchingEvictionPolicyConfiguration() {
|
||||
applicationContext = newApplicationContext(LastMatchingWinsEvictionPolicyConfiguration.class);
|
||||
|
||||
EvictionAttributes lastMatchingEvictionAttributes = newEvictionAttributes(99, EvictionPolicyType.ENTRY_COUNT,
|
||||
EvictionActionType.OVERFLOW_TO_DISK);
|
||||
|
||||
assertEvictionAttributes(applicationContext.getBean("PartitionRegion", Region.class),
|
||||
lastMatchingEvictionAttributes);
|
||||
|
||||
assertEvictionAttributes(applicationContext.getBean("ReplicateRegion", Region.class),
|
||||
lastMatchingEvictionAttributes);
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@SuppressWarnings("unused")
|
||||
static class CacheRegionConfiguration {
|
||||
|
||||
@Bean("mockCache")
|
||||
@SuppressWarnings("unchecked")
|
||||
Cache mockCache() {
|
||||
Cache mockCache = mock(Cache.class);
|
||||
|
||||
RegionFactory mockRegionFactory = mock(RegionFactory.class);
|
||||
|
||||
final AtomicReference<EvictionAttributes> evictionAttributes =
|
||||
new AtomicReference<EvictionAttributes>(null);
|
||||
|
||||
when(mockCache.createRegionFactory()).thenReturn(mockRegionFactory);
|
||||
|
||||
when(mockRegionFactory.setEvictionAttributes(any(EvictionAttributes.class))).thenAnswer(
|
||||
new Answer<RegionFactory>() {
|
||||
@Override
|
||||
public RegionFactory answer(InvocationOnMock invocation) throws Throwable {
|
||||
evictionAttributes.set(invocation.getArgumentAt(0, EvictionAttributes.class));
|
||||
return (RegionFactory) invocation.getMock();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
when(mockRegionFactory.create(anyString())).thenAnswer(new Answer<Region>() {
|
||||
@Override
|
||||
public Region answer(InvocationOnMock invocation) throws Throwable {
|
||||
String regionName = invocation.getArgumentAt(0, String.class);
|
||||
|
||||
Region mockRegion = mock(Region.class, regionName);
|
||||
|
||||
RegionAttributes mockRegionAttributes =
|
||||
mock(RegionAttributes.class, regionName.concat("Attributes"));
|
||||
|
||||
when(mockRegion.getName()).thenReturn(regionName);
|
||||
when(mockRegion.getFullPath()).thenReturn(String.format("%1$s%2$s", Region.SEPARATOR, regionName));
|
||||
when(mockRegion.getAttributes()).thenReturn(mockRegionAttributes);
|
||||
when(mockRegionAttributes.getEvictionAttributes()).thenReturn(evictionAttributes.get());
|
||||
|
||||
return mockRegion;
|
||||
}
|
||||
});
|
||||
|
||||
return mockCache;
|
||||
}
|
||||
|
||||
@Bean("PartitionRegion")
|
||||
PartitionedRegionFactoryBean<Object, Object> mockPartitionRegion(Cache gemfireCache) {
|
||||
PartitionedRegionFactoryBean<Object, Object> partitionRegion =
|
||||
new PartitionedRegionFactoryBean<Object, Object>();
|
||||
|
||||
partitionRegion.setCache(gemfireCache);
|
||||
partitionRegion.setClose(false);
|
||||
partitionRegion.setPersistent(false);
|
||||
|
||||
return partitionRegion;
|
||||
}
|
||||
|
||||
@Bean("ReplicateRegion")
|
||||
ReplicatedRegionFactoryBean<Object, Object> mockReplicateRegion(Cache gemfireCache) {
|
||||
ReplicatedRegionFactoryBean<Object, Object> replicateRegion =
|
||||
new ReplicatedRegionFactoryBean<Object, Object>();
|
||||
|
||||
replicateRegion.setCache(gemfireCache);
|
||||
replicateRegion.setClose(false);
|
||||
replicateRegion.setPersistent(false);
|
||||
|
||||
return replicateRegion;
|
||||
}
|
||||
|
||||
@Bean
|
||||
ObjectSizer mockObjectSizer() {
|
||||
return mock(ObjectSizer.class);
|
||||
}
|
||||
}
|
||||
|
||||
@EnableEviction
|
||||
static class DefaultEvictionPolicyConfiguration extends CacheRegionConfiguration {
|
||||
}
|
||||
|
||||
@EnableEviction(policies = @EvictionPolicy(maximum = 65536, type = EvictionPolicyType.MEMORY_SIZE,
|
||||
action = EvictionActionType.OVERFLOW_TO_DISK, objectSizerName = "mockObjectSizer"))
|
||||
static class CustomEvictionPolicyConfiguration extends CacheRegionConfiguration {
|
||||
}
|
||||
|
||||
@EnableEviction(policies = {
|
||||
@EvictionPolicy(maximum = 85, type = EvictionPolicyType.HEAP_PERCENTAGE, action = EvictionActionType.OVERFLOW_TO_DISK,
|
||||
objectSizerName = "mockObjectSizer", regionNames = "PartitionRegion"),
|
||||
@EvictionPolicy(maximum = 10000, type = EvictionPolicyType.ENTRY_COUNT, action = EvictionActionType.LOCAL_DESTROY,
|
||||
regionNames = "ReplicateRegion")
|
||||
})
|
||||
static class RegionSpecificEvictionPolicyConfiguration extends CacheRegionConfiguration {
|
||||
}
|
||||
|
||||
@EnableEviction(policies = {
|
||||
@EvictionPolicy(maximum = 1, type = EvictionPolicyType.ENTRY_COUNT, action = EvictionActionType.LOCAL_DESTROY,
|
||||
objectSizerName = "mockObjectSizer", regionNames = "ReplicateRegion"),
|
||||
@EvictionPolicy(maximum = 99, type = EvictionPolicyType.ENTRY_COUNT, action = EvictionActionType.OVERFLOW_TO_DISK)
|
||||
})
|
||||
static class LastMatchingWinsEvictionPolicyConfiguration extends CacheRegionConfiguration {
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user