diff --git a/src/main/java/org/springframework/data/gemfire/RegionFactoryBean.java b/src/main/java/org/springframework/data/gemfire/RegionFactoryBean.java index d1179234..fb057bec 100644 --- a/src/main/java/org/springframework/data/gemfire/RegionFactoryBean.java +++ b/src/main/java/org/springframework/data/gemfire/RegionFactoryBean.java @@ -77,6 +77,8 @@ public class RegionFactoryBean extends RegionLookupFactoryBean imple private Object[] asyncEventQueues; private Object[] gatewaySenders; + private Region parent; + private RegionAttributes attributes; private Resource snapshot; @@ -103,11 +105,11 @@ public class RegionFactoryBean extends RegionLookupFactoryBean imple AttributesFactory.validateAttributes(attributes); } - final RegionFactory regionFactory = (attributes != null ? cache.createRegionFactory(attributes) : - cache. createRegionFactory()); + RegionFactory regionFactory = (attributes != null ? cache.createRegionFactory(attributes) + : cache.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 extends RegionLookupFactoryBean 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 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 extends RegionLookupFactoryBean imple } } + if (!ObjectUtils.isEmpty(cacheListeners)) { + for (CacheListener listener : cacheListeners) { + regionFactory.addCacheListener(listener); + } + } + if (cacheLoader != null) { regionFactory.setCacheLoader(cacheLoader); } @@ -164,10 +167,20 @@ public class RegionFactoryBean extends RegionLookupFactoryBean imple } // get underlying AttributesFactory - postProcess(findAttrFactory(regionFactory)); + postProcess(findAttributesFactory(regionFactory)); - Region region = regionFactory.create(regionName); - log.info("Created new cache region [" + regionName + "]"); + Region 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 extends RegionLookupFactoryBean imple } @SuppressWarnings("unchecked") - private AttributesFactory findAttrFactory(RegionFactory regionFactory) { + private AttributesFactory findAttributesFactory(RegionFactory regionFactory) { Field attrsFactoryField = ReflectionUtils.findField(RegionFactory.class, "attrsFactory", AttributesFactory.class); ReflectionUtils.makeAccessible(attrsFactoryField); @@ -218,12 +231,13 @@ public class RegionFactoryBean extends RegionLookupFactoryBean 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 attrFactory) { + @SuppressWarnings("unused") + protected void postProcess(AttributesFactory attributesFactory) { } /** @@ -233,6 +247,7 @@ public class RegionFactoryBean extends RegionLookupFactoryBean imple * * @param region */ + @SuppressWarnings("unused") protected void postProcess(Region region) { } @@ -244,17 +259,38 @@ public class RegionFactoryBean extends RegionLookupFactoryBean 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 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 extends RegionLookupFactoryBean 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 created region. That - * is, the snapshot will be used only 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 extends RegionLookupFactoryBean 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 extends RegionLookupFactoryBean 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 extends RegionLookupFactoryBean 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 attributes) { - this.attributes = attributes; + public void setScope(Scope scope) { + this.scope = scope; + } + + /** + * Sets the snapshots used for loading a newly created region. That + * is, the snapshot will be used only 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; } /** diff --git a/src/main/java/org/springframework/data/gemfire/RegionLookupFactoryBean.java b/src/main/java/org/springframework/data/gemfire/RegionLookupFactoryBean.java index dfdcadb3..b4e18954 100644 --- a/src/main/java/org/springframework/data/gemfire/RegionLookupFactoryBean.java +++ b/src/main/java/org/springframework/data/gemfire/RegionLookupFactoryBean.java @@ -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}. + *

