Fixes JIRA issue SGF-241 adding support for defining client sub-Regions using the gfe:client-region XML namespace element in an nested fashion.

This commit is contained in:
John Blum
2013-12-09 10:50:16 -08:00
parent 101d977026
commit bb97756f8d
8 changed files with 273 additions and 91 deletions

View File

@@ -50,6 +50,7 @@ import com.gemstone.gemfire.internal.cache.GemFireCacheImpl;
* @author David Turanski
* @author John Blum
*/
@SuppressWarnings("unused")
public class ClientRegionFactoryBean<K, V> extends RegionLookupFactoryBean<K, V> implements BeanFactoryAware,
DisposableBean {
@@ -74,6 +75,8 @@ public class ClientRegionFactoryBean<K, V> extends RegionLookupFactoryBean<K, V>
private Interest<K>[] interests;
private Region<?, ?> parent;
private RegionAttributes<K, V> attributes;
private Resource snapshot;
@@ -96,7 +99,7 @@ public class ClientRegionFactoryBean<K, V> extends RegionLookupFactoryBean<K, V>
Assert.isTrue(((GemFireCacheImpl) cache).isClient(), "A client-cache instance is required.");
}
final ClientCache clientCache = (ClientCache) cache;
ClientCache clientCache = (ClientCache) cache;
ClientRegionFactory<K, V> factory = clientCache.createClientRegionFactory(resolveClientRegionShortcut());
@@ -142,8 +145,18 @@ public class ClientRegionFactoryBean<K, V> extends RegionLookupFactoryBean<K, V>
factory.setDiskStoreName(diskStoreName);
}
Region<K, V> clientRegion = factory.create(regionName);
log.info("Created new cache region [" + regionName + "]");
Region<K, V> clientRegion = (this.parent != null ? factory.createSubregion(parent, regionName)
: factory.create(regionName));
if (log.isInfoEnabled()) {
if (parent != null) {
log.info(String.format("Created new Client Cache sub-Region [%1$s] under parent Region [%2$s].",
regionName, parent.getName()));
}
else {
log.info(String.format("Created new Client Cache Region [%1$s].", regionName));
}
}
if (snapshot != null) {
clientRegion.loadSnapshot(snapshot.getInputStream());
@@ -481,6 +494,10 @@ public class ClientRegionFactoryBean<K, V> extends RegionLookupFactoryBean<K, V>
setDataPolicy(resolvedDataPolicy);
}
public void setParent(Region<?, ?> parent) {
this.parent = parent;
}
protected boolean isPersistent() {
return Boolean.TRUE.equals(persistent);
}

View File

