Initial implementation and tests for JIRA feature requests SGF-207 and SGF-254 supporting inheritable Region templates when defining GemFire Regions using Spring Data GemFire XML configuration meta-data. This feature allows common Region configuration and attribute values to be defined once and then shared across multiple Region bean definitions in the Spring context for added convenience.

This commit is contained in:
John Blum
2014-08-19 11:41:51 -07:00
committed by John Blum
parent 4121581dea
commit 5d27c19ef5
6 changed files with 721 additions and 274 deletions

View File

@@ -49,9 +49,20 @@ abstract class AbstractRegionParser extends AbstractSingleBeanDefinitionParser {
return getRegionFactoryClass();
}
@Override
protected String getParentName(final Element element) {
String regionTemplate = element.getAttribute("template");
return (StringUtils.hasText(regionTemplate) ? regionTemplate : super.getParentName(element));
}
protected abstract Class<?> getRegionFactoryClass();
protected boolean isSubRegion(Element element) {
protected boolean isRegionTemplate(final Element element) {
String localName = element.getLocalName();
return (localName != null && localName.endsWith("-template"));
}
protected boolean isSubRegion(final Element element) {
String localName = element.getParentNode().getLocalName();
return (localName != null && localName.endsWith("region"));
}
@@ -59,6 +70,7 @@ abstract class AbstractRegionParser extends AbstractSingleBeanDefinitionParser {
@Override
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
super.doParse(element, builder);
builder.setAbstract(isRegionTemplate(element));
boolean subRegion = isSubRegion(element);
doParseRegion(element, parserContext, builder, subRegion);
}

View File

@@ -52,10 +52,15 @@ class GemfireNamespaceHandler extends NamespaceHandlerSupport {
registerBeanDefinitionParser("cache-server", new CacheServerParser());
registerBeanDefinitionParser("client-cache", new ClientCacheParser());
registerBeanDefinitionParser("client-region", new ClientRegionParser());
registerBeanDefinitionParser("client-region-template", new ClientRegionParser());
registerBeanDefinitionParser("lookup-region", new LookupRegionParser());
registerBeanDefinitionParser("region-template", new TemplateRegionParser());
registerBeanDefinitionParser("local-region", new LocalRegionParser());
registerBeanDefinitionParser("local-region-template", new LocalRegionParser());
registerBeanDefinitionParser("partitioned-region", new PartitionedRegionParser());
registerBeanDefinitionParser("partitioned-region-template", new PartitionedRegionParser());
registerBeanDefinitionParser("replicated-region", new ReplicatedRegionParser());
registerBeanDefinitionParser("replicated-region-template", new ReplicatedRegionParser());
registerBeanDefinitionParser("async-event-queue", new AsyncEventQueueParser());
registerBeanDefinitionParser("disk-store", new DiskStoreParser());
registerBeanDefinitionParser("gateway-hub", new GatewayHubParser());

View File

@@ -0,0 +1,53 @@
/*
* 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 org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.data.gemfire.RegionAttributesFactoryBean;
import org.springframework.data.gemfire.RegionFactoryBean;
import org.w3c.dom.Element;
/**
* The TemplateRegionParser class is a generic Region parser used to parse Region Template bean definitions in the
* Spring context configuration meta-data to encapsulate common Region 'attribute' configuration irrespective of the
* Region's Data Policy (e.g. REPLICATE, PARTITION).
*
* @author John Blum
* @see org.springframework.data.gemfire.RegionFactoryBean
* @see org.springframework.data.gemfire.config.AbstractRegionParser
* @since 1.5.0
*/
class TemplateRegionParser extends AbstractRegionParser {
@Override
protected Class<?> getRegionFactoryClass() {
return RegionFactoryBean.class;
}
@Override
protected void doParseRegion(Element element, ParserContext parserContext, BeanDefinitionBuilder builder,
boolean subRegion) {
BeanDefinitionBuilder regionAttributesBuilder = BeanDefinitionBuilder.genericBeanDefinition(
RegionAttributesFactoryBean.class);
doParseCommonRegionConfiguration(element, parserContext, builder, regionAttributesBuilder, subRegion);
builder.addPropertyValue("attributes", regionAttributesBuilder.getBeanDefinition());
}
}

View File

@@ -319,8 +319,7 @@ that have already been processed by the clients.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="search-timeout" type="xsd:string"
use="optional" default="300">
<xsd:attribute name="search-timeout" type="xsd:string" use="optional" default="300">
<xsd:annotation>
<xsd:documentation><![CDATA[
How many seconds a netSearch operation can wait for data before timing out.
@@ -458,6 +457,41 @@ Defines a lookup Subregion
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
<!-- -->
<xsd:complexType name="lookupRegionType">
<xsd:complexContent>
<xsd:extension base="baseLookupRegionType">
<xsd:attributeGroup ref="topLevelRegionAttributes" />
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
<!-- -->
<xsd:complexType name="lookupSubRegionType">
<xsd:complexContent>
<xsd:extension base="baseLookupRegionType">
<xsd:attribute name="name" type="xsd:string" use="required">
<xsd:annotation>
<xsd:documentation><![CDATA[
The name of the region definition.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
<!-- -->
<xsd:element name="lookup-region" type="lookupRegionType"/>
<!-- -->
<xsd:complexType name="basicRegionType">
<xsd:annotation>
<xsd:appinfo>
<tool:annotation>
<tool:exports type="com.gemstone.gemfire.cache.Region" />
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
</xsd:complexType>
<!-- -->
<xsd:complexType name="basicSubRegionType">
<xsd:complexContent>
<xsd:extension base="baseLookupRegionType">
@@ -470,15 +504,6 @@ The name of the region definition.]]></xsd:documentation>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
<xsd:complexType name="basicRegionType">
<xsd:annotation>
<xsd:appinfo>
<tool:annotation>
<tool:exports type="com.gemstone.gemfire.cache.Region" />
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
</xsd:complexType>
<!-- -->
<xsd:complexType name="baseReadOnlyRegionType" abstract="true">
<xsd:complexContent>
@@ -598,6 +623,62 @@ CustomExpiry Time to idle (or idle timeout) configuration for the region entries
</xsd:element>
</xsd:choice>
</xsd:sequence>
<xsd:attribute name="cloning-enabled" type="xsd:string" default="true">
<xsd:annotation>
<xsd:documentation><![CDATA[[
Determines how fromDelta applies deltas to the local cache for delta propagation. When true, the updates are applied to a
clone of the value and then the clone is saved to the cache. When false, the value is modified in place in the cache.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="close" type="xsd:string" default="false">
<xsd:annotation>
<xsd:documentation><![CDATA[
Indicates whether the defined region should be closed or not at shutdown. Close performs a local destroy but leaves behind the region
disk files. Additionally it notifies the listeners and callbacks.
Default is false
Note: Regions are automatically closed when cache closes.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="concurrency-checks-enabled" type="xsd:string" default="true">
<xsd:annotation>
<xsd:documentation><![CDATA[[
Indicates whether concurrency checks (versioning) are enabled for the region
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="destroy" type="xsd:string" default="false">
<xsd:annotation>
<xsd:documentation><![CDATA[
Indicates whether the defined region should be destroyed or not at shutdown. Destroy cascades to all entries and subregions.
After the destroy, this region object can not be used any more and any attempt to use this region object will get
RegionDestroyedException.
Default is false, meaning that regions are not destroyed.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="disk-store-ref" type="xsd:string">
<xsd:annotation>
<xsd:documentation><![CDATA[
Indicates the id of the disk store to use for persistence or overflow.
Note this attribute only applies if a disk store is configured for this region.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="disk-synchronous" type="xsd:string" default="false">
<xsd:annotation>
<xsd:documentation><![CDATA[
Indicates whether the writing to the disk is synchronous or not. Default is false, meaning asynchronous writing.
Note this attribute only applies if a disk store is configured for this region.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="ignore-if-exists" type="xsd:string" default="false">
<xsd:annotation>
<xsd:documentation><![CDATA[
@@ -621,6 +702,37 @@ for the "same" Region (by name), then this can cause confusion or have unexpecte
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="ignore-jta" type="xsd:string" use="optional" default="false">
<xsd:annotation>
<xsd:documentation><![CDATA[
Indicates whether operations on this region participates in active JTA transactions or ignores them and operates outside of transactions.
This is primarily used in cache loaders, writers, and listeners that need to perform non-transactional operations on a region,
such as caching a result set.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="initial-capacity" type="xsd:string" use="optional" default="16">
<xsd:annotation>
<xsd:documentation><![CDATA[
Sets the initial capacity (number of entries) for the region
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="key-constraint" type="xsd:string" use="optional">
<xsd:annotation>
<xsd:documentation><![CDATA[
The fully qualified class name of the expected key type
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="load-factor" type="xsd:string" default="0.75">
<xsd:annotation>
<xsd:documentation><![CDATA[[
Together with the initial-capacity region attribute, sets the initial parameters on the underlying java.util.ConcurrentHashMap
used for storing region entries. This must be a floating point number between 0 and 1, inclusive.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="persistent" type="xsd:string">
<xsd:annotation>
<xsd:documentation><![CDATA[
@@ -635,77 +747,7 @@ Note: Persistence for partitioned regions is supported only from GemFire 6.5 onw
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="disk-synchronous" type="xsd:string"
default="false">
<xsd:annotation>
<xsd:documentation><![CDATA[
Indicates whether the writing to the disk is synchronous or not. Default is false, meaning asynchronous writing.
Note this attribute only applies if a disk store is configured for this region.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="disk-store-ref" type="xsd:string">
<xsd:annotation>
<xsd:documentation><![CDATA[
Indicates the id of the disk store to use for persistence or overflow.
Note this attribute only applies if a disk store is configured for this region.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="load-factor" type="xsd:string"
default="0.75">
<xsd:annotation>
<xsd:documentation><![CDATA[[
Together with the initial-capacity region attribute, sets the initial parameters on the underlying java.util.ConcurrentHashMap
used for storing region entries. This must be a floating point number between 0 and 1, inclusive.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="cloning-enabled" type="xsd:string"
default="true">
<xsd:annotation>
<xsd:documentation><![CDATA[[
Determines how fromDelta applies deltas to the local cache for delta propagation. When true, the updates are applied to a
clone of the value and then the clone is saved to the cache. When false, the value is modified in place in the cache.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="concurrency-checks-enabled" type="xsd:string"
default="true">
<xsd:annotation>
<xsd:documentation><![CDATA[[
Indicates whether concurrency checks (versioning) are enabled for the region
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="destroy" type="xsd:string"
default="false">
<xsd:annotation>
<xsd:documentation><![CDATA[
Indicates whether the defined region should be destroyed or not at shutdown. Destroy cascades to all entries and subregions.
After the destroy, this region object can not be used any more and any attempt to use this region object will get
RegionDestroyedException.
Default is false, meaning that regions are not destroyed.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="close" type="xsd:string" default="false">
<xsd:annotation>
<xsd:documentation><![CDATA[
Indicates whether the defined region should be closed or not at shutdown. Close performs a local destroy but leaves behind the region
disk files. Additionally it notifies the listeners and callbacks.
Default is false
Note: Regions are automatically closed when cache closes.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="statistics" type="xsd:string"
default="false">
<xsd:attribute name="statistics" type="xsd:string" default="false">
<xsd:annotation>
<xsd:documentation><![CDATA[
Indicates whether statistics are enabled or disabled for this region and its entries.
@@ -713,12 +755,11 @@ Default is false, meaning statistics are disabled.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="key-constraint" type="xsd:string"
use="optional">
<xsd:attribute name="template" type="xsd:string" use="optional">
<xsd:annotation>
<xsd:documentation><![CDATA[
The fully qualified class name of the expected key type
]]></xsd:documentation>
<xsd:documentation>
Specifies the parent, template Region from which to inherit the Region attribute configuration.
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="value-constraint" type="xsd:string"
@@ -729,24 +770,6 @@ The fully qualified class name of the expected value type
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="ignore-jta" type="xsd:string"
use="optional" default="false">
<xsd:annotation>
<xsd:documentation><![CDATA[
Indicates whether operations on this region participates in active JTA transactions or ignores them and operates outside of transactions.
This is primarily used in cache loaders, writers, and listeners that need to perform non-transactional operations on a region,
such as caching a result set.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="initial-capacity" type="xsd:string"
use="optional" default="16">
<xsd:annotation>
<xsd:documentation><![CDATA[
Sets the initial capacity (number of entries) for the region
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
@@ -773,7 +796,7 @@ The name of the region definition.]]>
</xsd:complexContent>
</xsd:complexType>
<!-- -->
<xsd:complexType name="baseRegionType">
<xsd:complexType name="baseRegionType" abstract="true">
<xsd:complexContent>
<xsd:extension base="baseReadOnlyRegionType">
<xsd:sequence minOccurs="0" maxOccurs="1">
@@ -870,35 +893,33 @@ use inner bean declarations.
</xsd:element>
</xsd:choice>
</xsd:sequence>
<xsd:attribute name="index-update-type" use="optional"
default="synchronous">
<xsd:attribute name="enable-gateway" type="xsd:string" use="optional">
<xsd:annotation>
<xsd:documentation><![CDATA[
Specifies whether region indexes are maintained synchronously with region modifications, or asynchronously in a background thread.
]]></xsd:documentation>
</xsd:annotation>
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:enumeration value="asynchronous" />
<xsd:enumeration value="synchronous" />
</xsd:restriction>
</xsd:simpleType>
</xsd:attribute>
<xsd:attribute name="enable-gateway" type="xsd:string"
use="optional">
<xsd:annotation>
<xsd:documentation><![CDATA[
Specifies if WAN gateway communications are enabled for this region (true or false) (Deprecated since Gemfire v 7.0)
Specifies if WAN Gateway communications are enabled for this Region (true or false) (Deprecated since Gemfire v 7.0)
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="hub-id" type="xsd:string" use="optional">
<xsd:annotation>
<xsd:documentation><![CDATA[
Specifies if WAN gateway hub id if enable-gateway is true. (Deprecated since Gemfire v 7.0)
Specifies if WAN Gateway hub id if enable-gateway is true. (Deprecated since Gemfire v 7.0)
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="index-update-type" use="optional" default="synchronous">
<xsd:annotation>
<xsd:documentation><![CDATA[
Specifies whether Region indexes are maintained synchronously with region modifications, or asynchronously in a background thread.
]]></xsd:documentation>
</xsd:annotation>
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:enumeration value="asynchronous"/>
<xsd:enumeration value="synchronous"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:attribute>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
@@ -910,6 +931,7 @@ use inner bean declarations.
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
<!-- -->
<xsd:complexType name="subRegionType">
<xsd:complexContent>
<xsd:extension base="baseRegionType">
@@ -924,27 +946,18 @@ use inner bean declarations.
</xsd:complexContent>
</xsd:complexType>
<!-- -->
<xsd:complexType name="lookupRegionType">
<xsd:complexContent>
<xsd:extension base="baseLookupRegionType">
<xsd:attributeGroup ref="topLevelRegionAttributes" />
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
<!-- -->
<xsd:complexType name="lookupSubRegionType">
<xsd:complexContent>
<xsd:extension base="baseLookupRegionType">
<xsd:attribute name="name" type="xsd:string" use="required">
<xsd:annotation>
<xsd:documentation><![CDATA[
The name of the region definition.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
<xsd:element name="region-template" type="regionType">
<xsd:annotation>
<xsd:documentation source="org.springframework.data.gemfire.RegionFactoryBean"><![CDATA[
Defines a template for creating multiple GemFire Regions that all share a common attribute configuration.
]]></xsd:documentation>
<xsd:appinfo>
<tool:annotation>
<tool:exports type="com.gemstone.gemfire.cache.Region"/>
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
</xsd:element>
<!-- -->
<xsd:group name="subRegionGroup">
<xsd:choice>
@@ -964,8 +977,7 @@ The id of the region bean definition.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="cache-ref" type="xsd:string" use="optional"
default="gemfireCache">
<xsd:attribute name="cache-ref" type="xsd:string" use="optional" default="gemfireCache">
<xsd:annotation>
<xsd:documentation><![CDATA[
The name of the bean defining the GemFire cache (by default 'gemfireCache').
@@ -983,16 +995,7 @@ Required for subregions.
</xsd:attributeGroup>
<!-- -->
<xsd:attributeGroup name="distributedRegionAttributes">
<xsd:attribute name="enable-subscription-conflation"
type="xsd:string" default="false">
<xsd:annotation>
<xsd:documentation><![CDATA[
Indicates whether the region can conflate its messages to the client.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="enable-async-conflation" type="xsd:string"
default="false">
<xsd:attribute name="enable-async-conflation" type="xsd:string" default="false">
<xsd:annotation>
<xsd:documentation><![CDATA[
For TCP/IP distributions between peers, specifies whether to allow aggregation of asynchronous messages sent by the producer member for the region.
@@ -1000,6 +1003,13 @@ Indicates whether the region can conflate its messages to the client.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="enable-subscription-conflation" type="xsd:string" default="false">
<xsd:annotation>
<xsd:documentation><![CDATA[
Indicates whether the region can conflate its messages to the client.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="multicast-enabled" type="xsd:string">
<xsd:annotation>
<xsd:documentation><![CDATA[
@@ -1010,15 +1020,12 @@ distributed system with the mcast-port gemfire.properties setting.
</xsd:attribute>
</xsd:attributeGroup>
<!-- -->
<xsd:element name="lookup-region" type="lookupRegionType" />
<!-- -->
<xsd:complexType name="baseReplicatedRegionType">
<xsd:complexType name="baseReplicatedRegionType" abstract="true">
<xsd:annotation>
<xsd:documentation
source="org.springframework.data.gemfire.RegionFactoryBean"><![CDATA[
Defines a GemFire replicated region instance. Each replicated region contains a complete copy of the data.
As well as high availability, replication provides excellent performance as each region contains a complete,
up to date copy of the data.
<xsd:documentation source="org.springframework.data.gemfire.RegionFactoryBean"><![CDATA[
Defines a GemFire Replicated Region instance. Each Replicated Region contains a complete copy of the data.
As well as high availability, replication provides excellent performance as each Region contains a complete,
up-to-date copy of the data.
]]></xsd:documentation>
<xsd:appinfo>
<tool:annotation>
@@ -1145,119 +1152,28 @@ The name of the region definition.
</xsd:complexContent>
</xsd:complexType>
<!-- -->
<xsd:element name="replicated-region" type="replicatedRegionType"/>
<!-- -->
<xsd:complexType name="baseLocalRegionType">
<xsd:element name="replicated-region-template" type="replicatedRegionType">
<xsd:annotation>
<xsd:documentation
source="org.springframework.data.gemfire.ReplicatedRegionFactoryBean"><![CDATA[
Defines a GemFire local region instance. Each local region is scoped only to the local JVM.
]]></xsd:documentation>
<xsd:documentation source="org.springframework.data.gemfire.ReplicatedRegionFactoryBean"><![CDATA[
Defines a template for creating multiple GemFire REPLICATE Regions that all share a common attribute configuration.
]]></xsd:documentation>
<xsd:appinfo>
<tool:annotation>
<tool:exports type="com.gemstone.gemfire.cache.Region" />
<tool:exports type="com.gemstone.gemfire.cache.Region"/>
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
<xsd:complexContent>
<xsd:extension base="baseRegionType">
<xsd:sequence minOccurs="1" maxOccurs="1">
<xsd:element name="eviction" minOccurs="0" maxOccurs="1">
<xsd:annotation>
<xsd:documentation><![CDATA[
Eviction policy for the replicated region.
]]></xsd:documentation>
</xsd:annotation>
<xsd:complexType>
<xsd:complexContent>
<xsd:extension base="evictionType">
<xsd:attribute name="action" type="evictionActionType">
<xsd:annotation>
<xsd:documentation><![CDATA[
The action to take when performing eviction.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
</xsd:element>
<xsd:group ref="subRegionGroup" minOccurs="0" maxOccurs="unbounded" />
</xsd:sequence>
<xsd:attribute name="concurrency-level">
<xsd:annotation>
<xsd:documentation><![CDATA[
Provides an estimate of the maximum number of application threads that will concurrently access a region entry at one time.
This attribute does not apply to partitioned regions. This attribute helps GemFire optimize the use of system resources and
reduce thread contention. This sets an initial parameter on the underlying java.util.ConcurrentHashMap used for storing region entries.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="data-policy" use="optional">
<xsd:annotation>
<xsd:documentation><![CDATA[
Specifies the data policy for this region (NORMAL or PRELOADED). Setting 'data-policy' is not stictly necessary,
but if set, then the value must agree with the 'persistent' attribute if also specified.
]]></xsd:documentation>
</xsd:annotation>
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:enumeration value="NORMAL"/>
<xsd:enumeration value="PRELOADED"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:attribute>
<xsd:attribute name="shortcut" use="optional">
<xsd:annotation>
<xsd:documentation><![CDATA[
The RegionShortcut for this region. Allows easy initialization of the region based on pre-defined defaults.
]]></xsd:documentation>
</xsd:annotation>
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:enumeration value="LOCAL"/>
<xsd:enumeration value="LOCAL_PERSISTENT"/>
<xsd:enumeration value="LOCAL_HEAP_LRU"/>
<xsd:enumeration value="LOCAL_OVERFLOW"/>
<xsd:enumeration value="LOCAL_PERSISTENT_OVERFLOW"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:attribute>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
</xsd:element>
<!-- -->
<xsd:complexType name="localRegionType">
<xsd:complexContent>
<xsd:extension base="baseLocalRegionType">
<xsd:attributeGroup ref="topLevelRegionAttributes" />
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
<xsd:element name="replicated-region" type="replicatedRegionType"/>
<!-- -->
<xsd:complexType name="localSubRegionType">
<xsd:complexContent>
<xsd:extension base="baseLocalRegionType">
<xsd:attribute name="name" type="xsd:string" use="required">
<xsd:annotation>
<xsd:documentation><![CDATA[
The name of the region definition.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
<!-- -->
<xsd:element name="local-region" type="localRegionType"/>
<!-- -->
<xsd:complexType name="basePartitionedRegionType">
<xsd:complexType name="basePartitionedRegionType" abstract="true">
<xsd:annotation>
<xsd:documentation
source="org.springframework.data.gemfire.RegionFactoryBean"><![CDATA[
Defines a GemFire partitioned region instance. Through partitioning, the data is split across regions.
Defines a GemFire Partitioned Region instance. Through partitioning, the data is split across Regions.
Partitioning is useful when the amount of data to store is too large for one member to hold and work
with as if it were a single entity. One can configure the partitioned region to store redundant copies
with as if it were a single entity. One can configure the Partitioned Region to store redundant copies
in different members, for high availability in case of an application failure.
]]></xsd:documentation>
<xsd:appinfo>
@@ -1515,8 +1431,138 @@ The name of the region definition.
</xsd:complexContent>
</xsd:complexType>
<!-- -->
<xsd:element name="partitioned-region-template" type="partitionedRegionType">
<xsd:annotation>
<xsd:documentation source="org.springframework.data.gemfire.PartitionedRegionFactoryBean"><![CDATA[
Defines a template for creating multiple GemFire PARTITION Regions that all share a common attribute configuration.
]]></xsd:documentation>
<xsd:appinfo>
<tool:annotation>
<tool:exports type="com.gemstone.gemfire.cache.Region"/>
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
</xsd:element>
<!-- -->
<xsd:element name="partitioned-region" type="partitionedRegionType"/>
<!-- -->
<xsd:complexType name="baseLocalRegionType" abstract="true">
<xsd:annotation>
<xsd:documentation
source="org.springframework.data.gemfire.ReplicatedRegionFactoryBean"><![CDATA[
Defines a GemFire Local Region instance. Each Local Region is scoped only to the local JVM.
]]></xsd:documentation>
<xsd:appinfo>
<tool:annotation>
<tool:exports type="com.gemstone.gemfire.cache.Region"/>
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
<xsd:complexContent>
<xsd:extension base="baseRegionType">
<xsd:sequence minOccurs="1" maxOccurs="1">
<xsd:element name="eviction" minOccurs="0" maxOccurs="1">
<xsd:annotation>
<xsd:documentation><![CDATA[
Eviction policy for the replicated region.
]]></xsd:documentation>
</xsd:annotation>
<xsd:complexType>
<xsd:complexContent>
<xsd:extension base="evictionType">
<xsd:attribute name="action" type="evictionActionType">
<xsd:annotation>
<xsd:documentation><![CDATA[
The action to take when performing eviction.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
</xsd:element>
<xsd:group ref="subRegionGroup" minOccurs="0" maxOccurs="unbounded" />
</xsd:sequence>
<xsd:attribute name="concurrency-level">
<xsd:annotation>
<xsd:documentation><![CDATA[
Provides an estimate of the maximum number of application threads that will concurrently access a region entry at one time.
This attribute does not apply to partitioned regions. This attribute helps GemFire optimize the use of system resources and
reduce thread contention. This sets an initial parameter on the underlying java.util.ConcurrentHashMap used for storing region entries.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="data-policy" use="optional">
<xsd:annotation>
<xsd:documentation><![CDATA[
Specifies the data policy for this region (NORMAL or PRELOADED). Setting 'data-policy' is not stictly necessary,
but if set, then the value must agree with the 'persistent' attribute if also specified.
]]></xsd:documentation>
</xsd:annotation>
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:enumeration value="NORMAL"/>
<xsd:enumeration value="PRELOADED"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:attribute>
<xsd:attribute name="shortcut" use="optional">
<xsd:annotation>
<xsd:documentation><![CDATA[
The RegionShortcut for this region. Allows easy initialization of the region based on pre-defined defaults.
]]></xsd:documentation>
</xsd:annotation>
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:enumeration value="LOCAL"/>
<xsd:enumeration value="LOCAL_PERSISTENT"/>
<xsd:enumeration value="LOCAL_HEAP_LRU"/>
<xsd:enumeration value="LOCAL_OVERFLOW"/>
<xsd:enumeration value="LOCAL_PERSISTENT_OVERFLOW"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:attribute>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
<!-- -->
<xsd:complexType name="localRegionType">
<xsd:complexContent>
<xsd:extension base="baseLocalRegionType">
<xsd:attributeGroup ref="topLevelRegionAttributes" />
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
<!-- -->
<xsd:complexType name="localSubRegionType">
<xsd:complexContent>
<xsd:extension base="baseLocalRegionType">
<xsd:attribute name="name" type="xsd:string" use="required">
<xsd:annotation>
<xsd:documentation><![CDATA[
The name of the region definition.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
<!-- -->
<xsd:element name="local-region-template" type="localRegionType">
<xsd:annotation>
<xsd:documentation source="org.springframework.data.gemfire.LocalRegionFactoryBean"><![CDATA[
Defines a template for creating multiple GemFire Local Regions that all share a common attribute configuration.
]]></xsd:documentation>
<xsd:appinfo>
<tool:annotation>
<tool:exports type="com.gemstone.gemfire.cache.Region"/>
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
</xsd:element>
<!-- -->
<xsd:element name="local-region" type="localRegionType"/>
<!-- -->
<xsd:complexType name="expirationType">
<xsd:attribute name="timeout" type="xsd:string" default="0">
<xsd:annotation>
@@ -1797,7 +1843,7 @@ The name of the bean defining the GemFire cache (by default 'gemfireCache').
<!-- -->
<xsd:element name="disk-store" type="diskStoreType" />
<!-- -->
<xsd:complexType name="baseClientRegionType">
<xsd:complexType name="baseClientRegionType" abstract="true">
<xsd:annotation>
<xsd:documentation
source="org.springframework.data.gemfire.client.ClientRegionFactoryBean"><![CDATA[
@@ -1989,6 +2035,19 @@ The name of the region definition.
</xsd:complexContent>
</xsd:complexType>
<!-- -->
<xsd:element name="client-region-template" type="clientRegionType">
<xsd:annotation>
<xsd:documentation source="org.springframework.data.gemfire.ClientRegionFactoryBean"><![CDATA[
Defines a template for creating multiple GemFire Client Regions that all share a common attribute configuration.
]]></xsd:documentation>
<xsd:appinfo>
<tool:annotation>
<tool:exports type="com.gemstone.gemfire.cache.Region"/>
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
</xsd:element>
<!-- -->
<xsd:element name="client-region" type="clientRegionType"/>
<!-- -->
<xsd:complexType name="connectionType">
@@ -3105,10 +3164,8 @@ Deprecated as of Gemfire 7
</xsd:annotation>
<xsd:sequence>
<xsd:choice>
<xsd:element name="gateway-endpoint" minOccurs="1"
maxOccurs="unbounded" type="gatewayEndpointType" />
<xsd:element name="gateway-listener" minOccurs="1"
maxOccurs="1">
<xsd:element name="gateway-endpoint" minOccurs="1" maxOccurs="unbounded" type="gatewayEndpointType"/>
<xsd:element name="gateway-listener" minOccurs="1" maxOccurs="1">
<xsd:annotation>
<xsd:documentation
source="com.gemstone.gemfire.cache.util.GatewayEventListener"><![CDATA[
@@ -3116,8 +3173,7 @@ An gateway event listener definition for the gateway
]]></xsd:documentation>
<xsd:appinfo>
<tool:annotation>
<tool:exports
type="com.gemstone.gemfire.cache.util.GatewayEventListener" />
<tool:exports type="com.gemstone.gemfire.cache.util.GatewayEventListener"/>
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>

View File

@@ -0,0 +1,229 @@
/*
* 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.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.util.List;
import javax.annotation.Resource;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanIsAbstractException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.data.gemfire.test.GemfireTestApplicationContextInitializer;
import org.springframework.data.gemfire.test.support.CollectionUtils;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.util.ObjectUtils;
import com.gemstone.gemfire.cache.CacheLoader;
import com.gemstone.gemfire.cache.CacheLoaderException;
import com.gemstone.gemfire.cache.EntryOperation;
import com.gemstone.gemfire.cache.LoaderHelper;
import com.gemstone.gemfire.cache.PartitionResolver;
import com.gemstone.gemfire.cache.Region;
import com.gemstone.gemfire.cache.RegionAttributes;
import com.gemstone.gemfire.cache.asyncqueue.AsyncEvent;
import com.gemstone.gemfire.cache.asyncqueue.AsyncEventListener;
import com.gemstone.gemfire.cache.partition.PartitionListenerAdapter;
import com.gemstone.gemfire.cache.util.CacheListenerAdapter;
import com.gemstone.gemfire.cache.util.CacheWriterAdapter;
/**
* The TemplateRegionsNamespaceTests class...
*
* @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
* @since 1.5.0
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(initializers = GemfireTestApplicationContextInitializer.class)
@SuppressWarnings("unused")
public class TemplateRegionsNamespaceTests {
@Autowired
private ApplicationContext applicationContext;
@Resource(name = "SimpleReplicateRegion")
private Region<Integer, String> simpleReplicateRegion;
@SuppressWarnings("deprecation")
protected static <K, V> void assertBaseRegionAttributes(final Region<K, V> region) {
assertNotNull("The Region must not be null!", region);
RegionAttributes<K, V> regionAttributes = region.getAttributes();
assertNotNull("The Region must have RegionAttributes defined!", regionAttributes);
assertTrue(regionAttributes.getCloningEnabled());
assertFalse(regionAttributes.getConcurrencyChecksEnabled());
assertTrue(regionAttributes.isDiskSynchronous());
assertTrue(regionAttributes.getIgnoreJTA());
assertEquals(Long.class, regionAttributes.getKeyConstraint());
assertEquals(0.90f, regionAttributes.getLoadFactor());
assertFalse(regionAttributes.getDataPolicy().withPersistence());
assertTrue(regionAttributes.getStatisticsEnabled());
assertEquals(String.class, regionAttributes.getValueConstraint());
assertTrue(regionAttributes.getIndexMaintenanceSynchronous());
assertTrue(ObjectUtils.isEmpty(regionAttributes.getCacheListeners()));
assertNotNull(regionAttributes.getCacheLoader());
assertTrue(regionAttributes.getCacheLoader() instanceof TestCacheLoader);
assertEquals("X", regionAttributes.getCacheLoader().toString());
assertNotNull(regionAttributes.getCacheWriter());
assertTrue(regionAttributes.getCacheWriter() instanceof TestCacheWriter);
assertEquals("Y", regionAttributes.getCacheWriter().toString());
}
@Test
public void testNoAbstractRegionTemplateBeans() {
String[] beanNames = {
"BaseRegion", "ExtendedRegionWithOverrides", "BaseReplicateRegion", "BasePartitionRegion", "BaseLocalRegion"
};
for (String beanName : beanNames) {
assertTrue(applicationContext.containsBean(beanName));
assertTrue(applicationContext.containsBeanDefinition(beanName));
try {
applicationContext.getBean(beanName);
fail(String.format("The abstract bean definition '%1$s' should not exists as a bean in the Spring context!",
beanName));
}
catch (BeansException ignore) {
assertTrue(ignore instanceof BeanIsAbstractException);
assertTrue(ignore.getMessage().contains(beanName));
}
}
}
@Test
public void testSimpleReplicateRegion() {
fail("Not Implemented!");
}
protected static interface Nameable {
void setName(String name);
}
protected static abstract class AbstractNameable implements Nameable {
private String name;
public void setName(final String name) {
this.name = name;
}
protected String getName() {
return this.name;
}
@Override
public String toString() {
return name;
}
}
public static final class TestAsyncEventListener extends AbstractNameable implements AsyncEventListener {
@Override public boolean processEvents(final List<AsyncEvent> asyncEvents) {
return false;
}
@Override public void close() {
}
}
public static final class TestCacheListener extends CacheListenerAdapter {
private String name;
public void setName(final String name) {
this.name = name;
}
@Override
public String toString() {
return name;
}
}
public static final class TestCacheLoader extends AbstractNameable implements CacheLoader {
@Override public Object load(final LoaderHelper loaderHelper) throws CacheLoaderException {
return null;
}
@Override public void close() {
}
}
public static final class TestCacheWriter extends CacheWriterAdapter {
private String name;
public void setName(final String name) {
this.name = name;
}
@Override
public String toString() {
return name;
}
}
public static final class TestPartitionListener extends PartitionListenerAdapter {
private String name;
public void setName(final String name) {
this.name = name;
}
@Override
public String toString() {
return name;
}
}
public static final class TestPartitionResolver extends AbstractNameable implements PartitionResolver {
@Override public Object getRoutingObject(final EntryOperation entryOperation) {
return null;
}
@Override public String getName() {
return super.getName();
}
@Override public void close() {
}
}
}

View File

@@ -0,0 +1,92 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:gfe="http://www.springframework.org/schema/gemfire"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/gemfire http://www.springframework.org/schema/gemfire/spring-gemfire.xsd
">
<gfe:cache/>
<gfe:async-event-queue id="TestAsyncEventQueue" persistent="false" parallel="true" dispatcher-threads="4">
<gfe:async-event-listener>
<bean class="org.springframework.data.gemfire.config.TemplateRegionsNamespaceTests$TestAsyncEventListener"/>
</gfe:async-event-listener>
</gfe:async-event-queue>
<gfe:gateway-sender id="TestGatewaySender" remote-distributed-system-id="123" manual-start="true" persistent="false"
parallel="true" dispatcher-threads="8"/>
<!-- Generic Region -->
<gfe:region-template id="BaseRegion" cloning-enabled="true" concurrency-checks-enabled="false"
disk-synchronous="true" ignore-jta="true" initial-capacity="1000"
key-constraint="java.lang.Long" load-factor="0.90" persistent="false" statistics="true"
value-constraint="java.lang.String" index-update-type="synchronous">
<gfe:cache-loader>
<bean class="org.springframework.data.gemfire.config.TemplateRegionsNamespaceTests$TestCacheLoader" p:name="X"/>
</gfe:cache-loader>
<gfe:cache-writer>
<bean class="org.springframework.data.gemfire.config.TemplateRegionsNamespaceTests$TestCacheWriter" p:name="Y"/>
</gfe:cache-writer>
</gfe:region-template>
<gfe:region-template id="ExtendedRegionWithOverrides" cloning-enabled="false" concurrency-checks-enabled="true"
disk-synchronous="false" ignore-jta="false" key-constraint="java.lang.String" template="BaseRegion">
<gfe:cache-listener>
<bean class="org.springframework.data.gemfire.config.TemplateRegionsNamespaceTests$TestCacheListener" p:name="Z"/>
</gfe:cache-listener>
<gfe:gateway-sender-ref bean="TestGatewaySender"/>
<gfe:async-event-queue-ref bean="TestAsyncEventQueue"/>
</gfe:region-template>
<!-- REPLICATE Region -->
<gfe:replicated-region-template id="BaseReplicateRegion" concurrency-level="2" enable-async-conflation="true"
enable-subscription-conflation="true" template="BaseRegion">
<gfe:subscription type="CACHE_CONTENT"/>
<gfe:eviction type="ENTRY_COUNT" threshold="1000" action="OVERFLOW_TO_DISK"/>
</gfe:replicated-region-template>
<gfe:replicated-region id="SimpleReplicateRegion" persistent="true" concurrency-level="8" is-lock-grantor="true" scope="global"
key-constraint="java.lang.Integer">
<gfe:cache-listener>
<bean class="org.springframework.data.gemfire.config.TemplateRegionsNamespaceTests$TestCacheListener" p:name="A"/>
</gfe:cache-listener>
</gfe:replicated-region>
<gfe:replicated-region id="InheritedReplicateRegion" template="BaseReplicateRegion"/>
<gfe:replicated-region id="ComplexReplicateRegion" persistent="true" key-constraint="java.lang.Integer" cloning-enabled="false"
template="BaseReplicateRegion">
<gfe:cache-listener>
<bean class="org.springframework.data.gemfire.config.TemplateRegionsNamespaceTests$TestCacheListener" p:name="AAA"/>
</gfe:cache-listener>
<gfe:cache-loader>
<bean class="org.springframework.data.gemfire.config.TemplateRegionsNamespaceTests$TestCacheLoader" p:name="xyz"/>
</gfe:cache-loader>
<gfe:subscription type="ALL"/>
<gfe:eviction type="ENTRY_COUNT" threshold="1024" action="OVERFLOW_TO_DISK"/>
</gfe:replicated-region>
<!-- PARTITION Region -->
<gfe:partitioned-region-template id="BasePartitionRegion" copies="2" local-max-memory="1000" total-max-memory="4000"
total-buckets="77" recovery-delay="1000" startup-recovery-delay="5000">
<gfe:partition-resolver>
<bean class="org.springframework.data.gemfire.config.TemplateRegionsNamespaceTests$TestPartitionResolver" p:name="A"/>
</gfe:partition-resolver>
<gfe:partition-listener>
<bean class="org.springframework.data.gemfire.config.TemplateRegionsNamespaceTests$TestPartitionListener" p:name="B"/>
</gfe:partition-listener>
<gfe:subscription type="ALL"/>
<gfe:eviction type="MEMORY_SIZE" threshold="4000" action="OVERFLOW_TO_DISK"/>
</gfe:partitioned-region-template>
<gfe:local-region-template id="BaseLocalRegion" concurrency-level="4">
<gfe:eviction type="ENTRY_COUNT" threshold="8192" action="LOCAL_DESTROY"/>
</gfe:local-region-template>
</beans>