* @author Costin Leau + * @author John Blum */ public class RegionLookupFactoryBean implements FactoryBean>, InitializingBean, BeanNameAware { @@ -45,21 +45,24 @@ public class RegionLookupFactoryBean implements FactoryBean>, 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 implements FactoryBean>, * @throws Exception */ protected Region 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 getObject() throws Exception { @@ -88,34 +92,52 @@ public class RegionLookupFactoryBean implements FactoryBean>, 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. + *

+ * @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. + *

+ * @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. + *

* @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. + *

+ * @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 getRegion() { return region; } diff --git a/src/main/java/org/springframework/data/gemfire/ReplicatedRegionFactoryBean.java b/src/main/java/org/springframework/data/gemfire/ReplicatedRegionFactoryBean.java index 50ff9cae..642f8d85 100644 --- a/src/main/java/org/springframework/data/gemfire/ReplicatedRegionFactoryBean.java +++ b/src/main/java/org/springframework/data/gemfire/ReplicatedRegionFactoryBean.java @@ -33,19 +33,19 @@ public class ReplicatedRegionFactoryBean extends RegionFactoryBean { 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. )! - 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 { diff --git a/src/main/java/org/springframework/data/gemfire/SubRegionFactoryBean.java b/src/main/java/org/springframework/data/gemfire/SubRegionFactoryBean.java index cdaa917c..95d0733b 100644 --- a/src/main/java/org/springframework/data/gemfire/SubRegionFactoryBean.java +++ b/src/main/java/org/springframework/data/gemfire/SubRegionFactoryBean.java @@ -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. *

* @author David Turanski * @author John Blum - * @param - Region Key Type - * @param - Region Value Type + * @param Region Key Type + * @param 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 extends AttributesFactory implements FactoryBean>, InitializingBean { diff --git a/src/main/java/org/springframework/data/gemfire/config/AbstractRegionParser.java b/src/main/java/org/springframework/data/gemfire/config/AbstractRegionParser.java index c5b8e368..339882ae 100644 --- a/src/main/java/org/springframework/data/gemfire/config/AbstractRegionParser.java +++ b/src/main/java/org/springframework/data/gemfire/config/AbstractRegionParser.java @@ -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 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 allSubRegionElements = new HashMap(); - findSubregionElements(element, getRegionNameFromElement(element), allSubRegionElements); - if (!CollectionUtils.isEmpty(allSubRegionElements)) { - for (Map.Entry 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 subElements = DomUtils.getChildElementsByTagName(element, new String[] { subElementName, - subElementName + "-ref" }); - if (!CollectionUtils.isEmpty(subElements)) { + private void parseSubRegions(Element element, ParserContext parserContext, String resolvedCacheRef) { + Map allSubRegionElements = new HashMap(); + findSubRegionElements(element, getRegionNameFromElement(element), allSubRegionElements); + + if (!CollectionUtils.isEmpty(allSubRegionElements)) { + for (Map.Entry 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 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 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 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); - } - } - } - } diff --git a/src/main/java/org/springframework/data/gemfire/config/ClientRegionParser.java b/src/main/java/org/springframework/data/gemfire/config/ClientRegionParser.java index bd598ab5..85d98596 100644 --- a/src/main/java/org/springframework/data/gemfire/config/ClientRegionParser.java +++ b/src/main/java/org/springframework/data/gemfire/config/ClientRegionParser.java @@ -78,6 +78,7 @@ class ClientRegionParser extends AbstractRegionParser { builder.addPropertyValue("attributes", regionAttributesBuilder.getBeanDefinition()); List subElements = DomUtils.getChildElements(element); + ManagedList interests = new ManagedList(); 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())); diff --git a/src/main/java/org/springframework/data/gemfire/config/GemfireNamespaceHandler.java b/src/main/java/org/springframework/data/gemfire/config/GemfireNamespaceHandler.java index f603c90d..60f15ea3 100644 --- a/src/main/java/org/springframework/data/gemfire/config/GemfireNamespaceHandler.java +++ b/src/main/java/org/springframework/data/gemfire/config/GemfireNamespaceHandler.java @@ -31,12 +31,12 @@ import org.w3c.dom.Element; * @author David Turanski */ class GemfireNamespaceHandler extends NamespaceHandlerSupport { - static final List GEMFIRE7_ELEMENTS = Arrays.asList("async-event-queue", "gateway-sender", - "gateway-receiver"); + + protected static final List 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()); } } diff --git a/src/main/java/org/springframework/data/gemfire/config/LocalRegionParser.java b/src/main/java/org/springframework/data/gemfire/config/LocalRegionParser.java index aef8e54c..b76f3e5c 100644 --- a/src/main/java/org/springframework/data/gemfire/config/LocalRegionParser.java +++ b/src/main/java/org/springframework/data/gemfire/config/LocalRegionParser.java @@ -23,27 +23,28 @@ import org.springframework.data.gemfire.RegionAttributesFactoryBean; import org.w3c.dom.Element; /** - * Parser for <local-region;gt; definitions. - * + * Parser for <local-region;gt; bean definitions. + *

* @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; } -} \ No newline at end of file + @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()); + } + +} diff --git a/src/main/java/org/springframework/data/gemfire/config/LookupRegionParser.java b/src/main/java/org/springframework/data/gemfire/config/LookupRegionParser.java index 3c601e87..2d20d6e2 100644 --- a/src/main/java/org/springframework/data/gemfire/config/LookupRegionParser.java +++ b/src/main/java/org/springframework/data/gemfire/config/LookupRegionParser.java @@ -24,9 +24,10 @@ import org.w3c.dom.Element; /** * Parser for <lookup-region;gt; definitions. - * + *

* @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); diff --git a/src/main/java/org/springframework/data/gemfire/config/ParsingUtils.java b/src/main/java/org/springframework/data/gemfire/config/ParsingUtils.java index 3e417180..1110ca42 100644 --- a/src/main/java/org/springframework/data/gemfire/config/ParsingUtils.java +++ b/src/main/java/org/springframework/data/gemfire/config/ParsingUtils.java @@ -183,10 +183,12 @@ abstract class ParsingUtils { *

* @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 { *

* @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, diff --git a/src/main/java/org/springframework/data/gemfire/config/PartitionedRegionParser.java b/src/main/java/org/springframework/data/gemfire/config/PartitionedRegionParser.java index 479e14d6..7065f410 100644 --- a/src/main/java/org/springframework/data/gemfire/config/PartitionedRegionParser.java +++ b/src/main/java/org/springframework/data/gemfire/config/PartitionedRegionParser.java @@ -31,11 +31,10 @@ import org.springframework.util.xml.DomUtils; import org.w3c.dom.Element; /** - * Parser for <partitioned-region;gt; definitions. - * - * To avoid eager evaluations, the region attributes are declared as a nested - * definition. - * + * Parser for <partitioned-region;gt; bean definitions. + *

+ * To avoid eager evaluations, the region attributes are declared as a nested definition. + *

* @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 fixedPartitions = DomUtils.getChildElementsByTagName(element, "fixed-partition"); + List 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); } diff --git a/src/main/java/org/springframework/data/gemfire/config/ReplicatedRegionParser.java b/src/main/java/org/springframework/data/gemfire/config/ReplicatedRegionParser.java index dbea7541..58eed613 100644 --- a/src/main/java/org/springframework/data/gemfire/config/ReplicatedRegionParser.java +++ b/src/main/java/org/springframework/data/gemfire/config/ReplicatedRegionParser.java @@ -24,9 +24,10 @@ import org.w3c.dom.Element; /** * Parser for <replicated-region;gt; definitions. - * + *

* @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()); } } diff --git a/src/main/resources/org/springframework/data/gemfire/config/spring-gemfire-1.4.xsd b/src/main/resources/org/springframework/data/gemfire/config/spring-gemfire-1.4.xsd index 610baa87..585a07f0 100644 --- a/src/main/resources/org/springframework/data/gemfire/config/spring-gemfire-1.4.xsd +++ b/src/main/resources/org/springframework/data/gemfire/config/spring-gemfire-1.4.xsd @@ -733,37 +733,33 @@ arbitrarily pick one. - + +Establishes reliability requirements and behavior for a region. Use this to configure the region to require one or more membership roles to be running in the system for reliable access to the region. + ]]> - + - + - + diff --git a/src/test/java/org/springframework/data/gemfire/SubRegionIntegrationTest.java b/src/test/java/org/springframework/data/gemfire/SubRegionIntegrationTest.java new file mode 100644 index 00000000..6dcccd3c --- /dev/null +++ b/src/test/java/org/springframework/data/gemfire/SubRegionIntegrationTest.java @@ -0,0 +1,139 @@ +/* + * Copyright 2010-2013 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 static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; + +import javax.annotation.Resource; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import com.gemstone.gemfire.cache.Cache; +import com.gemstone.gemfire.cache.DataPolicy; +import com.gemstone.gemfire.cache.EvictionAction; +import com.gemstone.gemfire.cache.EvictionAttributes; +import com.gemstone.gemfire.cache.InterestPolicy; +import com.gemstone.gemfire.cache.LossAction; +import com.gemstone.gemfire.cache.MembershipAttributes; +import com.gemstone.gemfire.cache.Region; +import com.gemstone.gemfire.cache.RegionAttributes; +import com.gemstone.gemfire.cache.ResumptionAction; +import com.gemstone.gemfire.cache.Scope; +import com.gemstone.gemfire.cache.SubscriptionAttributes; + +/** + * The SubRegionIntegrationTest class is a test suite of test cases testing the functionality of SubRegions in GemFire + * configured with Spring Data GemFire's XML namespace configuration meta-data. This test class tests a complex + * SubRegion configuration in order to ensure functional completeness. + *

+ * @author John Blum + * @see org.junit.Test + * @see org.junit.runner.RunWith + * @see org.springframework.test.context.ContextConfiguration + * @see org.springframework.test.context.junit4.SpringJUnit4ClassRunner + * @since 1.4.0 + * @since 7.0.1 (GemFire) + */ +@ContextConfiguration("complex-subregion.xml") +@RunWith(SpringJUnit4ClassRunner.class) +public class SubRegionIntegrationTest { + + @Autowired + private Cache cache; + + @Resource(name = "Customers") + private Region customers; + + @Resource(name = "/Customers/Accounts") + private Region accounts; + + @Test + public void testGemFireAccountsSubRegionCreation() { + assertNotNull("The GemFire Cache was not properly initialized!", cache); + + Region customers = cache.getRegion("Customers"); + + assertNotNull(customers); + assertEquals("Customers", customers.getName()); + assertEquals("/Customers", customers.getFullPath()); + + Region accounts = customers.getSubregion("Accounts"); + + assertNotNull(accounts); + assertEquals("Accounts", accounts.getName()); + assertEquals("/Customers/Accounts", accounts.getFullPath()); + + Region cacheAccounts = cache.getRegion("/Customers/Accounts"); + + assertSame(accounts, cacheAccounts); + } + + @Test + public void testSpringSubRegionConfiguration() { + assertNotNull("The /Customers/Accounts SubRegion was not properly initialized!", accounts); + assertEquals("Accounts", accounts.getName()); + assertEquals("/Customers/Accounts", accounts.getFullPath()); + + RegionAttributes regionAttributes = accounts.getAttributes(); + + assertNotNull(regionAttributes); + assertEquals(DataPolicy.PERSISTENT_REPLICATE, regionAttributes.getDataPolicy()); + assertEquals(20, regionAttributes.getConcurrencyLevel()); + assertTrue(regionAttributes.isDiskSynchronous()); + assertTrue(regionAttributes.getIgnoreJTA()); + assertFalse(regionAttributes.getIndexMaintenanceSynchronous()); + assertEquals(1000, regionAttributes.getInitialCapacity()); + assertEquals(Long.class, regionAttributes.getKeyConstraint()); + assertEquals(Scope.DISTRIBUTED_ACK, regionAttributes.getScope()); + assertTrue(regionAttributes.getStatisticsEnabled()); + assertEquals(String.class, regionAttributes.getValueConstraint()); + assertNotNull(regionAttributes.getCacheListeners()); + assertEquals(1, regionAttributes.getCacheListeners().length); + assertTrue(regionAttributes.getCacheListeners()[0] instanceof SimpleCacheListener); + assertTrue(regionAttributes.getCacheLoader() instanceof SimpleCacheLoader); + assertTrue(regionAttributes.getCacheWriter() instanceof SimpleCacheWriter); + + EvictionAttributes evictionAttributes = regionAttributes.getEvictionAttributes(); + + assertNotNull(evictionAttributes); + assertEquals(EvictionAction.OVERFLOW_TO_DISK, evictionAttributes.getAction()); + assertEquals(10000, evictionAttributes.getMaximum()); + + MembershipAttributes membershipAttributes = regionAttributes.getMembershipAttributes(); + + assertNotNull(membershipAttributes); + assertNotNull(membershipAttributes.getRequiredRoles()); + assertEquals(1, membershipAttributes.getRequiredRoles().size()); + assertTrue(membershipAttributes.getRequiredRoles().iterator().next().getName().equalsIgnoreCase("TEST")); + assertEquals(LossAction.LIMITED_ACCESS, membershipAttributes.getLossAction()); + assertEquals(ResumptionAction.REINITIALIZE, membershipAttributes.getResumptionAction()); + + SubscriptionAttributes subscriptionAttributes = regionAttributes.getSubscriptionAttributes(); + + assertNotNull(subscriptionAttributes); + assertEquals(InterestPolicy.CACHE_CONTENT, subscriptionAttributes.getInterestPolicy()); + } + +} diff --git a/src/test/java/org/springframework/data/gemfire/config/ClientRegionUsingDataPolicyAndShortcutTest.java b/src/test/java/org/springframework/data/gemfire/config/ClientRegionUsingDataPolicyAndShortcutTest.java index 91727065..7cf8febf 100644 --- a/src/test/java/org/springframework/data/gemfire/config/ClientRegionUsingDataPolicyAndShortcutTest.java +++ b/src/test/java/org/springframework/data/gemfire/config/ClientRegionUsingDataPolicyAndShortcutTest.java @@ -16,7 +16,6 @@ package org.springframework.data.gemfire.config; -import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import org.junit.Test; @@ -28,7 +27,7 @@ import org.springframework.context.support.ClassPathXmlApplicationContext; * bean definition with both data-policy and shortcut specified. *

* @author John Blum - * @see org.junit.Assert + * @see org.junit.Test * @since 1.3.3 */ public class ClientRegionUsingDataPolicyAndShortcutTest { diff --git a/src/test/java/org/springframework/data/gemfire/config/SubRegionNamespaceTest.java b/src/test/java/org/springframework/data/gemfire/config/SubRegionNamespaceTest.java index 45054a45..ea3e2426 100644 --- a/src/test/java/org/springframework/data/gemfire/config/SubRegionNamespaceTest.java +++ b/src/test/java/org/springframework/data/gemfire/config/SubRegionNamespaceTest.java @@ -24,24 +24,31 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; -import org.springframework.data.gemfire.SubRegionFactoryBean; +import org.springframework.data.gemfire.ReplicatedRegionFactoryBean; +import org.springframework.data.gemfire.TestUtils; import org.springframework.data.gemfire.test.GemfireTestApplicationContextInitializer; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; -import com.gemstone.gemfire.cache.AttributesFactory; import com.gemstone.gemfire.cache.Cache; import com.gemstone.gemfire.cache.CacheLoader; import com.gemstone.gemfire.cache.Region; -import com.gemstone.gemfire.cache.RegionAttributes; /** + * The SubRegionNamespaceTest class is a test suite of test cases testing the contract and functionality of + * Region/SubRegion creation in a GemFire Cache. + *

* @author David Turanski + * @author John Blum + * @see org.junit.Test + * @see org.junit.runner.RunWith + * @see org.springframework.data.gemfire.test.GemfireTestApplicationContextInitializer + * @see org.springframework.test.context.ContextConfiguration + * @see org.springframework.test.context.junit4.SpringJUnit4ClassRunner */ -@SuppressWarnings("deprecation") +@ContextConfiguration(locations = "subregion-ns.xml", initializers = GemfireTestApplicationContextInitializer.class) @RunWith(SpringJUnit4ClassRunner.class) -@ContextConfiguration(locations="subregion-ns.xml", -initializers=GemfireTestApplicationContextInitializer.class) +@SuppressWarnings("deprecation") public class SubRegionNamespaceTest { @Autowired @@ -51,6 +58,7 @@ public class SubRegionNamespaceTest { @Test public void testNestedRegionsCreated() { Cache cache = context.getBean(Cache.class); + assertNotNull(cache.getRegion("parent")); assertNotNull(cache.getRegion("/parent/child")); assertNotNull(cache.getRegion("/parent/child/grandchild")); @@ -59,35 +67,31 @@ public class SubRegionNamespaceTest { @SuppressWarnings("rawtypes") @Test public void testNestedReplicatedRegions() { - Region parent = null; - parent = context.getBean("parent", Region.class); - Cache cache = context.getBean(Cache.class); + Region parent = context.getBean("parent", Region.class); Region child = context.getBean("/parent/child", Region.class); Region grandchild = context.getBean("/parent/child/grandchild", Region.class); + assertNotNull(child); assertEquals("/parent/child", child.getFullPath()); assertSame(child, parent.getSubregion("child")); - + assertNotNull(grandchild); assertEquals("/parent/child/grandchild", grandchild.getFullPath()); assertSame(grandchild, child.getSubregion("grandchild")); - } - @SuppressWarnings({ "unused", "rawtypes", "unchecked" }) + @SuppressWarnings({ "rawtypes", "unchecked" }) @Test public void testMixedNestedRegions() { - Cache cache = context.getBean(Cache.class); - Region parent = context.getBean("replicatedParent", Region.class); - Region child = context.getBean("/replicatedParent/replicatedChild", Region.class); Region grandchild = context.getBean("/replicatedParent/replicatedChild/partitionedGrandchild", Region.class); + assertNotNull(child); assertEquals("/replicatedParent/replicatedChild", child.getFullPath()); - + assertEquals(child, parent.getSubregion("replicatedChild")); + assertNotNull(grandchild); assertEquals("/replicatedParent/replicatedChild/partitionedGrandchild", grandchild.getFullPath()); assertSame(grandchild, child.getSubregion("partitionedGrandchild")); - } @SuppressWarnings("rawtypes") @@ -100,25 +104,29 @@ public class SubRegionNamespaceTest { assertEquals("/parentWithSiblings/child2", child2.getFullPath()); assertSame(child1, parent.getSubregion("child1")); assertSame(child2, parent.getSubregion("child2")); - Region grandchild1 = context.getBean("/parentWithSiblings/child1/grandChild11", Region.class); assertEquals("/parentWithSiblings/child1/grandChild11", grandchild1.getFullPath()); } - @SuppressWarnings({ "unused", "rawtypes" }) + @SuppressWarnings({ "rawtypes", "unused" }) @Test public void testComplexNestedRegions() throws Exception { Region parent = context.getBean("complexNested", Region.class); Region child1 = context.getBean("/complexNested/child1", Region.class); Region child2 = context.getBean("/complexNested/child2", Region.class); - Region grandchild1 = context.getBean("/complexNested/child1/grandChild11", Region.class); + Region grandchild11 = context.getBean("/complexNested/child1/grandChild11", Region.class); - SubRegionFactoryBean grandchild1fb = context.getBean("&/complexNested/child1/grandChild11", - SubRegionFactoryBean.class); - assertNotNull(grandchild1fb); - RegionAttributes attr = grandchild1fb.create(); - assertNotNull(attr); - CacheLoader cl = attr.getCacheLoader(); - assertNotNull(cl); + ReplicatedRegionFactoryBean grandchild11FactoryBean = context.getBean("&/complexNested/child1/grandChild11", + ReplicatedRegionFactoryBean.class); + + assertNotNull(grandchild11FactoryBean); + + CacheLoader expectedCacheLoader = TestUtils.readField("cacheLoader", grandchild11FactoryBean); + + assertNotNull(expectedCacheLoader); + + CacheLoader actualCacheLoader = grandchild11.getAttributes().getCacheLoader(); + + assertSame(expectedCacheLoader, actualCacheLoader); } -} \ No newline at end of file +} diff --git a/src/test/java/org/springframework/data/gemfire/config/SubRegionWithInvalidDataPolicyTest.java b/src/test/java/org/springframework/data/gemfire/config/SubRegionWithInvalidDataPolicyTest.java new file mode 100644 index 00000000..8f6f4350 --- /dev/null +++ b/src/test/java/org/springframework/data/gemfire/config/SubRegionWithInvalidDataPolicyTest.java @@ -0,0 +1,68 @@ +/* + * Copyright 2010-2013 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 static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; +import org.springframework.beans.factory.BeanCreationException; +import org.springframework.context.support.ClassPathXmlApplicationContext; + +/** + * The SubRegionWithInvalidDataPolicyTest class is a test suite of test cases testing the data-policy and persistent + * attributes settings are consistent for GemFire SubRegion bean definitions. + *

+ * @author John Blum + * @see org.junit.Test + * @see org.springframework.test.context.junit4.SpringJUnit4ClassRunner + * @since GemFire 7.0.1 + * @since Spring Data GemFire 1.4.0 + */ +public class SubRegionWithInvalidDataPolicyTest { + + @Test(expected = BeanCreationException.class) + public void testSubRegionBeanDefinitionWithInconsistentDataPolicy() { + try { + new ClassPathXmlApplicationContext("/org/springframework/data/gemfire/config/subregion-with-invalid-datapolicy.xml"); + } + catch (BeanCreationException expected) { + //expected.printStackTrace(System.err); + assertTrue(expected.getMessage().contains("Error creating bean with name '/Parent/Child'")); + assertTrue(expected.getCause() instanceof IllegalArgumentException); + assertEquals("Data Policy 'PERSISTENT_PARTITION' is not supported in Replicated Regions.", + expected.getCause().getMessage()); + throw expected; + } + } + + @Test(expected = BeanCreationException.class) + public void testSubRegionBeanDefinitionWithInvalidDataPolicyPersistentSettings() { + try { + new ClassPathXmlApplicationContext("/org/springframework/data/gemfire/config/subregion-with-inconsistent-datapolicy-persistent-settings.xml"); + } + catch (BeanCreationException expected) { + //expected.printStackTrace(System.err); + assertTrue(expected.getMessage().contains("Error creating bean with name '/Parent/Child'")); + assertTrue(expected.getCause() instanceof IllegalArgumentException); + assertEquals("Data Policy 'REPLICATE' is invalid when persistent is true.", + expected.getCause().getMessage()); + throw expected; + } + } + +} diff --git a/src/test/java/org/springframework/data/gemfire/test/MockRegionFactory.java b/src/test/java/org/springframework/data/gemfire/test/MockRegionFactory.java index 57bae91d..268f45e6 100644 --- a/src/test/java/org/springframework/data/gemfire/test/MockRegionFactory.java +++ b/src/test/java/org/springframework/data/gemfire/test/MockRegionFactory.java @@ -42,19 +42,19 @@ import com.gemstone.gemfire.cache.RegionService; import com.gemstone.gemfire.cache.Scope; import com.gemstone.gemfire.cache.SubscriptionAttributes; import com.gemstone.gemfire.cache.query.QueryService; + /** * @author David Turanski - * + * @author John Blum */ - @SuppressWarnings("deprecation") public class MockRegionFactory { - + private static QueryService queryService = mock(QueryService.class); private static RegionService regionService = mock(RegionService.class); - + private AttributesFactory attributesFactory; - + private final StubCache cache; public MockRegionFactory(StubCache cache) { @@ -64,50 +64,55 @@ public class MockRegionFactory { public RegionFactory createMockRegionFactory() { return createMockRegionFactory(null); } - - @SuppressWarnings({ "unchecked", "rawtypes" }) - public RegionFactory createMockRegionFactory(RegionAttributes attributes) { - attributesFactory = attributes == null? - new AttributesFactory() : - new AttributesFactory(attributes) ; - //Workaround for GemFire bug - if(attributes !=null) { - attributesFactory.setLockGrantor(attributes.isLockGrantor()); - } - - final RegionFactory regionFactory = mock(RegionFactory.class); - - when(regionFactory.create(anyString())).thenAnswer(new Answer() { + @SuppressWarnings({ "unchecked", "rawtypes" }) + public RegionFactory createMockRegionFactory(RegionAttributes attributes) { + attributesFactory = (attributes != null ? new AttributesFactory(attributes) + : new AttributesFactory()); + + //Workaround for GemFire bug + if (attributes !=null) { + attributesFactory.setLockGrantor(attributes.isLockGrantor()); + } + + final RegionFactory regionFactory = mock(RegionFactory.class); + + when(regionFactory.create(anyString())).thenAnswer(new Answer() { @Override public Region answer(InvocationOnMock invocation) throws Throwable { - String name = (String)invocation.getArguments()[0]; + String name = (String) invocation.getArguments()[0]; Region region = mockRegion(name); cache.allRegions().put(name, region); return region; - }}); - - - when(regionFactory.createSubregion(any(Region.class),anyString())).thenAnswer(new Answer() { + } + }); + when(regionFactory.createSubregion(any(Region.class),anyString())).thenAnswer(new Answer() { @Override public Region answer(InvocationOnMock invocation) throws Throwable { - Region parent = (Region)invocation.getArguments()[0]; - String name = (String)invocation.getArguments()[1]; - - String parentName = null; + Region parent = (Region) invocation.getArguments()[0]; + String name = (String) invocation.getArguments()[1]; + String parentRegionName = null; + for (String key: cache.allRegions().keySet()) { if (cache.allRegions().get(key).equals(parent)) { - parentName = key; + parentRegionName = key; } } - String regionName = parentName.startsWith("/") ? parentName+"/"+name : "/"+parentName+"/"+ name; - Region subRegion = mockRegion(regionName); - cache.allRegions().put(regionName, subRegion); + + assert parentRegionName != null : "The parent Region name was null!"; + + String subRegionName = (parentRegionName.startsWith("/") ? parentRegionName+"/"+name + : "/"+parentRegionName+"/"+ name); + + Region subRegion = mockRegion(subRegionName); + + cache.allRegions().put(subRegionName, subRegion); + return subRegion; - }}); - - + } + }); + when(regionFactory.setCacheLoader(any(CacheLoader.class))).thenAnswer(new Answer(){ @Override public RegionFactory answer(InvocationOnMock invocation) throws Throwable { @@ -116,7 +121,7 @@ public class MockRegionFactory { return regionFactory; } }); - + when(regionFactory.setCacheWriter(any(CacheWriter.class))).thenAnswer(new Answer(){ @Override public RegionFactory answer(InvocationOnMock invocation) throws Throwable { @@ -125,8 +130,8 @@ public class MockRegionFactory { return regionFactory; } }); - - + + when(regionFactory.addAsyncEventQueueId(anyString())).thenAnswer(new Answer(){ @Override public RegionFactory answer(InvocationOnMock invocation) throws Throwable { @@ -135,7 +140,7 @@ public class MockRegionFactory { return regionFactory; } }); - + when(regionFactory.addCacheListener(any(CacheListener.class))).thenAnswer(new Answer(){ @Override public RegionFactory answer(InvocationOnMock invocation) throws Throwable { @@ -144,7 +149,7 @@ public class MockRegionFactory { return regionFactory; } }); - + when(regionFactory.setEvictionAttributes(any(EvictionAttributes.class))).thenAnswer(new Answer(){ @Override public RegionFactory answer(InvocationOnMock invocation) throws Throwable { @@ -153,7 +158,7 @@ public class MockRegionFactory { return regionFactory; } }); - + when(regionFactory.setEntryIdleTimeout(any(ExpirationAttributes.class))).thenAnswer(new Answer(){ @Override public RegionFactory answer(InvocationOnMock invocation) throws Throwable { @@ -171,7 +176,7 @@ public class MockRegionFactory { return regionFactory; } }); - + when(regionFactory.setEntryTimeToLive(any(ExpirationAttributes.class))).thenAnswer(new Answer(){ @Override public RegionFactory answer(InvocationOnMock invocation) throws Throwable { @@ -189,7 +194,7 @@ public class MockRegionFactory { return regionFactory; } }); - + when(regionFactory.setRegionIdleTimeout(any(ExpirationAttributes.class))).thenAnswer(new Answer(){ @Override public RegionFactory answer(InvocationOnMock invocation) throws Throwable { @@ -198,7 +203,7 @@ public class MockRegionFactory { return regionFactory; } }); - + when(regionFactory.setRegionTimeToLive(any(ExpirationAttributes.class))).thenAnswer(new Answer(){ @Override public RegionFactory answer(InvocationOnMock invocation) throws Throwable { @@ -207,7 +212,7 @@ public class MockRegionFactory { return regionFactory; } }); - + when(regionFactory.setScope(any(Scope.class))).thenAnswer(new Answer(){ @Override public RegionFactory answer(InvocationOnMock invocation) throws Throwable { @@ -216,7 +221,7 @@ public class MockRegionFactory { return regionFactory; } }); - + when(regionFactory.setDataPolicy(any(DataPolicy.class))).thenAnswer(new Answer(){ @Override public RegionFactory answer(InvocationOnMock invocation) throws Throwable { @@ -225,7 +230,7 @@ public class MockRegionFactory { return regionFactory; } }); - + when(regionFactory.setEarlyAck(anyBoolean())).thenAnswer(new Answer(){ @Override public RegionFactory answer(InvocationOnMock invocation) throws Throwable { @@ -234,7 +239,7 @@ public class MockRegionFactory { return regionFactory; } }); - + when(regionFactory.setMulticastEnabled(anyBoolean())).thenAnswer(new Answer(){ @Override public RegionFactory answer(InvocationOnMock invocation) throws Throwable { @@ -243,7 +248,7 @@ public class MockRegionFactory { return regionFactory; } }); - + when(regionFactory.setPoolName(anyString())).thenAnswer(new Answer(){ @Override public RegionFactory answer(InvocationOnMock invocation) throws Throwable { @@ -252,7 +257,7 @@ public class MockRegionFactory { return regionFactory; } }); - + when(regionFactory.setEnableGateway(anyBoolean())).thenAnswer(new Answer(){ @Override public RegionFactory answer(InvocationOnMock invocation) throws Throwable { @@ -261,7 +266,7 @@ public class MockRegionFactory { return regionFactory; } }); - + when(regionFactory.setEnableAsyncConflation(anyBoolean())).thenAnswer(new Answer(){ @Override public RegionFactory answer(InvocationOnMock invocation) throws Throwable { @@ -270,7 +275,7 @@ public class MockRegionFactory { return regionFactory; } }); - + when(regionFactory.setEnableSubscriptionConflation(anyBoolean())).thenAnswer(new Answer(){ @Override public RegionFactory answer(InvocationOnMock invocation) throws Throwable { @@ -279,7 +284,7 @@ public class MockRegionFactory { return regionFactory; } }); - + when(regionFactory.setKeyConstraint(any(Class.class))).thenAnswer(new Answer(){ @Override public RegionFactory answer(InvocationOnMock invocation) throws Throwable { @@ -288,7 +293,7 @@ public class MockRegionFactory { return regionFactory; } }); - + when(regionFactory.setValueConstraint(any(Class.class))).thenAnswer(new Answer(){ @Override public RegionFactory answer(InvocationOnMock invocation) throws Throwable { @@ -297,7 +302,7 @@ public class MockRegionFactory { return regionFactory; } }); - + when(regionFactory.setInitialCapacity(anyInt())).thenAnswer(new Answer(){ @Override public RegionFactory answer(InvocationOnMock invocation) throws Throwable { @@ -307,7 +312,7 @@ public class MockRegionFactory { return regionFactory; } }); - + when(regionFactory.setLoadFactor(anyInt())).thenAnswer(new Answer(){ @Override public RegionFactory answer(InvocationOnMock invocation) throws Throwable { @@ -316,7 +321,7 @@ public class MockRegionFactory { return regionFactory; } }); - + when(regionFactory.setConcurrencyLevel(anyInt())).thenAnswer(new Answer(){ @Override public RegionFactory answer(InvocationOnMock invocation) throws Throwable { @@ -325,7 +330,7 @@ public class MockRegionFactory { return regionFactory; } }); - + when(regionFactory.setConcurrencyChecksEnabled(anyBoolean())).thenAnswer(new Answer(){ @Override public RegionFactory answer(InvocationOnMock invocation) throws Throwable { @@ -334,7 +339,7 @@ public class MockRegionFactory { return regionFactory; } }); - + when(regionFactory.setDiskWriteAttributes(any(DiskWriteAttributes.class))).thenAnswer(new Answer(){ @Override public RegionFactory answer(InvocationOnMock invocation) throws Throwable { @@ -343,7 +348,7 @@ public class MockRegionFactory { return regionFactory; } }); - + when(regionFactory.setDiskStoreName(anyString())).thenAnswer(new Answer(){ @Override public RegionFactory answer(InvocationOnMock invocation) throws Throwable { @@ -352,7 +357,7 @@ public class MockRegionFactory { return regionFactory; } }); - + when(regionFactory.setDiskSynchronous(anyBoolean())).thenAnswer(new Answer(){ @Override public RegionFactory answer(InvocationOnMock invocation) throws Throwable { @@ -361,7 +366,7 @@ public class MockRegionFactory { return regionFactory; } }); - + when(regionFactory.setDiskDirs(any(File[].class))).thenAnswer(new Answer(){ @Override public RegionFactory answer(InvocationOnMock invocation) throws Throwable { @@ -370,7 +375,7 @@ public class MockRegionFactory { return regionFactory; } }); - + when(regionFactory.setDiskDirsAndSizes(any(File[].class),any(int[].class))).thenAnswer(new Answer(){ @Override public RegionFactory answer(InvocationOnMock invocation) throws Throwable { @@ -380,7 +385,7 @@ public class MockRegionFactory { return regionFactory; } }); - + when(regionFactory.setPartitionAttributes(any(PartitionAttributes.class))).thenAnswer(new Answer(){ @Override public RegionFactory answer(InvocationOnMock invocation) throws Throwable { @@ -389,7 +394,7 @@ public class MockRegionFactory { return regionFactory; } }); - + when(regionFactory.setMembershipAttributes(any(MembershipAttributes.class))).thenAnswer(new Answer(){ @Override public RegionFactory answer(InvocationOnMock invocation) throws Throwable { @@ -398,7 +403,7 @@ public class MockRegionFactory { return regionFactory; } }); - + when(regionFactory.setIndexMaintenanceSynchronous(anyBoolean())).thenAnswer(new Answer(){ @Override public RegionFactory answer(InvocationOnMock invocation) throws Throwable { @@ -407,7 +412,7 @@ public class MockRegionFactory { return regionFactory; } }); - + when(regionFactory.setStatisticsEnabled(anyBoolean())).thenAnswer(new Answer(){ @Override public RegionFactory answer(InvocationOnMock invocation) throws Throwable { @@ -416,7 +421,7 @@ public class MockRegionFactory { return regionFactory; } }); - + when(regionFactory.setIgnoreJTA(anyBoolean())).thenAnswer(new Answer(){ @Override public RegionFactory answer(InvocationOnMock invocation) throws Throwable { @@ -425,7 +430,7 @@ public class MockRegionFactory { return regionFactory; } }); - + when(regionFactory.setLockGrantor(anyBoolean())).thenAnswer(new Answer(){ @Override public RegionFactory answer(InvocationOnMock invocation) throws Throwable { @@ -435,7 +440,7 @@ public class MockRegionFactory { return regionFactory; } }); - + when(regionFactory.setSubscriptionAttributes(any(SubscriptionAttributes.class))).thenAnswer(new Answer(){ @Override public RegionFactory answer(InvocationOnMock invocation) throws Throwable { @@ -444,7 +449,7 @@ public class MockRegionFactory { return regionFactory; } }); - + when(regionFactory.setGatewayHubId(anyString())).thenAnswer(new Answer(){ @Override public RegionFactory answer(InvocationOnMock invocation) throws Throwable { @@ -453,7 +458,7 @@ public class MockRegionFactory { return regionFactory; } }); - + when(regionFactory.setCloningEnabled(anyBoolean())).thenAnswer(new Answer(){ @Override public RegionFactory answer(InvocationOnMock invocation) throws Throwable { @@ -462,7 +467,7 @@ public class MockRegionFactory { return regionFactory; } }); - + when(regionFactory.addGatewaySenderId(anyString())).thenAnswer(new Answer(){ @Override public RegionFactory answer(InvocationOnMock invocation) throws Throwable { @@ -471,7 +476,7 @@ public class MockRegionFactory { return regionFactory; } }); - + when(regionFactory.addAsyncEventQueueId(anyString())).thenAnswer(new Answer(){ @Override public RegionFactory answer(InvocationOnMock invocation) throws Throwable { @@ -480,82 +485,80 @@ public class MockRegionFactory { return regionFactory; } }); - - + + return regionFactory; } - - @SuppressWarnings("rawtypes") + + @SuppressWarnings("rawtypes") RegionFactory createRegionFactory() { return createMockRegionFactory(); } - + @SuppressWarnings({ "unchecked", "rawtypes" }) public Region mockRegion(String name) { RegionService regionService = mockRegionService(); Region region = mock(Region.class); - when(region.getRegionService()).thenReturn(regionService); - - when(region.getAttributes()).thenAnswer(new Answer() { + when(region.getRegionService()).thenReturn(regionService); + + when(region.getAttributes()).thenAnswer(new Answer() { @Override public RegionAttributes answer(InvocationOnMock invocation) throws Throwable { - RegionAttributes attributes = attributesFactory.create(); - return attributes; } - }); - when(region.getName()).thenReturn(name); - - when(region.getSubregion(anyString())).thenAnswer(new Answer() { + when(region.getFullPath()).thenReturn(name); + when(region.getName()).thenReturn(name); + + when(region.getSubregion(anyString())).thenAnswer(new Answer() { + @Override + public Region answer(InvocationOnMock invocation) throws Throwable { + Region parent = (Region) invocation.getMock(); + + String parentRegionName = parent.getName(); + String subRegionName = (String) invocation.getArguments()[0]; + String subRegionPath = (parentRegionName.startsWith("/") ? parentRegionName+"/"+subRegionName + : "/"+parentRegionName+"/"+subRegionName); + + Region region = cache.getRegion(subRegionPath); + + return region; + } + }); + + when(region.createSubregion(anyString(), any(RegionAttributes.class))).thenAnswer(new Answer() { @Override public Region answer(InvocationOnMock invocation) throws Throwable { String name = (String) invocation.getArguments()[0]; - Region parent = (Region)invocation.getMock(); - String parentName = parent.getName(); - String regionName = parentName.startsWith("/") ? parentName+"/"+ name : - "/"+parentName+"/"+ name; + RegionAttributes attributes = (RegionAttributes) invocation.getArguments()[1]; - Region region = cache.getRegion(regionName); - - return region; - } - - }); - - when(region.createSubregion(anyString(),any(RegionAttributes.class))).thenAnswer(new Answer() { - - @Override - public Region answer(InvocationOnMock invocation) throws Throwable { - String name = (String)invocation.getArguments()[0]; - RegionAttributes attributes = (RegionAttributes)invocation.getArguments()[1]; - - Region parent = (Region)invocation.getMock(); + Region parent = (Region) invocation.getMock(); String parentName = parent.getName(); String regionName = parentName.startsWith("/") ? parentName+"/"+name : "/"+parentName+"/"+ name; - + Region subRegion = new MockRegionFactory(cache).createMockRegionFactory(attributes).create(regionName); when(subRegion.getFullPath()).thenReturn(regionName); - + cache.allRegions().put(regionName, subRegion); + return subRegion; - }}); - + } + }); + return region; } - + public static RegionService mockRegionService() { - when(regionService.getQueryService()).thenReturn(queryService); return regionService; } - + public static QueryService mockQueryService() { return queryService; } - - -} \ No newline at end of file + + +} diff --git a/src/test/resources/org/springframework/data/gemfire/complex-subregion.xml b/src/test/resources/org/springframework/data/gemfire/complex-subregion.xml new file mode 100644 index 00000000..22b6810c --- /dev/null +++ b/src/test/resources/org/springframework/data/gemfire/complex-subregion.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/resources/org/springframework/data/gemfire/config/client-region-using-datapolicy-and-shortcut.xml b/src/test/resources/org/springframework/data/gemfire/config/client-region-using-datapolicy-and-shortcut.xml index 589ef054..88a448a2 100644 --- a/src/test/resources/org/springframework/data/gemfire/config/client-region-using-datapolicy-and-shortcut.xml +++ b/src/test/resources/org/springframework/data/gemfire/config/client-region-using-datapolicy-and-shortcut.xml @@ -7,6 +7,8 @@ http://www.springframework.org/schema/gemfire http://www.springframework.org/schema/gemfire/spring-gemfire.xsd "> + + diff --git a/src/test/resources/org/springframework/data/gemfire/config/subregion-ns.xml b/src/test/resources/org/springframework/data/gemfire/config/subregion-ns.xml index 96e4d9a5..ef750f40 100644 --- a/src/test/resources/org/springframework/data/gemfire/config/subregion-ns.xml +++ b/src/test/resources/org/springframework/data/gemfire/config/subregion-ns.xml @@ -1,13 +1,13 @@ - + http://www.springframework.org/schema/gemfire http://www.springframework.org/schema/gemfire/spring-gemfire.xsd +"> + + @@ -15,36 +15,35 @@ - - + - + - + - - - - - - - - - - - - + + + + + + + + + + + + - + - \ No newline at end of file + diff --git a/src/test/resources/org/springframework/data/gemfire/config/subregion-with-inconsistent-datapolicy-persistent-settings.xml b/src/test/resources/org/springframework/data/gemfire/config/subregion-with-inconsistent-datapolicy-persistent-settings.xml new file mode 100644 index 00000000..5217e35e --- /dev/null +++ b/src/test/resources/org/springframework/data/gemfire/config/subregion-with-inconsistent-datapolicy-persistent-settings.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + diff --git a/src/test/resources/org/springframework/data/gemfire/config/subregion-with-invalid-datapolicy.xml b/src/test/resources/org/springframework/data/gemfire/config/subregion-with-invalid-datapolicy.xml new file mode 100644 index 00000000..d3377812 --- /dev/null +++ b/src/test/resources/org/springframework/data/gemfire/config/subregion-with-invalid-datapolicy.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + +