added subregion support

This commit is contained in:
David Turanski
2012-06-08 10:19:09 -04:00
parent 40cb46a682
commit b740727b9b
14 changed files with 1834 additions and 1237 deletions

View File

@@ -1,37 +0,0 @@
package org.springframework.data.gemfire;
import java.util.List;
import com.gemstone.gemfire.cache.RegionAttributes;
/**
*
* @author David Turanski
*
* @param <K>
* @param <V>
*/
public class SubRegion<K, V> {
private final RegionAttributes<K, V> regionAttributes;
private final String regionName;
private List<SubRegion<?,?>> subRegions;
public SubRegion(String regionName, RegionAttributes<K, V> regionAttributes) {
this.regionAttributes = regionAttributes;
this.regionName = regionName;
}
public RegionAttributes<K, V> getRegionAttributes() {
return regionAttributes;
}
public String getRegionName() {
return regionName;
}
public List<SubRegion<?, ?>> getSubRegions() {
return subRegions;
}
public void setSubRegions(List<SubRegion<?, ?>> subRegions) {
this.subRegions = subRegions;
}
}

View File

@@ -1,42 +1,79 @@
/*
* Copyright 2010-2012 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;
import java.util.List;
import org.springframework.beans.factory.BeanNameAware;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.BeanInitializationException;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.Assert;
import com.gemstone.gemfire.cache.AttributesFactory;
import com.gemstone.gemfire.cache.Region;
public class SubRegionFactoryBean<K,V> extends AttributesFactory<K,V> implements FactoryBean<SubRegion<K, V>>, InitializingBean {
@SuppressWarnings("deprecation")
/**
* FactoryBean for creating a Gemfire Region as a subregion
* @author David Turanski
*
* @param <K> - Region Key Type
* @param <V> - Region Value Type
*/
public class SubRegionFactoryBean<K, V> extends AttributesFactory<K, V> implements FactoryBean<Region<K, V>>,
InitializingBean {
protected final Log log = LogFactory.getLog(getClass());
@SuppressWarnings("unused")
private String name;
private SubRegion<K,V> subRegion;
private String regionName;
private List<SubRegion<?,?>> subRegions;
public void setName(String name) {
this.name = name;
}
private Region<K, V> subRegion;
public void setSubRegions(List<SubRegion<?, ?>> subRegions) {
this.subRegions = subRegions;
private Region<?, ?> parent;
private boolean lookupOnly;
@Override
public void afterPropertiesSet() throws Exception {
Assert.notNull(parent, "parent region must not be null");
this.subRegion = parent.getSubregion(regionName);
if (this.subRegion == null) {
if (lookupOnly) {
throw new BeanInitializationException("Cannot find region [" + regionName + "] in cache "
+ parent.getRegionService());
}
else {
log.debug("creating subregion of [" + parent.getFullPath() + "] with name " + regionName);
this.subRegion = this.parent.createSubregion(regionName, create());
}
}
}
@Override
public void afterPropertiesSet() throws Exception {
this.subRegion = new SubRegion<K,V>(name,create());
this.subRegion.setSubRegions(this.subRegions);
}
@Override
public SubRegion<K, V> getObject() throws Exception {
public Region<K, V> getObject() throws Exception {
return this.subRegion;
}
@Override
public Class<?> getObjectType() {
return SubRegion.class;
return Region.class;
}
@Override
@@ -44,4 +81,37 @@ public class SubRegionFactoryBean<K,V> extends AttributesFactory<K,V> implements
return true;
}
/**
* Set the bean name - the same as the subregion full path
* @param name
*/
public void setName(String name) {
this.name = name;
}
/**
* Set the simple name of the region
* @param regionName
*/
public void setRegionName(String regionName) {
this.regionName = regionName;
}
/**
* Set the parent Region
* @param parent
*/
public void setParent(Region<?, ?> parent) {
this.parent = parent;
}
/**
* Set to true if the subregion should already exist, e.g., specified by
* &lt;lookup-region&gt;
* @param lookupOnly
*/
public void setLookupOnly(boolean lookupOnly) {
this.lookupOnly = lookupOnly;
}
}

View File

@@ -0,0 +1,116 @@
/*
* Copyright 2012 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;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.data.gemfire.RegionFactoryBean;
import org.springframework.data.gemfire.SubRegionFactoryBean;
import org.springframework.util.StringUtils;
import org.w3c.dom.Element;
/**
* Base class for all Region Parsers
*
* @author David Turanski
*/
abstract class AbstractRegionParser extends AliasReplacingBeanDefinitionParser {
protected final Log log = LogFactory.getLog(getClass());
protected Class<?> getBeanClass(Element element) {
if (element.hasAttribute("subregion")) {
return SubRegionFactoryBean.class;
}
else {
return RegionFactoryBean.class;
}
}
@Override
protected void doParseInternal(Element element, ParserContext parserContext, BeanDefinitionBuilder builder){
super.doParse(element, builder);
boolean subRegion = element.hasAttribute("subregion");
doParseRegion(element, parserContext, builder, subRegion);
if (subRegion) {
builder.addPropertyValue("parent", parserContext.getContainingBeanDefinition().getAttribute("parent"));
builder.addPropertyValue("regionName", element.getAttribute(NAME_ATTRIBUTE));
}
}
protected abstract void doParseRegion(Element element, ParserContext parserContext, BeanDefinitionBuilder builder,
boolean subRegion);
protected void doParseSubRegion(Element element, Element subElement, ParserContext parserContext,
BeanDefinitionBuilder builder, boolean subRegion) {
String regionPath = null;
String parentBeanName = null;
if (subRegion) {
parentBeanName = parserContext.getContainingBeanDefinition().getAttribute("regionPath").toString();
}
else {
parentBeanName = getRegionNameFromElement(element);
}
regionPath = StringUtils
.arrayToDelimitedString(
new String[] { parentBeanName, getRegionNameFromElement(subElement) }, "/");
if (!regionPath.startsWith("/")) {
regionPath = "/" + regionPath;
}
/*
* The Region parser needs some context to handle recursion correctly
*/
builder.getBeanDefinition().setAttribute("parent",
new BeanDefinitionHolder(builder.getBeanDefinition(), parentBeanName));
builder.getBeanDefinition().setAttribute("regionPath",regionPath);
// Make recursive call
BeanDefinition subRegionDef = this.parseSubRegion(subElement, parserContext, builder);
//TODO: Is there a better work-around?
/*
* This setting prevents the BF from generating a name for this been
*/
subRegionDef.setScope(BeanDefinition.SCOPE_PROTOTYPE);
if (log.isDebugEnabled()) {
log.debug("registering subregion as " + regionPath);
}
this.registerBeanDefinition(new BeanDefinitionHolder(subRegionDef, regionPath), parserContext.getRegistry());
}
private BeanDefinition parseSubRegion(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
/*
* Easy way to mark this element as a subregion
*/
element.setAttribute("subregion", "true");
BeanDefinition beanDefinition = parserContext.getDelegate().parseCustomElement(element,
builder.getBeanDefinition());
return beanDefinition;
}
private String getRegionNameFromElement(Element element){
String name = element.getAttribute(NAME_ATTRIBUTE);
return StringUtils.hasText(name)? name: element.getAttribute(ID_ATTRIBUTE);
}
}

View File

@@ -16,10 +16,14 @@
package org.springframework.data.gemfire.config;
import java.util.List;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.data.gemfire.RegionLookupFactoryBean;
import org.springframework.data.gemfire.SubRegionFactoryBean;
import org.springframework.util.StringUtils;
import org.springframework.util.xml.DomUtils;
import org.w3c.dom.Element;
/**
@@ -27,21 +31,41 @@ import org.w3c.dom.Element;
*
* @author Costin Leau
*/
class LookupRegionParser extends AliasReplacingBeanDefinitionParser {
class LookupRegionParser extends AbstractRegionParser {
@Override
protected Class<?> getBeanClass(Element element) {
return RegionLookupFactoryBean.class;
if (element.hasAttribute("subregion")) {
return SubRegionFactoryBean.class;
}
else {
return RegionLookupFactoryBean.class;
}
}
@Override
protected void doParseInternal(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
protected void doParseRegion(Element element, ParserContext parserContext, BeanDefinitionBuilder builder,
boolean subRegion) {
super.doParse(element, builder);
ParsingUtils.setPropertyValue(element, builder, "name", "name");
String attr = element.getAttribute("cache-ref");
// add cache reference (fallback to default if nothing is specified)
builder.addPropertyReference("cache", (StringUtils.hasText(attr) ? attr : "gemfire-cache"));
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 : "gemfire-cache"));
}
else {
builder.addPropertyValue("lookupOnly", true);
}
// parse nested elements
List<Element> subElements = DomUtils.getChildElements(element);
for (Element subElement : subElements) {
String name = subElement.getLocalName();
if (name.endsWith("region")) {
doParseSubRegion(element, subElement, parserContext, builder, subRegion);
}
}
}
}

View File

@@ -23,7 +23,6 @@ import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.data.gemfire.PartitionAttributesFactoryBean;
import org.springframework.data.gemfire.RegionAttributesFactoryBean;
import org.springframework.data.gemfire.RegionFactoryBean;
import org.springframework.util.StringUtils;
import org.springframework.util.xml.DomUtils;
import org.w3c.dom.Element;
@@ -35,18 +34,17 @@ import com.gemstone.gemfire.cache.Region;
/**
* Parser for &lt;partitioned-region;gt; definitions.
*
* To avoid eager evaluations, the region attributes are declared as a nested definition.
* To avoid eager evaluations, the region attributes are declared as a nested
* definition.
*
* @author Costin Leau
* @author David Turanski
*/
class PartitionedRegionParser extends AliasReplacingBeanDefinitionParser {
protected Class<?> getBeanClass(Element element) {
return RegionFactoryBean.class;
}
class PartitionedRegionParser extends AbstractRegionParser {
@Override
protected void doParseInternal(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
protected void doParseRegion(Element element, ParserContext parserContext, BeanDefinitionBuilder builder,
boolean subRegion) {
super.doParse(element, builder);
// set the data policy
@@ -67,23 +65,24 @@ class PartitionedRegionParser extends AliasReplacingBeanDefinitionParser {
builder.addPropertyValue("dataPolicy", DataPolicy.PARTITION);
}
BeanDefinitionBuilder attrBuilder = builder;
if (!subRegion) {
attr = element.getAttribute("cache-ref");
// add cache reference (fallback to default if nothing is specified)
builder.addPropertyReference("cache", (StringUtils.hasText(attr) ? attr : "gemfire-cache"));
attrBuilder = BeanDefinitionBuilder.genericBeanDefinition(RegionAttributesFactoryBean.class);
}
ParsingUtils.setPropertyValue(element, builder, "name", "name");
attr = element.getAttribute("cache-ref");
// add cache reference (fallback to default if nothing is specified)
builder.addPropertyReference("cache", (StringUtils.hasText(attr) ? attr : "gemfire-cache"));
// region attributes
BeanDefinitionBuilder attrBuilder = BeanDefinitionBuilder.genericBeanDefinition(RegionAttributesFactoryBean.class);
ParsingUtils.parseStatistics(element, attrBuilder);
ParsingUtils.parseExpiration(parserContext, element, attrBuilder);
ParsingUtils.parseEviction(parserContext, element, attrBuilder);
ParsingUtils.parseDiskStorage(element, attrBuilder);
// partition attributes
BeanDefinitionBuilder parAttrBuilder = BeanDefinitionBuilder.genericBeanDefinition(PartitionAttributesFactoryBean.class);
BeanDefinitionBuilder parAttrBuilder = BeanDefinitionBuilder
.genericBeanDefinition(PartitionAttributesFactoryBean.class);
attr = element.getAttribute("colocated-with");
@@ -122,7 +121,6 @@ class PartitionedRegionParser extends AliasReplacingBeanDefinitionParser {
parAttrBuilder.addPropertyValue("totalNumBuckets", Integer.valueOf(attr));
}
List<Element> subElements = DomUtils.getChildElements(element);
// parse nested cache-listener elements
@@ -142,15 +140,21 @@ class PartitionedRegionParser extends AliasReplacingBeanDefinitionParser {
}
else if ("partition-resolver".equals(name)) {
parAttrBuilder.addPropertyValue("partitionResolver", parsePartitionResolver(parserContext, subElement,
builder));
parAttrBuilder.addPropertyValue("partitionResolver",
parsePartitionResolver(parserContext, subElement, builder));
}
// subregion
else if (name.endsWith("region")) {
doParseSubRegion(element, subElement, parserContext, builder, subRegion);
}
}
// add partition attributes attributes
attrBuilder.addPropertyValue("partitionAttributes", parAttrBuilder.getBeanDefinition());
// add partition/overflow settings as attributes
builder.addPropertyValue("attributes", attrBuilder.getBeanDefinition());
if (!subRegion) {
builder.addPropertyValue("attributes", attrBuilder.getBeanDefinition());
}
}
private Object parseCacheListener(ParserContext parserContext, Element subElement, BeanDefinitionBuilder builder) {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2010-2011 the original author or authors.
* Copyright 2010-2012 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.
@@ -18,15 +18,9 @@ package org.springframework.data.gemfire.config;
import java.util.List;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.ManagedList;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.data.gemfire.RegionAttributesFactoryBean;
import org.springframework.data.gemfire.SubRegion;
import org.springframework.data.gemfire.SubRegionFactoryBean;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.util.xml.DomUtils;
import org.w3c.dom.Element;
@@ -38,18 +32,13 @@ import com.gemstone.gemfire.cache.Scope;
* Parser for &lt;replicated-region;gt; definitions.
*
* @author Costin Leau
* @author David Turanski
*/
class ReplicatedRegionParser extends AliasReplacingBeanDefinitionParser {
class ReplicatedRegionParser extends AbstractRegionParser {
@Override
protected void doParseInternal(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
super.doParse(element, builder);
System.out.println("building class " +
builder.getBeanDefinition().getBeanClassName());
protected void doParseRegion(Element element, ParserContext parserContext, BeanDefinitionBuilder builder,
boolean subRegion) {
boolean subRegion = element.hasAttribute("subregion");
// set the data policy
String attr = element.getAttribute("persistent");
if (Boolean.parseBoolean(attr)) {
@@ -64,8 +53,8 @@ class ReplicatedRegionParser extends AliasReplacingBeanDefinitionParser {
ParsingUtils.setPropertyValue(element, builder, "name", "name");
BeanDefinitionBuilder attrBuilder = builder;
if (!subRegion){
if (!subRegion) {
attr = element.getAttribute("cache-ref");
// add cache reference (fallback to default if nothing is specified)
builder.addPropertyReference("cache", (StringUtils.hasText(attr) ? attr : "gemfire-cache"));
@@ -84,13 +73,12 @@ class ReplicatedRegionParser extends AliasReplacingBeanDefinitionParser {
ParsingUtils.parseEviction(parserContext, element, attrBuilder);
ParsingUtils.parseDiskStorage(element, attrBuilder);
builder.addPropertyValue("attributes", attrBuilder.getBeanDefinition());
if (!subRegion) {
builder.addPropertyValue("attributes", attrBuilder.getBeanDefinition());
}
List<Element> subElements = DomUtils.getChildElements(element);
ManagedList subRegions = new ManagedList();
subRegions.setElementTypeName(SubRegionFactoryBean.class.getName());
// parse nested elements
for (Element subElement : subElements) {
String name = subElement.getLocalName();
@@ -106,23 +94,11 @@ class ReplicatedRegionParser extends AliasReplacingBeanDefinitionParser {
else if ("cache-writer".equals(name)) {
builder.addPropertyValue("cacheWriter", parseCacheWriter(parserContext, subElement, builder));
}
//subregion
else if (name.endsWith("region")){
System.out.println("element type:" + subElement.getSchemaTypeInfo().getTypeName());
String parentRegionName = StringUtils.hasLength(element.getAttribute(NAME_ATTRIBUTE))? element.getAttribute(NAME_ATTRIBUTE):
element.getAttribute(ID_ATTRIBUTE);
BeanDefinition subRegionDef = this.parseSubRegion(subElement, parserContext, parentRegionName,builder.getBeanDefinition());
subRegions.add(subRegionDef);
System.out.println("parsed subregion " + subRegionDef);
// subregion
else if (name.endsWith("region")) {
doParseSubRegion(element, subElement, parserContext, builder, subRegion);
}
}
if (!CollectionUtils.isEmpty(subRegions)) {
builder.addPropertyValue("subRegions", subRegions);
}
}
private Object parseCacheListener(ParserContext parserContext, Element subElement, BeanDefinitionBuilder builder) {
@@ -137,10 +113,4 @@ class ReplicatedRegionParser extends AliasReplacingBeanDefinitionParser {
return ParsingUtils.parseRefOrNestedBeanDeclaration(parserContext, subElement, builder);
}
private BeanDefinition parseSubRegion(Element element, ParserContext parserContext, String parentRegionName,
BeanDefinition parentDefinition) {
element.setAttribute("subregion", "true");
BeanDefinition beanDefinition = parserContext.getDelegate().parseCustomElement(element, parentDefinition);
return beanDefinition;
}
}