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:
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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")) {
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user