@@ -35,9 +35,10 @@ import org.springframework.util.xml.DomUtils;
import org.w3c.dom.Element;
/**
* Base class for all Region Parsers
*
* Abstract base class encapsulating functionality common to all Region Parsers.
* <p/>
* @author David Turanski
* @author John Blum
*/
abstract class AbstractRegionParser extends AbstractSingleBeanDefinitionParser {
@@ -68,9 +69,7 @@ abstract class AbstractRegionParser extends AbstractSingleBeanDefinitionParser {
protected void doParseCommonRegionConfiguration(Element element, ParserContext parserContext,
BeanDefinitionBuilder builder, BeanDefinitionBuilder regionAttributesBuilder, boolean subRegion) {
String cacheRef = element.getAttribute("cache-ref");
String resolvedCacheRef = (StringUtils.hasText(cacheRef) ? cacheRef
: GemfireConstants.DEFAULT_GEMFIRE_CACHE_NAME);
String resolvedCacheRef = ParsingUtils.resolveCacheReference(element.getAttribute("cache-ref"));
if (!subRegion) {
builder.addPropertyReference("cache", resolvedCacheRef);
@@ -89,9 +88,9 @@ abstract class AbstractRegionParser extends AbstractSingleBeanDefinitionParser {
}
ParsingUtils.parseOptionalRegionAttributes(parserContext, element, regionAttributesBuilder);
ParsingUtils.parseSubscription(parserContext, element, regionAttributesBuilder);
ParsingUtils.parseStatistics(element, regionAttributesBuilder);
ParsingUtils.parseExpiration(parserContext, element, regionAttributesBuilder);
ParsingUtils.parseSubscription(parserContext, element, regionAttributesBuilder);
ParsingUtils.parseEviction(parserContext, element, regionAttributesBuilder);
ParsingUtils.parseMembershipAttributes(parserContext, element, regionAttributesBuilder);
@@ -146,18 +145,6 @@ abstract class AbstractRegionParser extends AbstractSingleBeanDefinitionParser {
}
}
private void parseSubRegions(Element element, ParserContext parserContext, String resolvedCacheRef) {
Map<String, Element> allSubRegionElements = new HashMap<String, Element>();
findSubRegionElements(element, getRegionNameFromElement(element), allSubRegionElements);
if (!CollectionUtils.isEmpty(allSubRegionElements)) {
for (Map.Entry<String, Element> entry : allSubRegionElements.entrySet()) {
parseSubRegion(entry.getValue(), parserContext, entry.getKey(), resolvedCacheRef);
}
}
}
private void parseCollectionOfCustomSubElements(Element element, ParserContext parserContext,
BeanDefinitionBuilder builder, String className, String subElementName, String propertyName) {
List<Element> subElements = DomUtils.getChildElementsByTagName(element,
@@ -174,6 +161,18 @@ abstract class AbstractRegionParser extends AbstractSingleBeanDefinitionParser {
}
}
protected void parseSubRegions(Element element, ParserContext parserContext, String resolvedCacheRef) {
Map<String, Element> allSubRegionElements = new HashMap<String, Element>();
findSubRegionElements(element, getRegionNameFromElement(element), allSubRegionElements);
if (!CollectionUtils.isEmpty(allSubRegionElements)) {
for (Map.Entry<String, Element> entry : allSubRegionElements.entrySet()) {
parseSubRegion(entry.getValue(), parserContext, entry.getKey(), resolvedCacheRef);
}
}
}
private void findSubRegionElements(Element parent, String parentPath, Map<String, Element> allSubRegionElements) {
for (Element element : DomUtils.getChildElements(parent)) {
if (element.getLocalName().endsWith("region")) {

View File

@@ -46,18 +46,19 @@ class ClientRegionParser extends AbstractRegionParser {
}
@Override
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
super.doParse(element, builder);
protected void doParseRegion(Element element, ParserContext parserContext, BeanDefinitionBuilder builder,
boolean subRegion) {
validateDataPolicyShortcutMutualExclusion(element, parserContext);
String cacheRefAttributeValue = element.getAttribute("cache-ref");
String resolvedCacheRef = ParsingUtils.resolveCacheReference(element.getAttribute("cache-ref"));
builder.addPropertyReference("cache", (StringUtils.hasText(cacheRefAttributeValue) ? cacheRefAttributeValue
: GemfireConstants.DEFAULT_GEMFIRE_CACHE_NAME));
if (!subRegion) {
builder.addPropertyReference("cache", resolvedCacheRef);
ParsingUtils.setPropertyValue(element, builder, "close");
ParsingUtils.setPropertyValue(element, builder, "destroy");
}
ParsingUtils.setPropertyValue(element, builder, "close");
ParsingUtils.setPropertyValue(element, builder, "destroy");
ParsingUtils.setPropertyValue(element, builder, "data-policy", "dataPolicyName");
ParsingUtils.setPropertyValue(element, builder, "name");
ParsingUtils.setPropertyValue(element, builder, "persistent");
@@ -72,8 +73,8 @@ class ClientRegionParser extends AbstractRegionParser {
ParsingUtils.parseOptionalRegionAttributes(parserContext, element, regionAttributesBuilder);
ParsingUtils.parseStatistics(element, regionAttributesBuilder);
ParsingUtils.parseEviction(parserContext, element, regionAttributesBuilder);
ParsingUtils.parseExpiration(parserContext, element, regionAttributesBuilder);
ParsingUtils.parseEviction(parserContext, element, regionAttributesBuilder);
builder.addPropertyValue("attributes", regionAttributesBuilder.getBeanDefinition());
@@ -107,14 +108,10 @@ class ClientRegionParser extends AbstractRegionParser {
if (!interests.isEmpty()) {
builder.addPropertyValue("interests", interests);
}
}
@Override
protected void doParseRegion(Element element, ParserContext parserContext, BeanDefinitionBuilder builder,
boolean subRegion) {
throw new UnsupportedOperationException(String.format(
"doParseRegion(:Element, :ParserContext, :BeanDefinitionBuilder, :boolean) is not supported on %1$s",
getClass().getName()));
if (!subRegion) {
parseSubRegions(element, parserContext, resolvedCacheRef);
}
}
private void validateDataPolicyShortcutMutualExclusion(final Element element, final ParserContext parserContext) {
@@ -134,6 +131,12 @@ class ClientRegionParser extends AbstractRegionParser {
}
}
private void parseCommonInterestAttributes(Element element, BeanDefinitionBuilder builder) {
ParsingUtils.setPropertyValue(element, builder, "durable", "durable");
ParsingUtils.setPropertyValue(element, builder, "result-policy", "policy");
ParsingUtils.setPropertyValue(element, builder, "receive-values", "receiveValues");
}
private Object parseKeyInterest(Element keyInterestElement, ParserContext parserContext) {
BeanDefinitionBuilder keyInterestBuilder = BeanDefinitionBuilder.genericBeanDefinition(Interest.class);
@@ -153,10 +156,4 @@ class ClientRegionParser extends AbstractRegionParser {
return regexInterestBuilder.getBeanDefinition();
}
private void parseCommonInterestAttributes(Element element, BeanDefinitionBuilder builder) {
ParsingUtils.setPropertyValue(element, builder, "durable", "durable");
ParsingUtils.setPropertyValue(element, builder, "result-policy", "policy");
ParsingUtils.setPropertyValue(element, builder, "receive-values", "receiveValues");
}
}

View File

@@ -22,7 +22,6 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.ManagedArray;
import org.springframework.beans.factory.support.ManagedList;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.core.Conventions;
@@ -39,7 +38,7 @@ import com.gemstone.gemfire.cache.ResumptionAction;
import com.gemstone.gemfire.cache.Scope;
/**
* Various minor utilities used by the parser.
* Utilities used by the Spring Data GemFire XML Namespace parsers.
* <p/>
* @author Costin Leau
* @author David Turanski
@@ -271,22 +270,25 @@ abstract class ParsingUtils {
* <p/>
* @param parserContext the context used while parsing the XML document.
* @param element the XML element being parsed.
* @param attrBuilder the Region Attributes builder.
* @param regionAttributesBuilder the Region Attributes builder.
* @return a boolean indicating whether Region expiration attributes were specified.
*/
static boolean parseExpiration(ParserContext parserContext, Element element, BeanDefinitionBuilder attrBuilder) {
boolean result = parseExpiration(element, "region-ttl", "regionTimeToLive", attrBuilder);
static boolean parseExpiration(ParserContext parserContext, Element element,
BeanDefinitionBuilder regionAttributesBuilder) {
result |= parseExpiration(element, "region-tti", "regionIdleTimeout", attrBuilder);
result |= parseExpiration(element, "entry-ttl", "entryTimeToLive", attrBuilder);
result |= parseExpiration(element, "entry-tti", "entryIdleTimeout", attrBuilder);
result |= parseCustomExpiration(parserContext, element,"custom-entry-ttl","customEntryTimeToLive",attrBuilder);
result |= parseCustomExpiration(parserContext, element,"custom-entry-tti","customEntryIdleTimeout",attrBuilder);
boolean result = parseExpiration(element, "region-ttl", "regionTimeToLive", regionAttributesBuilder);
result |= parseExpiration(element, "region-tti", "regionIdleTimeout", regionAttributesBuilder);
result |= parseExpiration(element, "entry-ttl", "entryTimeToLive", regionAttributesBuilder);
result |= parseExpiration(element, "entry-tti", "entryIdleTimeout", regionAttributesBuilder);
result |= parseCustomExpiration(parserContext, element,"custom-entry-ttl","customEntryTimeToLive",
regionAttributesBuilder);
result |= parseCustomExpiration(parserContext, element,"custom-entry-tti","customEntryIdleTimeout",
regionAttributesBuilder);
// TODO why?
if (result) {
// turn on statistics
attrBuilder.addPropertyValue("statisticsEnabled", Boolean.TRUE);
regionAttributesBuilder.addPropertyValue("statisticsEnabled", Boolean.TRUE);
}
return result;
}
@@ -314,7 +316,8 @@ abstract class ParsingUtils {
String indexUpdateType = element.getAttribute("index-update-type");
if (StringUtils.hasText(indexUpdateType)) {
regionAttributesBuilder.addPropertyValue("indexMaintenanceSynchronous", "synchronous".equals(indexUpdateType));
regionAttributesBuilder.addPropertyValue("indexMaintenanceSynchronous",
"synchronous".equals(indexUpdateType));
}
String concurrencyChecksEnabled = element.getAttribute("concurrency-checks-enabled");
@@ -433,4 +436,9 @@ abstract class ParsingUtils {
return true;
}
static String resolveCacheReference(final String cacheRef) {
return (StringUtils.hasText(cacheRef) ? cacheRef : GemfireConstants.DEFAULT_GEMFIRE_CACHE_NAME);
}
}