Fixes bug SGF-225 involving GemFire SubRegion bean definition inconsistencies when data-policy is specified along with SGF-242 that involves the use of membership-attributes configuration on a GemFire Region.

This commit is contained in:
John Blum
2013-12-06 16:17:07 -08:00
parent bccf918b72
commit 101d977026
23 changed files with 850 additions and 494 deletions

View File

@@ -77,6 +77,8 @@ public class RegionFactoryBean<K, V> extends RegionLookupFactoryBean<K, V> imple
private Object[] asyncEventQueues;
private Object[] gatewaySenders;
private Region<?, ?> parent;
private RegionAttributes<K, V> attributes;
private Resource snapshot;
@@ -103,11 +105,11 @@ public class RegionFactoryBean<K, V> extends RegionLookupFactoryBean<K, V> imple
AttributesFactory.validateAttributes(attributes);
}
final RegionFactory<K, V> regionFactory = (attributes != null ? cache.createRegionFactory(attributes) :
cache.<K, V> createRegionFactory());
RegionFactory<K, V> regionFactory = (attributes != null ? cache.createRegionFactory(attributes)
: cache.<K, V>createRegionFactory());
if (hubId != null) {
enableGateway = enableGateway == null ? true : enableGateway;
enableGateway = (enableGateway == null || enableGateway);
Assert.isTrue(enableGateway, "hubId requires the enableGateway property to be true");
regionFactory.setGatewayHubId(hubId);
@@ -115,20 +117,15 @@ public class RegionFactoryBean<K, V> extends RegionLookupFactoryBean<K, V> imple
if (enableGateway != null) {
if (enableGateway) {
Assert.notNull(hubId, "enableGateway requires the hubId property to be true");
Assert.notNull(hubId, "The 'enableGateway' property requires the 'hubId' property to be set.");
}
regionFactory.setEnableGateway(enableGateway);
}
if (!ObjectUtils.isEmpty(cacheListeners)) {
for (CacheListener<K, V> listener : cacheListeners) {
regionFactory.addCacheListener(listener);
}
}
if (!ObjectUtils.isEmpty(gatewaySenders)) {
Assert.isTrue(hubId == null, "It is invalid to configure a region with both a hubId and gatewaySenders."
+ " Note that the enableGateway and hubId properties are deprecated since Gemfire 7.0");
for (Object gatewaySender : gatewaySenders) {
regionFactory.addGatewaySenderId(((GatewaySender) gatewaySender).getId());
}
@@ -140,6 +137,12 @@ public class RegionFactoryBean<K, V> extends RegionLookupFactoryBean<K, V> imple
}
}
if (!ObjectUtils.isEmpty(cacheListeners)) {
for (CacheListener<K, V> listener : cacheListeners) {
regionFactory.addCacheListener(listener);
}
}
if (cacheLoader != null) {
regionFactory.setCacheLoader(cacheLoader);
}
@@ -164,10 +167,20 @@ public class RegionFactoryBean<K, V> extends RegionLookupFactoryBean<K, V> imple
}
// get underlying AttributesFactory
postProcess(findAttrFactory(regionFactory));
postProcess(findAttributesFactory(regionFactory));
Region<K, V> region = regionFactory.create(regionName);
log.info("Created new cache region [" + regionName + "]");
Region<K, V> region = (this.parent != null ? regionFactory.createSubregion(parent, regionName)
: regionFactory.create(regionName));
if (log.isInfoEnabled()) {
if (parent != null) {
log.info(String.format("Created new Cache sub-Region [%1$s] under parent Region [%2$s].",
regionName, parent.getName()));
}
else {
log.info(String.format("Created new Cache Region [%1$s].", regionName));
}
}
if (snapshot != null) {
region.loadSnapshot(snapshot.getInputStream());
@@ -205,7 +218,7 @@ public class RegionFactoryBean<K, V> extends RegionLookupFactoryBean<K, V> imple
}
@SuppressWarnings("unchecked")
private AttributesFactory<K, V> findAttrFactory(RegionFactory<K, V> regionFactory) {
private AttributesFactory<K, V> findAttributesFactory(RegionFactory<K, V> regionFactory) {
Field attrsFactoryField = ReflectionUtils.findField(RegionFactory.class, "attrsFactory",
AttributesFactory.class);
ReflectionUtils.makeAccessible(attrsFactoryField);
@@ -218,12 +231,13 @@ public class RegionFactoryBean<K, V> extends RegionLookupFactoryBean<K, V> imple
* already initialized and configured by the factory bean before this method
* is invoked.
*
* @param attrFactory attribute factory
* @param attributesFactory attribute factory
* @deprecated as of GemFire 6.5, the use of {@link AttributesFactory} has
* been deprecated
*/
@Deprecated
protected void postProcess(AttributesFactory<K, V> attrFactory) {
@SuppressWarnings("unused")
protected void postProcess(AttributesFactory<K, V> attributesFactory) {
}
/**
@@ -233,6 +247,7 @@ public class RegionFactoryBean<K, V> extends RegionLookupFactoryBean<K, V> imple
*
* @param region
*/
@SuppressWarnings("unused")
protected void postProcess(Region<K, V> region) {
}
@@ -244,17 +259,38 @@ public class RegionFactoryBean<K, V> extends RegionLookupFactoryBean<K, V> imple
if (!getRegion().getRegionService().isClosed()) {
try {
getRegion().close();
} catch (Exception cce) {
// nothing to see folks, move on.
}
catch (Exception ignore) {
}
}
} if (destroy) {
}
if (destroy) {
getRegion().destroyRegion();
}
}
}
/**
*
* @param asyncEventQueues defined as Object for backward compatibility with
* Gemfire 6
*/
public void setAsyncEventQueues(Object[] asyncEventQueues) {
this.asyncEventQueues = asyncEventQueues;
}
/**
* Sets the region attributes used for the region used by this factory.
* Allows maximum control in specifying the region settings. Used only when
* a new region is created.
*
* @param attributes the attributes to set on a newly created region
*/
public void setAttributes(RegionAttributes<K, V> attributes) {
this.attributes = attributes;
}
/**
* Indicates whether the region referred by this factory bean, will be
* closed on shutdown (default true).
@@ -263,26 +299,6 @@ public class RegionFactoryBean<K, V> extends RegionLookupFactoryBean<K, V> imple
this.close = close;
}
/**
* Indicates whether the region referred by this factory bean, will be
* destroyed on shutdown (default false).
*/
public void setDestroy(boolean destroy) {
this.destroy = destroy;
}
/**
* Sets the snapshots used for loading a newly <i>created</i> region. That
* is, the snapshot will be used <i>only</i> when a new region is created -
* if the region already exists, no loading will be performed.
*
* @see #setName(String)
* @param snapshot the snapshot to set
*/
public void setSnapshot(Resource snapshot) {
this.snapshot = snapshot;
}
/**
* Sets the cache listeners used for the region used by this factory. Used
* only when a new region is created.Overrides the settings specified
@@ -317,18 +333,11 @@ public class RegionFactoryBean<K, V> extends RegionLookupFactoryBean<K, V> imple
}
/**
* Sets the region scope. Used only when a new region is created. Overrides
* the settings specified through {@link #setAttributes(RegionAttributes)}.
*
* @see Scope
* @param scope the region scope
* Indicates whether the region referred by this factory bean, will be
* destroyed on shutdown (default false).
*/
public void setScope(Scope scope) {
this.scope = scope;
}
public void setPersistent(boolean persistent) {
this.persistent = persistent;
public void setDestroy(boolean destroy) {
this.destroy = destroy;
}
/**
@@ -348,6 +357,10 @@ public class RegionFactoryBean<K, V> extends RegionLookupFactoryBean<K, V> imple
this.diskStoreName = diskStoreName;
}
public void setEnableGateway(boolean enableGateway) {
this.enableGateway = enableGateway;
}
/**
*
* @param gatewaySenders defined as Object for backward compatibility with
@@ -357,32 +370,39 @@ public class RegionFactoryBean<K, V> extends RegionLookupFactoryBean<K, V> imple
this.gatewaySenders = gatewaySenders;
}
/**
*
* @param asyncEventQueues defined as Object for backward compatibility with
* Gemfire 6
*/
public void setAsyncEventQueues(Object[] asyncEventQueues) {
this.asyncEventQueues = asyncEventQueues;
}
public void setEnableGateway(boolean enableGateway) {
this.enableGateway = enableGateway;
}
public void setHubId(String hubId) {
this.hubId = hubId;
}
public void setParent(Region<?, ?> parent) {
this.parent = parent;
}
public void setPersistent(boolean persistent) {
this.persistent = persistent;
}
/**
* Sets the region attributes used for the region used by this factory.
* Allows maximum control in specifying the region settings. Used only when
* a new region is created.
* Sets the region scope. Used only when a new region is created. Overrides
* the settings specified through {@link #setAttributes(RegionAttributes)}.
*
* @param attributes the attributes to set on a newly created region
* @see Scope
* @param scope the region scope
*/
public void setAttributes(RegionAttributes<K, V> attributes) {
this.attributes = attributes;
public void setScope(Scope scope) {
this.scope = scope;
}
/**
* Sets the snapshots used for loading a newly <i>created</i> region. That
* is, the snapshot will be used <i>only</i> when a new region is created -
* if the region already exists, no loading will be performed.
*
* @see #setName(String)
* @param snapshot the snapshot to set
*/
public void setSnapshot(Resource snapshot) {
this.snapshot = snapshot;
}
/**

View File

@@ -29,11 +29,11 @@ import com.gemstone.gemfire.cache.GemFireCache;
import com.gemstone.gemfire.cache.Region;
/**
* Simple FactoryBean for retrieving generic GemFire {@link Region}s. If the region doesn't exist, an exception is thrown.
*
* For declaring and configuring new regions, see {@link RegionFactoryBean}.
*
* Simple FactoryBean for retrieving generic GemFire {@link Region}s. If the Region does not exist,
* an exception is thrown. For declaring and configuring new regions, see {@link RegionFactoryBean}.
* <p/>
* @author Costin Leau
* @author John Blum
*/
public class RegionLookupFactoryBean<K, V> implements FactoryBean<Region<K, V>>, InitializingBean, BeanNameAware {
@@ -45,21 +45,24 @@ public class RegionLookupFactoryBean<K, V> implements FactoryBean<Region<K, V>>,
private String beanName;
private String name;
private String regionName;
public void afterPropertiesSet() throws Exception {
Assert.notNull(cache, "Cache property must be set");
Assert.notNull(cache, "The 'cache' property must be set.");
name = (StringUtils.hasText(name) ? name : beanName);
Assert.hasText(name, "The 'name' or 'beanName' property must be set.");
String regionName = (StringUtils.hasText(this.regionName) ? this.regionName
: (StringUtils.hasText(name) ? name : beanName));
Assert.hasText(regionName, "The 'regionName', 'name' or 'beanName' property must be set.");
synchronized (cache) {
region = cache.getRegion(name);
region = cache.getRegion(regionName);
if (region != null) {
log.info(String.format("Retrieved region [%1$s] from cache [%2$s].", name, cache.getName()));
log.info(String.format("Retrieved Region [%1$s] from Cache [%2$s].", regionName, cache.getName()));
}
else {
region = lookupFallback(cache, name);
region = lookupFallback(cache, regionName);
}
}
}
@@ -73,7 +76,8 @@ public class RegionLookupFactoryBean<K, V> implements FactoryBean<Region<K, V>>,
* @throws Exception
*/
protected Region<K, V> lookupFallback(GemFireCache cache, String regionName) throws Exception {
throw new BeanInitializationException("Cannot find region [" + regionName + "] in cache " + cache);
throw new BeanInitializationException(String.format("Cannot find Region [%1$s] in Cache [%2$s].",
regionName, cache));
}
public Region<K, V> getObject() throws Exception {
@@ -88,34 +92,52 @@ public class RegionLookupFactoryBean<K, V> implements FactoryBean<Region<K, V>>,
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.
* <p/>
* @param name the name of this bean (Region) in the application context (bean factory).
* @see org.springframework.beans.factory.BeanNameAware#setBeanName(String)
*/
public void setBeanName(String name) {
this.beanName = name;
}
/**
* Sets the cache used for creating the region.
*
* Sets a reference to the Cache used to create the Region.
* <p/>
* @param cache a reference to the Cache.
* @see org.springframework.data.gemfire.CacheFactoryBean
* @param cache the cache to set
* @see com.gemstone.gemfire.cache.GemFireCache
*/
public void setCache(GemFireCache cache) {
this.cache = cache;
}
/**
* Sets the name of the cache region. If no cache is found under
* the given name, a new one will be created.
* If no name is given, the beanName will be used.
*
* @see com.gemstone.gemfire.cache.Region#getFullPath()
* @see #setBeanName(String)
*
* 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.
* <p/>
* @param name the region name
* @see #setBeanName(String)
* @see com.gemstone.gemfire.cache.Region#getFullPath()
*/
public void setName(String name) {
this.name = name;
}
/**
* 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.
* <p/>
* @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;
}
protected Region<K, V> getRegion() {
return region;
}

View File

@@ -33,19 +33,19 @@ public class ReplicatedRegionFactoryBean<K, V> extends RegionFactoryBean<K, V> {
Assert.notNull(resolvedDataPolicy, String.format("Data Policy '%1$s' is invalid.", dataPolicy));
// Validate that the data-policy and persistent attributes are compatible when specified!
assertDataPolicyAndPersistentAttributesAreCompatible(resolvedDataPolicy);
if (DataPolicy.EMPTY.equals(resolvedDataPolicy)) {
resolvedDataPolicy = DataPolicy.EMPTY;
}
else {
// Validate that the user-defined Data Policy matches the appropriate Spring GemFire XML namespace
// configuration meta-data element for Region (i.e. <gfe:replicated-region .../>)!
Assert.isTrue(resolvedDataPolicy.withReplication(), String.format("" +
Assert.isTrue(resolvedDataPolicy.withReplication(), String.format(
"Data Policy '%1$s' is not supported in Replicated Regions.", resolvedDataPolicy));
}
// Validate that the data-policy and persistent attributes are compatible when specified!
assertDataPolicyAndPersistentAttributesAreCompatible(resolvedDataPolicy);
regionFactory.setDataPolicy(resolvedDataPolicy);
}
else {

View File

@@ -29,16 +29,18 @@ import com.gemstone.gemfire.cache.Region;
import com.gemstone.gemfire.cache.asyncqueue.AsyncEventQueue;
import com.gemstone.gemfire.cache.wan.GatewaySender;
@SuppressWarnings("deprecation")
/**
* FactoryBean for creating a Gemfire Region as a sub-Region.
* FactoryBean for creating a Gemfire sub-Regions.
* <p/>
* @author David Turanski
* @author John Blum
* @param <K> - Region Key Type
* @param <V> - Region Value Type
* @param <K> Region Key Type
* @param <V> Region Value Type
* @deprecated as Spring Data GemFire 1.4.0. Use Region type specific FactoryBeans
* (e.g. ReplicatedRegionFactoryBean) instead.
*/
// TODO why does this class extend the com.gemstone.gemfire.cache.AttributesFactory class? AttributesFactory is deprecated!
@Deprecated
@SuppressWarnings("deprecation")
public class SubRegionFactoryBean<K, V> extends AttributesFactory<K, V> implements FactoryBean<Region<K, V>>,
InitializingBean {

View File

@@ -29,7 +29,6 @@ import org.springframework.beans.factory.support.ManagedArray;
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.data.gemfire.GemfireUtils;
import org.springframework.data.gemfire.SubRegionFactoryBean;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.util.xml.DomUtils;
@@ -46,7 +45,7 @@ abstract class AbstractRegionParser extends AbstractSingleBeanDefinitionParser {
@Override
protected Class<?> getBeanClass(Element element) {
return (isSubRegion(element) ? SubRegionFactoryBean.class : getRegionFactoryClass());
return getRegionFactoryClass();
}
protected abstract Class<?> getRegionFactoryClass();
@@ -67,45 +66,45 @@ abstract class AbstractRegionParser extends AbstractSingleBeanDefinitionParser {
boolean subRegion);
protected void doParseCommonRegionConfiguration(Element element, ParserContext parserContext,
BeanDefinitionBuilder builder, BeanDefinitionBuilder attrBuilder, boolean subRegion) {
BeanDefinitionBuilder builder, BeanDefinitionBuilder regionAttributesBuilder, boolean subRegion) {
String cacheRef = element.getAttribute("cache-ref");
String resolvedCacheRef = (StringUtils.hasText(cacheRef) ? cacheRef
: GemfireConstants.DEFAULT_GEMFIRE_CACHE_NAME);
if (!subRegion) {
String cacheRef = element.getAttribute("cache-ref");
// add cache reference (fallback to default if nothing is specified)
builder.addPropertyReference("cache", (StringUtils.hasText(cacheRef) ? cacheRef : GemfireConstants.DEFAULT_GEMFIRE_CACHE_NAME));
builder.addPropertyReference("cache", resolvedCacheRef);
ParsingUtils.setPropertyValue(element, builder, "close");
ParsingUtils.setPropertyValue(element, builder, "destroy");
}
// add attributes
ParsingUtils.setPropertyValue(element, builder, "name");
ParsingUtils.parseOptionalRegionAttributes(parserContext, element, attrBuilder);
ParsingUtils.parseStatistics(element, attrBuilder);
ParsingUtils.setPropertyValue(element, attrBuilder, "publisher");
if (!isSubRegion(element)) {
ParsingUtils.setPropertyValue(element, builder, "persistent");
}
// set the data policy
ParsingUtils.setPropertyValue(element, builder, "name");
ParsingUtils.setPropertyValue(element, builder, "data-policy");
ParsingUtils.setPropertyValue(element, builder, "persistent");
ParsingUtils.setPropertyValue(element, regionAttributesBuilder, "publisher");
if (StringUtils.hasText(element.getAttribute("disk-store-ref"))) {
ParsingUtils.setPropertyValue(element, builder, "disk-store-ref", "diskStoreName");
builder.addDependsOn(element.getAttribute("disk-store-ref"));
}
ParsingUtils.parseExpiration(parserContext, element, attrBuilder);
ParsingUtils.parseSubscription(parserContext, element, attrBuilder);
ParsingUtils.parseEviction(parserContext, element, attrBuilder);
ParsingUtils.parseMembershipAttributes(parserContext, element, attrBuilder);
ParsingUtils.parseOptionalRegionAttributes(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);
String enableGateway = element.getAttribute("enable-gateway");
String hubId = element.getAttribute("hub-id");
// Factory will enable gateway if it is not set and hub-id is set.
if (StringUtils.hasText(enableGateway)) {
if (GemfireUtils.isGemfireVersion7OrAbove()) {
log.warn("'enable-gateway' is deprecated since Gemfire 7.0");
}
}
ParsingUtils.setPropertyValue(element, builder, "enable-gateway");
if (StringUtils.hasText(hubId)) {
@@ -117,16 +116,16 @@ abstract class AbstractRegionParser extends AbstractSingleBeanDefinitionParser {
element);
}
}
ParsingUtils.setPropertyValue(element, builder, "hub-id");
// Parse child elements
parseCollectionOfCustomSubElements(parserContext, element, builder,
"com.gemstone.gemfire.cache.wan.GatewaySender", "gateway-sender","gatewaySenders");
parseCollectionOfCustomSubElements(parserContext, element, builder,
"com.gemstone.gemfire.cache.asyncqueue.AsyncEventQueue", "async-event-queue", "asyncEventQueues");
parseCollectionOfCustomSubElements(element, parserContext, builder,
"com.gemstone.gemfire.cache.asyncqueue.AsyncEventQueue", "async-event-queue", "asyncEventQueues");
parseCollectionOfCustomSubElements(element, parserContext, builder,
"com.gemstone.gemfire.cache.wan.GatewaySender", "gateway-sender","gatewaySenders");
List<Element> subElements = DomUtils.getChildElements(element);
for (Element subElement : subElements) {
if (subElement.getLocalName().equals("cache-listener")) {
builder.addPropertyValue("cacheListeners",
@@ -143,43 +142,47 @@ abstract class AbstractRegionParser extends AbstractSingleBeanDefinitionParser {
}
if (!subRegion) {
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());
}
}
parseSubRegions(element, parserContext, resolvedCacheRef);
}
}
private void parseCollectionOfCustomSubElements(ParserContext parserContext, Element element,
BeanDefinitionBuilder builder, String className, String subElementName, String propertyName) {
List<Element> subElements = DomUtils.getChildElementsByTagName(element, new String[] { subElementName,
subElementName + "-ref" });
if (!CollectionUtils.isEmpty(subElements)) {
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,
new String[] { subElementName, subElementName + "-ref" });
if (!CollectionUtils.isEmpty(subElements)) {
ManagedArray array = new ManagedArray(className, subElements.size());
for (Element subElement : subElements) {
array.add(ParsingUtils.parseRefOrNestedCustomElement(parserContext, subElement, builder));
}
builder.addPropertyValue(propertyName, array);
}
}
private BeanDefinition parseSubRegion(Element element, ParserContext parserContext, String regionPath) {
String parentBeanName = getParentPathForSubRegion(regionPath);
String regionName = getRegionNameFromElement(element); // do before 'renaming' the element, below
element.setAttribute("id", regionPath);
element.setAttribute("name", regionPath);
BeanDefinition beanDefinition = parserContext.getDelegate().parseCustomElement(element);
beanDefinition.getPropertyValues().add("parent", new RuntimeBeanReference(parentBeanName));
beanDefinition.getPropertyValues().add("regionName", regionName);
return beanDefinition;
private void findSubRegionElements(Element parent, String parentPath, Map<String, Element> allSubRegionElements) {
for (Element element : DomUtils.getChildElements(parent)) {
if (element.getLocalName().endsWith("region")) {
String subRegionName = getRegionNameFromElement(element);
String subRegionPath = buildSubRegionPath(parentPath, subRegionName);
allSubRegionElements.put(subRegionPath, element);
findSubRegionElements(element, subRegionPath, allSubRegionElements);
}
}
}
private String getRegionNameFromElement(Element element) {
@@ -187,15 +190,33 @@ abstract class AbstractRegionParser extends AbstractSingleBeanDefinitionParser {
return (StringUtils.hasText(name) ? name : element.getAttribute(ID_ATTRIBUTE));
}
private String buildPathForSubRegion(String parentName, String regionName) {
String regionPath = StringUtils.arrayToDelimitedString(new String[] { parentName, regionName }, "/");
if (!regionPath.startsWith("/")) {
regionPath = "/" + regionPath;
}
return regionPath;
}
private String buildSubRegionPath(String parentName, String regionName) {
String regionPath = StringUtils.arrayToDelimitedString(new String[] { parentName, regionName }, "/");
if (!regionPath.startsWith("/")) {
regionPath = "/" + regionPath;
}
return regionPath;
}
private String getParentPathForSubRegion(String regionPath) {
private BeanDefinition parseSubRegion(Element element, ParserContext parserContext, String subRegionPath,
String cacheRef) {
String parentBeanName = getParentRegionPathFrom(subRegionPath);
String regionName = getRegionNameFromElement(element); // do before 'renaming' the element below
element.setAttribute("id", subRegionPath);
element.setAttribute("name", subRegionPath);
BeanDefinition beanDefinition = parserContext.getDelegate().parseCustomElement(element);
beanDefinition.getPropertyValues().add("cache", new RuntimeBeanReference(cacheRef));
beanDefinition.getPropertyValues().add("parent", new RuntimeBeanReference(parentBeanName));
beanDefinition.getPropertyValues().add("regionName", regionName);
return beanDefinition;
}
private String getParentRegionPathFrom(String regionPath) {
int index = regionPath.lastIndexOf("/");
String parentPath = regionPath.substring(0, index);
if (parentPath.lastIndexOf("/") == 0) {
@@ -204,14 +225,4 @@ abstract class AbstractRegionParser extends AbstractSingleBeanDefinitionParser {
return parentPath;
}
private void findSubregionElements(Element parent, String parentPath, Map<String, Element> allSubregionElements) {
for (Element element : DomUtils.getChildElements(parent)) {
if (element.getLocalName().endsWith("region")) {
String regionPath = buildPathForSubRegion(parentPath, getRegionNameFromElement(element));
allSubregionElements.put(regionPath, element);
findSubregionElements(element, regionPath, allSubregionElements);
}
}
}
}

View File

@@ -78,6 +78,7 @@ class ClientRegionParser extends AbstractRegionParser {
builder.addPropertyValue("attributes", regionAttributesBuilder.getBeanDefinition());
List<Element> subElements = DomUtils.getChildElements(element);
ManagedList<Object> interests = new ManagedList<Object>();
for (Element subElement : subElements) {
@@ -110,7 +111,7 @@ class ClientRegionParser extends AbstractRegionParser {
@Override
protected void doParseRegion(Element element, ParserContext parserContext, BeanDefinitionBuilder builder,
boolean subRegion) {
boolean subRegion) {
throw new UnsupportedOperationException(String.format(
"doParseRegion(:Element, :ParserContext, :BeanDefinitionBuilder, :boolean) is not supported on %1$s",
getClass().getName()));

View File

@@ -31,12 +31,12 @@ import org.w3c.dom.Element;
* @author David Turanski
*/
class GemfireNamespaceHandler extends NamespaceHandlerSupport {
static final List<String> GEMFIRE7_ELEMENTS = Arrays.asList("async-event-queue", "gateway-sender",
"gateway-receiver");
protected static final List<String> GEMFIRE7_ELEMENTS = Arrays.asList("async-event-queue", "gateway-sender",
"gateway-receiver");
@Override
public BeanDefinition parse(Element element, ParserContext parserContext) {
boolean v7ElementsPresent = GEMFIRE7_ELEMENTS.contains(element.getLocalName());
if (v7ElementsPresent) {
@@ -49,24 +49,23 @@ class GemfireNamespaceHandler extends NamespaceHandlerSupport {
@Override
public void init() {
registerBeanDefinitionParser("cache", new CacheParser());
registerBeanDefinitionParser("client-cache", new ClientCacheParser());
registerBeanDefinitionParser("lookup-region", new LookupRegionParser());
registerBeanDefinitionParser("replicated-region", new ReplicatedRegionParser());
registerBeanDefinitionParser("partitioned-region", new PartitionedRegionParser());
registerBeanDefinitionParser("local-region", new LocalRegionParser());
registerBeanDefinitionParser("client-region", new ClientRegionParser());
registerBeanDefinitionParser("pool", new PoolParser());
registerBeanDefinitionParser("index", new IndexParser());
registerBeanDefinitionParser("disk-store", new DiskStoreParser());
registerBeanDefinitionParser("cache-server", new CacheServerParser());
registerBeanDefinitionParser("transaction-manager", new TransactionManagerParser());
registerBeanDefinitionParser("cq-listener-container", new GemfireListenerContainerParser());
registerBeanDefinitionParser("client-cache", new ClientCacheParser());
registerBeanDefinitionParser("client-region", new ClientRegionParser());
registerBeanDefinitionParser("lookup-region", new LookupRegionParser());
registerBeanDefinitionParser("local-region", new LocalRegionParser());
registerBeanDefinitionParser("partitioned-region", new PartitionedRegionParser());
registerBeanDefinitionParser("replicated-region", new ReplicatedRegionParser());
registerBeanDefinitionParser("async-event-queue", new AsyncEventQueueParser());
registerBeanDefinitionParser("gateway-sender", new GatewaySenderParser());
registerBeanDefinitionParser("gateway-receiver", new GatewayReceiverParser());
registerBeanDefinitionParser("function-service", new FunctionServiceParser());
// V6 WAN parsers
registerBeanDefinitionParser("disk-store", new DiskStoreParser());
registerBeanDefinitionParser("gateway-hub", new GatewayHubParser());
registerBeanDefinitionParser("gateway-receiver", new GatewayReceiverParser());
registerBeanDefinitionParser("gateway-sender", new GatewaySenderParser());
registerBeanDefinitionParser("index", new IndexParser());
registerBeanDefinitionParser("pool", new PoolParser());
registerBeanDefinitionParser("annotation-driven", new AnnotationDrivenBeanDefinitionParser());
registerBeanDefinitionParser("cq-listener-container", new GemfireListenerContainerParser());
registerBeanDefinitionParser("function-service", new FunctionServiceParser());
registerBeanDefinitionParser("transaction-manager", new TransactionManagerParser());
}
}

View File

@@ -23,27 +23,28 @@ import org.springframework.data.gemfire.RegionAttributesFactoryBean;
import org.w3c.dom.Element;
/**
* Parser for &lt;local-region;gt; definitions.
*
* Parser for &lt;local-region;gt; bean definitions.
* <p/>
* @author David Turanski
* @author John Blum
*/
class LocalRegionParser extends AbstractRegionParser {
@Override
protected void doParseRegion(Element element, ParserContext parserContext, BeanDefinitionBuilder builder,
boolean subRegion) {
BeanDefinitionBuilder attrBuilder = subRegion ? builder : BeanDefinitionBuilder
.genericBeanDefinition(RegionAttributesFactoryBean.class);
super.doParseCommonRegionConfiguration(element, parserContext, builder, attrBuilder, subRegion);
if (!subRegion) {
builder.addPropertyValue("attributes", attrBuilder.getBeanDefinition());
}
}
@Override
protected Class<?> getRegionFactoryClass() {
return LocalRegionFactoryBean.class;
}
}
@Override
protected void doParseRegion(Element element, ParserContext parserContext, BeanDefinitionBuilder builder,
boolean subRegion) {
BeanDefinitionBuilder regionAttributesBuilder = BeanDefinitionBuilder.genericBeanDefinition(
RegionAttributesFactoryBean.class);
super.doParseCommonRegionConfiguration(element, parserContext, builder, regionAttributesBuilder, subRegion);
builder.addPropertyValue("attributes", regionAttributesBuilder.getBeanDefinition());
}
}

View File

@@ -24,9 +24,10 @@ import org.w3c.dom.Element;
/**
* Parser for &lt;lookup-region;gt; definitions.
*
* <p/>
* @author Costin Leau
* @author David Turanski
* @author John Blum
*/
class LookupRegionParser extends AbstractRegionParser {
@@ -43,9 +44,9 @@ class LookupRegionParser extends AbstractRegionParser {
ParsingUtils.setPropertyValue(element, builder, "name", "name");
if (!subRegion) {
String attr = element.getAttribute("cache-ref");
// add cache reference (fallback to default if nothing is specified)
builder.addPropertyReference("cache", (StringUtils.hasText(attr) ? attr : GemfireConstants.DEFAULT_GEMFIRE_CACHE_NAME));
String cacheRef = element.getAttribute("cache-ref");
builder.addPropertyReference("cache", (StringUtils.hasText(cacheRef) ? cacheRef
: GemfireConstants.DEFAULT_GEMFIRE_CACHE_NAME));
}
else {
builder.addPropertyValue("lookupOnly", true);

View File

@@ -183,10 +183,12 @@ abstract class ParsingUtils {
* <p/>
* @param parserContext the context used for parsing the XML document.
* @param element the XML elements being parsed.
* @param attributesBuilder the Region Attributes builder.
* @param regionAttributesBuilder the Region Attributes builder.
* @return true if parsing actually occurred, false otherwise.
*/
static boolean parseEviction(ParserContext parserContext, Element element, BeanDefinitionBuilder attributesBuilder) {
static boolean parseEviction(ParserContext parserContext, Element element,
BeanDefinitionBuilder regionAttributesBuilder) {
Element evictionElement = DomUtils.getChildElementByTagName(element, "eviction");
if (evictionElement != null) {
@@ -210,7 +212,7 @@ abstract class ParsingUtils {
evictionAttributesBuilder.addPropertyValue("ObjectSizer", sizer);
}
attributesBuilder.addPropertyValue("evictionAttributes", evictionAttributesBuilder.getBeanDefinition());
regionAttributesBuilder.addPropertyValue("evictionAttributes", evictionAttributesBuilder.getBeanDefinition());
return true;
}
@@ -223,27 +225,32 @@ 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 true if parsing actually occurred, false otherwise.
*/
@SuppressWarnings("unused")
static boolean parseSubscription(ParserContext parserContext, Element element, BeanDefinitionBuilder attrBuilder) {
static boolean parseSubscription(ParserContext parserContext, Element element,
BeanDefinitionBuilder regionAttributesBuilder) {
Element subscriptionElement = DomUtils.getChildElementByTagName(element, "subscription");
if (subscriptionElement == null)
return false;
if (subscriptionElement != null) {
BeanDefinitionBuilder subscriptionAttributesBuilder = BeanDefinitionBuilder.genericBeanDefinition(
SubscriptionAttributesFactoryBean.class);
BeanDefinitionBuilder subscriptionDefBuilder = BeanDefinitionBuilder
.genericBeanDefinition(SubscriptionAttributesFactoryBean.class);
// do manual conversion since the enum is not public
String type = subscriptionElement.getAttribute("type");
// do manual conversion since the enum is not public
String attr = subscriptionElement.getAttribute("type");
if (StringUtils.hasText(attr)) {
subscriptionDefBuilder.addPropertyValue("type", SubscriptionType.valueOf(attr.toUpperCase()));
if (StringUtils.hasText(type)) {
subscriptionAttributesBuilder.addPropertyValue("type", SubscriptionType.valueOf(type.toUpperCase()));
}
regionAttributesBuilder.addPropertyValue("subscriptionAttributes", subscriptionAttributesBuilder.getBeanDefinition());
return true;
}
attrBuilder.addPropertyValue("subscriptionAttributes", subscriptionDefBuilder.getBeanDefinition());
return true;
return false;
}
@@ -284,85 +291,90 @@ abstract class ParsingUtils {
return result;
}
@SuppressWarnings("unused")
static void parseOptionalRegionAttributes(ParserContext parserContext, Element element,
BeanDefinitionBuilder attrBuilder) {
BeanDefinitionBuilder regionAttributesBuilder) {
if (!("partitioned-region".equals(element.getLocalName()))) {
setPropertyValue(element, attrBuilder, "persistent", "persistBackup");
setPropertyValue(element, regionAttributesBuilder, "persistent", "persistBackup");
}
setPropertyValue(element, attrBuilder, "ignore-jta", "ignoreJTA");
setPropertyValue(element, attrBuilder, "key-constraint");
setPropertyValue(element, attrBuilder, "value-constraint");
setPropertyValue(element, attrBuilder, "is-lock-grantor", "lockGrantor");
setPropertyValue(element, attrBuilder, "enable-subscription-conflation");
setPropertyValue(element, attrBuilder, "enable-async-conflation");
setPropertyValue(element, attrBuilder, "initial-capacity");
setPropertyValue(element, attrBuilder, "load-factor");
setPropertyValue(element, attrBuilder, "cloning-enabled");
setPropertyValue(element, attrBuilder, "concurrency-level");
setPropertyValue(element, attrBuilder, "multicast-enabled");
setPropertyValue(element, regionAttributesBuilder, "cloning-enabled");
setPropertyValue(element, regionAttributesBuilder, "concurrency-level");
setPropertyValue(element, regionAttributesBuilder, "enable-async-conflation");
setPropertyValue(element, regionAttributesBuilder, "enable-subscription-conflation");
setPropertyValue(element, regionAttributesBuilder, "ignore-jta", "ignoreJTA");
setPropertyValue(element, regionAttributesBuilder, "initial-capacity");
setPropertyValue(element, regionAttributesBuilder, "is-lock-grantor", "lockGrantor");
setPropertyValue(element, regionAttributesBuilder, "key-constraint");
setPropertyValue(element, regionAttributesBuilder, "load-factor");
setPropertyValue(element, regionAttributesBuilder, "multicast-enabled");
setPropertyValue(element, regionAttributesBuilder, "value-constraint");
String indexUpdateType = element.getAttribute("index-update-type");
if (StringUtils.hasText(indexUpdateType)) {
attrBuilder.addPropertyValue("indexMaintenanceSynchronous", "synchronous".equals(indexUpdateType));
regionAttributesBuilder.addPropertyValue("indexMaintenanceSynchronous", "synchronous".equals(indexUpdateType));
}
String concurrencyChecksEnabled = element.getAttribute("concurrency-checks-enabled");
if (StringUtils.hasText(concurrencyChecksEnabled)) {
if (!GemfireUtils.isGemfireVersion7OrAbove()) {
log.warn("'concurrency-checks-enabled' is only available in Gemfire 7.0 or above");
} else {
ParsingUtils.setPropertyValue(element, attrBuilder, "concurrency-checks-enabled");
log.warn("Setting 'concurrency-checks-enabled' is only available in Gemfire 7.0 or above");
}
else {
ParsingUtils.setPropertyValue(element, regionAttributesBuilder, "concurrency-checks-enabled");
}
}
}
@SuppressWarnings("unused")
static void parseMembershipAttributes(ParserContext parserContext, Element element,
BeanDefinitionBuilder attrBuilder) {
BeanDefinitionBuilder regionAttributesBuilder) {
Element membershipAttributes = DomUtils.getChildElementByTagName(element, "membership-attributes");
if (membershipAttributes != null) {
String requiredRoles[] = StringUtils.commaDelimitedListToStringArray(membershipAttributes
.getAttribute("required-roles"));
String lossActionAttr = membershipAttributes.getAttribute("loss-action");
LossAction lossAction = StringUtils.hasText(lossActionAttr) ? LossAction.fromName(lossActionAttr
.toUpperCase().replace("-", "_")) : null;
String resumptionActionAttr = membershipAttributes.getAttribute("resumption-action");
ResumptionAction resumptionAction = StringUtils.hasText(resumptionActionAttr) ? ResumptionAction
.fromName(resumptionActionAttr.toUpperCase().replace("-", "_")) : null;
String[] requiredRoles = StringUtils.commaDelimitedListToStringArray(
membershipAttributes.getAttribute("required-roles"));
ManagedArray requiredRolesArray = new ManagedArray("java.lang.String", requiredRoles.length);
for (int i = 0; i < requiredRoles.length; i++) {
requiredRolesArray.add(requiredRoles[i]);
}
BeanDefinitionBuilder membershipAttributesBuilder = BeanDefinitionBuilder
.genericBeanDefinition(MembershipAttributes.class);
membershipAttributesBuilder.addConstructorArgValue(requiredRolesArray);
membershipAttributesBuilder.addConstructorArgValue(lossAction);
membershipAttributesBuilder.addConstructorArgValue(resumptionAction);
String lossActionValue = membershipAttributes.getAttribute("loss-action");
attrBuilder.addPropertyValue("membershipAttributes", membershipAttributesBuilder.getRawBeanDefinition());
LossAction lossAction = (StringUtils.hasText(lossActionValue)
? LossAction.fromName(lossActionValue.toUpperCase().replace("-", "_"))
: LossAction.NO_ACCESS);
String resumptionActionValue = membershipAttributes.getAttribute("resumption-action");
ResumptionAction resumptionAction = (StringUtils.hasText(resumptionActionValue)
? ResumptionAction.fromName(resumptionActionValue.toUpperCase().replace("-", "_"))
: ResumptionAction.REINITIALIZE);
regionAttributesBuilder.addPropertyValue("membershipAttributes",
new MembershipAttributes(requiredRoles, lossAction, resumptionAction));
}
}
static void throwExceptionIfNotGemfireV7(String elementName, String attributeName, ParserContext parserContext) {
if (!GemfireUtils.isGemfireVersion7OrAbove()) {
String messagePrefix = (attributeName == null) ? "element '" + elementName + "'" : "attribute '"
+ attributeName + " of element '" + elementName + "'";
String messagePrefix = (attributeName != null)
? String.format("Attribute '%1$s' of element '%2$s'", attributeName, elementName)
: String.format("Element '%1$s'", elementName);
parserContext.getReaderContext().error(
messagePrefix + " requires Gemfire version 7 or later. The current version is " + GemfireUtils.GEMFIRE_VERSION,
null);
String.format("%1$s requires GemFire version 7 or later. The current version is %2$s.",
messagePrefix, GemfireUtils.GEMFIRE_VERSION), null);
}
}
static void parseScope(Element element, BeanDefinitionBuilder builder) {
String scope = element.getAttribute("scope");
if (StringUtils.hasText(scope)) {
builder.addPropertyValue("scope", Scope.fromString(scope.toUpperCase().replace("-", "_")));
}
else {
builder.addPropertyValue("scope", Scope.DISTRIBUTED_ACK);
}
String scopeAttributeValue = element.getAttribute("scope");
Scope scope = (StringUtils.hasText(scopeAttributeValue)
? Scope.fromString(scopeAttributeValue.toUpperCase().replace("-", "_"))
: Scope.DISTRIBUTED_ACK);
builder.addPropertyValue("scope", scope);
}
private static boolean parseExpiration(Element rootElement, String elementName, String propertyName,

View File

@@ -31,11 +31,10 @@ import org.springframework.util.xml.DomUtils;
import org.w3c.dom.Element;
/**
* Parser for &lt;partitioned-region;gt; definitions.
*
* To avoid eager evaluations, the region attributes are declared as a nested
* definition.
*
* Parser for &lt;partitioned-region;gt; bean definitions.
* <p/>
* To avoid eager evaluations, the region attributes are declared as a nested definition.
* <p/>
* @author Costin Leau
* @author David Turanski
* @author John Blum
@@ -53,58 +52,57 @@ class PartitionedRegionParser extends AbstractRegionParser {
boolean subRegion) {
super.doParse(element, builder);
BeanDefinitionBuilder regionAttributesBuilder = (subRegion ? builder
: BeanDefinitionBuilder.genericBeanDefinition(RegionAttributesFactoryBean.class));
BeanDefinitionBuilder regionAttributesBuilder = BeanDefinitionBuilder.genericBeanDefinition(
RegionAttributesFactoryBean.class);
super.doParseCommonRegionConfiguration(element, parserContext, builder, regionAttributesBuilder, subRegion);
builder.addPropertyValue("attributes", regionAttributesBuilder.getBeanDefinition());
BeanDefinitionBuilder partitionAttributesBuilder = BeanDefinitionBuilder.genericBeanDefinition(
PartitionAttributesFactoryBean.class);
parseColocatedWith(element, builder, partitionAttributesBuilder, "colocated-with");
ParsingUtils.setPropertyValue(element, partitionAttributesBuilder, "local-max-memory");
ParsingUtils.setPropertyValue(element, partitionAttributesBuilder, "copies","redundantCopies");
ParsingUtils.setPropertyValue(element, partitionAttributesBuilder, "local-max-memory");
ParsingUtils.setPropertyValue(element, partitionAttributesBuilder, "recovery-delay");
ParsingUtils.setPropertyValue(element, partitionAttributesBuilder, "startup-recovery-delay");
ParsingUtils.setPropertyValue(element, partitionAttributesBuilder, "total-max-memory");
ParsingUtils.setPropertyValue(element, partitionAttributesBuilder, "total-buckets","totalNumBuckets");
ParsingUtils.setPropertyValue(element, partitionAttributesBuilder, "total-max-memory");
Element subElement = DomUtils.getChildElementByTagName(element, "partition-resolver");
// parse nested partition resolver element
if (subElement != null) {
Element partitionResolverSubElement = DomUtils.getChildElementByTagName(element, "partition-resolver");
if (partitionResolverSubElement != null) {
partitionAttributesBuilder.addPropertyValue("partitionResolver",
parsePartitionResolver(parserContext, subElement, builder));
parsePartitionResolver(partitionResolverSubElement, parserContext, builder));
}
subElement = DomUtils.getChildElementByTagName(element, "partition-listener");
// parse nested partition listener element
if (subElement != null) {
Element partitionListenerSubElement = DomUtils.getChildElementByTagName(element, "partition-listener");
if (partitionListenerSubElement != null) {
partitionAttributesBuilder.addPropertyValue("partitionListeners",
parsePartitionListeners(parserContext, subElement, builder));
parsePartitionListeners(partitionListenerSubElement, parserContext, builder));
}
List<Element> fixedPartitions = DomUtils.getChildElementsByTagName(element, "fixed-partition");
List<Element> fixedPartitionSubElements = DomUtils.getChildElementsByTagName(element, "fixed-partition");
if (!CollectionUtils.isEmpty(fixedPartitions)){
if (!CollectionUtils.isEmpty(fixedPartitionSubElements)){
@SuppressWarnings("rawtypes")
ManagedList fixedPartitionAttributes = new ManagedList();
for (Element fp: fixedPartitions) {
BeanDefinitionBuilder fpaBuilder = BeanDefinitionBuilder.genericBeanDefinition(
for (Element fixedPartition : fixedPartitionSubElements) {
BeanDefinitionBuilder fixedPartitionAttributesBuilder = BeanDefinitionBuilder.genericBeanDefinition(
FixedPartitionAttributesFactoryBean.class);
ParsingUtils.setPropertyValue(fp, fpaBuilder, "partition-name");
ParsingUtils.setPropertyValue(fp, fpaBuilder, "num-buckets");
ParsingUtils.setPropertyValue(fp, fpaBuilder, "primary");
fixedPartitionAttributes.add(fpaBuilder.getBeanDefinition());
ParsingUtils.setPropertyValue(fixedPartition, fixedPartitionAttributesBuilder, "partition-name");
ParsingUtils.setPropertyValue(fixedPartition, fixedPartitionAttributesBuilder, "num-buckets");
ParsingUtils.setPropertyValue(fixedPartition, fixedPartitionAttributesBuilder, "primary");
fixedPartitionAttributes.add(fixedPartitionAttributesBuilder.getBeanDefinition());
}
partitionAttributesBuilder.addPropertyValue("fixedPartitionAttributes", fixedPartitionAttributes);
}
// add partition attributes to region attributes
regionAttributesBuilder.addPropertyValue("partitionAttributes", partitionAttributesBuilder.getBeanDefinition());
// add partition/overflow settings as attributes to Region (via PartitionRegionFactoryBean -> RegionFactoryBean)
if (!subRegion) {
builder.addPropertyValue("attributes", regionAttributesBuilder.getBeanDefinition());
}
}
private void parseColocatedWith(Element element, BeanDefinitionBuilder regionBuilder,
@@ -124,12 +122,12 @@ class PartitionedRegionParser extends AbstractRegionParser {
}
}
private Object parsePartitionResolver(ParserContext parserContext, Element subElement,
private Object parsePartitionResolver(Element subElement, ParserContext parserContext,
BeanDefinitionBuilder builder) {
return ParsingUtils.parseRefOrSingleNestedBeanDeclaration(parserContext, subElement, builder);
}
private Object parsePartitionListeners(ParserContext parserContext, Element subElement,
private Object parsePartitionListeners(Element subElement, ParserContext parserContext,
BeanDefinitionBuilder builder) {
return ParsingUtils.parseRefOrNestedBeanDeclaration(parserContext, subElement, builder);
}

View File

@@ -24,9 +24,10 @@ import org.w3c.dom.Element;
/**
* Parser for &lt;replicated-region;gt; definitions.
*
* <p/>
* @author Costin Leau
* @author David Turanski
* @author John Blum
*/
class ReplicatedRegionParser extends AbstractRegionParser {
@@ -41,15 +42,13 @@ class ReplicatedRegionParser extends AbstractRegionParser {
ParsingUtils.parseScope(element, builder);
BeanDefinitionBuilder regionAttributesFactoryBuilder = (subRegion ? builder
: BeanDefinitionBuilder.genericBeanDefinition(RegionAttributesFactoryBean.class));
BeanDefinitionBuilder regionAttributesBuilder = BeanDefinitionBuilder.genericBeanDefinition(
RegionAttributesFactoryBean.class);
super.doParseCommonRegionConfiguration(element, parserContext, builder, regionAttributesFactoryBuilder,
super.doParseCommonRegionConfiguration(element, parserContext, builder, regionAttributesBuilder,
subRegion);
if (!subRegion) {
builder.addPropertyValue("attributes", regionAttributesFactoryBuilder.getBeanDefinition());
}
builder.addPropertyValue("attributes", regionAttributesBuilder.getBeanDefinition());
}
}