SGF-338 - Both <gfe:custom-entry-ttl> and <gfe:custom-entry-tti> SDG XML namespace elements allow for more than one 'CustomExpiry' bean to be set in the Region Expiration Attributes although GemFire only allows one!

This commit is contained in:
John Blum
2014-10-07 15:35:08 -07:00
parent 796226d0de
commit 664d53447f
8 changed files with 367 additions and 24 deletions

View File

@@ -276,9 +276,9 @@ abstract class ParsingUtils {
result |= parseExpiration(element, "region-tti", "regionIdleTimeout", regionAttributesBuilder);
result |= parseExpiration(element, "entry-ttl", "entryTimeToLive", regionAttributesBuilder);
result |= parseExpiration(element, "entry-tti", "entryIdleTimeout", regionAttributesBuilder);
result |= parseCustomExpiration(element, parserContext, "custom-entry-ttl","customEntryTimeToLive",
result |= parseCustomExpiration(element, parserContext, "custom-entry-ttl", "customEntryTimeToLive",
regionAttributesBuilder);
result |= parseCustomExpiration(element, parserContext, "custom-entry-tti","customEntryIdleTimeout",
result |= parseCustomExpiration(element, parserContext, "custom-entry-tti", "customEntryIdleTimeout",
regionAttributesBuilder);
if (result) {

View File

@@ -510,8 +510,7 @@ The name of the region definition.]]></xsd:documentation>
<xsd:complexContent>
<xsd:extension base="basicRegionType">
<xsd:sequence>
<xsd:element name="cache-listener" minOccurs="0"
maxOccurs="1">
<xsd:element name="cache-listener" minOccurs="0" maxOccurs="1">
<xsd:annotation>
<xsd:documentation source="com.gemstone.gemfire.cache.CacheListener"><![CDATA[
A cache listener definition for this region. A cache listener handles region or entry related events (that occur after
@@ -529,8 +528,7 @@ other thread for accessing the region and not waiting for it to complete its tas
</xsd:annotation>
<xsd:complexType>
<xsd:sequence>
<xsd:any namespace="##other" processContents="skip"
minOccurs="0" maxOccurs="unbounded">
<xsd:any namespace="##other" processContents="skip" minOccurs="0" maxOccurs="unbounded">
<xsd:annotation>
<xsd:documentation><![CDATA[
Inner bean definition of the cache listener.
@@ -561,16 +559,14 @@ to support compression on a Region.
</xsd:appinfo>
</xsd:annotation>
</xsd:element>
<xsd:element name="region-ttl" type="expirationType"
minOccurs="0" maxOccurs="1">
<xsd:element name="region-ttl" type="expirationType" minOccurs="0" maxOccurs="1">
<xsd:annotation>
<xsd:documentation><![CDATA[[
Time to live configuration for the region itself. Default: no expiration.
]]></xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="region-tti" type="expirationType"
minOccurs="0" maxOccurs="1">
<xsd:element name="region-tti" type="expirationType" minOccurs="0" maxOccurs="1">
<xsd:annotation>
<xsd:documentation><![CDATA[[
Time to idle (or idle timeout) configuration for the region itself. Default: no expiration.
@@ -578,16 +574,14 @@ Time to idle (or idle timeout) configuration for the region itself. Default: no
</xsd:annotation>
</xsd:element>
<xsd:choice>
<xsd:element name="entry-ttl" type="expirationType"
minOccurs="0" maxOccurs="1">
<xsd:element name="entry-ttl" type="expirationType" minOccurs="0" maxOccurs="1">
<xsd:annotation>
<xsd:documentation><![CDATA[[
Time to live configuration for the region entries. Default: no expiration.
]]></xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="custom-entry-ttl" type="customExpirationType"
minOccurs="0" maxOccurs="1">
<xsd:element name="custom-entry-ttl" type="customExpirationType" minOccurs="0" maxOccurs="1">
<xsd:annotation>
<xsd:appinfo>
<tool:annotation>
@@ -595,7 +589,7 @@ Time to live configuration for the region entries. Default: no expiration.
</tool:annotation>
</xsd:appinfo>
<xsd:documentation><![CDATA[[
CustomExpiry time to live configuration for the region entries. Default: no expiration.
CustomExpiry Time-to-Live (TTL) configuration for the Region Entries. The default is no expiration.
]]></xsd:documentation>
</xsd:annotation>
</xsd:element>
@@ -609,8 +603,7 @@ Time to idle (or idle timeout) configuration for the region entries. Default: no
]]></xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="custom-entry-tti" type="customExpirationType"
minOccurs="0" maxOccurs="1">
<xsd:element name="custom-entry-tti" type="customExpirationType" minOccurs="0" maxOccurs="1">
<xsd:annotation>
<xsd:appinfo>
<tool:annotation>
@@ -618,7 +611,7 @@ Time to idle (or idle timeout) configuration for the region entries. Default: no
</tool:annotation>
</xsd:appinfo>
<xsd:documentation><![CDATA[[
CustomExpiry Time to idle (or idle timeout) configuration for the region entries. Default: no expiration.
CustomExpiry Time-to-Idle (or Idle Timeout, TTI) configuration for the Region entries. The default is no expiration.
]]></xsd:documentation>
</xsd:annotation>
</xsd:element>
@@ -1614,8 +1607,7 @@ When the region or cached object expires, it is destroyed locally only. Not supp
<!-- -->
<xsd:complexType name="customExpirationType">
<xsd:sequence>
<xsd:any namespace="##other" processContents="skip"
minOccurs="0" maxOccurs="unbounded">
<xsd:any namespace="##other" processContents="skip" minOccurs="0" maxOccurs="1">
<xsd:annotation>
<xsd:documentation><![CDATA[
Inner bean definition of the CustomExpiry.

View File

@@ -0,0 +1,74 @@
/*
* 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.assertTrue;
import org.junit.Test;
import org.springframework.beans.factory.xml.XmlBeanDefinitionStoreException;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;
import org.springframework.data.gemfire.test.GemfireTestBeanPostProcessor;
import org.xml.sax.SAXParseException;
/**
* The InvalidRegionExpirationAttributesNamespaceTest class is a test suite of test cases testing the proper syntax
* of declaring "custom" expiration attributes on a Region.
*
* @author John Blum
* @see org.junit.Test
* @see org.springframework.context.ConfigurableApplicationContext
* @see org.springframework.context.support.GenericXmlApplicationContext
* @see org.springframework.data.gemfire.test.GemfireTestBeanPostProcessor
* @since 1.5.0
*/
public class InvalidRegionExpirationAttributesNamespaceTest {
protected String contextConfigLocation() {
return getClass().getName().replaceAll("\\.", "/").concat("-context.xml");
}
protected ConfigurableApplicationContext createApplicationContext() {
return new GenericXmlApplicationContext();
}
protected ConfigurableApplicationContext configureContext(ConfigurableApplicationContext applicationContext) {
applicationContext.getBeanFactory().addBeanPostProcessor(new GemfireTestBeanPostProcessor());
return applicationContext;
}
protected ConfigurableApplicationContext initializeApplicationContext(ConfigurableApplicationContext applicationContext) {
assertTrue(applicationContext instanceof GenericXmlApplicationContext);
((GenericXmlApplicationContext) applicationContext).load(contextConfigLocation());
applicationContext.registerShutdownHook();
applicationContext.refresh();
return applicationContext;
}
@Test(expected = XmlBeanDefinitionStoreException.class)
public void testInvalidXmlSyntax() {
try {
initializeApplicationContext(configureContext(createApplicationContext()));
}
catch (XmlBeanDefinitionStoreException expected) {
assertTrue(expected.getCause() instanceof SAXParseException);
assertTrue(expected.getMessage().contains("Invalid content was found starting with element 'bean'"));
throw expected;
}
}
}

View File

@@ -34,15 +34,20 @@ import com.gemstone.gemfire.cache.Region;
import com.gemstone.gemfire.internal.cache.lru.LRUCapacityController;
/**
* The RegionEvictionAttributesNamespaceTest class is a test suite of test cases testing the use of Eviction settings
* (EvictionAttributes) in the SDG XML namespace.
* The RegionEvictionAttributesNamespaceTest class is a test suite of test cases testing the use of
* Eviction configuration settings (EvictionAttributes) in the SDG XML namespace.
*
* @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.3.4
*/
@ContextConfiguration(locations = "regions-with-eviction-attributes-ns.xml",
initializers = GemfireTestApplicationContextInitializer.class)
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(initializers = GemfireTestApplicationContextInitializer.class)
@SuppressWarnings("unused")
public class RegionEvictionAttributesNamespaceTest {
@Resource(name = "One")

View File

@@ -0,0 +1,186 @@
/*
* 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.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.mockito.Mockito.mock;
import javax.annotation.Resource;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.data.gemfire.test.GemfireTestApplicationContextInitializer;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.util.Assert;
import com.gemstone.gemfire.cache.CustomExpiry;
import com.gemstone.gemfire.cache.DataPolicy;
import com.gemstone.gemfire.cache.ExpirationAction;
import com.gemstone.gemfire.cache.ExpirationAttributes;
import com.gemstone.gemfire.cache.Region;
/**
* The RegionExpirationAttributesNamespaceTest class is a test suite of test cases testing the configuration of
* ExpirationAttribute settings on Region Entries.
*
* @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
* @see com.gemstone.gemfire.cache.Region
* @see com.gemstone.gemfire.cache.RegionAttributes
* @see com.gemstone.gemfire.cache.EvictionAttributes
* @since 1.5.0
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(initializers = GemfireTestApplicationContextInitializer.class)
@SuppressWarnings("unused")
public class RegionExpirationAttributesNamespaceTest {
@Resource(name = "ReplicateExample")
private Region<?, ?> replicateExample;
@Resource(name = "PreloadedExample")
private Region<?, ?> preloadedExample;
@Resource(name = "PartitionExample")
private Region<?, ?> partitionExample;
@Resource(name = "LocalExample")
private Region<?, ?> localExample;
protected void assertRegionMetaData(final Region<?, ?> region, final String regionName, final DataPolicy dataPolicy) {
assertRegionMetaData(region, regionName, Region.SEPARATOR + regionName, dataPolicy);
}
protected void assertRegionMetaData(final Region<?, ?> region, final String regionName, final String regionFullPath,
final DataPolicy dataPolicy) {
assertNotNull(String.format("The '%1$s' Region was not properly configured and initialized!", regionName), region);
assertEquals(regionName, region.getName());
assertEquals(regionFullPath, region.getFullPath());
assertNotNull(region.getAttributes());
assertEquals(dataPolicy, region.getAttributes().getDataPolicy());
}
protected void assertNoExpiration(final ExpirationAttributes expirationAttributes) {
if (expirationAttributes != null) {
//assertEquals(ExpirationAction.INVALIDATE, expirationAttributes.getAction());
assertEquals(0, expirationAttributes.getTimeout());
}
}
protected void assertExpirationAttributes(final ExpirationAttributes expirationAttributes,
final int timeout, final ExpirationAction action) {
assertNotNull(expirationAttributes);
assertEquals(timeout, expirationAttributes.getTimeout());
assertEquals(action, expirationAttributes.getAction());
}
@SuppressWarnings("unchecked")
protected void assertCustomExpiry(final CustomExpiry<?, ?> customExpiry, final String name,
final int timeout, final ExpirationAction action) {
assertNotNull(customExpiry);
assertEquals(name, customExpiry.toString());
assertExpirationAttributes(customExpiry.getExpiry(mock(Region.Entry.class)), timeout, action);
}
@Test
public void testReplicateExampleExpirationAttributes() {
assertRegionMetaData(replicateExample, "ReplicateExample", DataPolicy.REPLICATE);
assertExpirationAttributes(replicateExample.getAttributes().getEntryTimeToLive(),
600, ExpirationAction.DESTROY);
assertExpirationAttributes(replicateExample.getAttributes().getEntryIdleTimeout(),
300, ExpirationAction.INVALIDATE);
assertNull(replicateExample.getAttributes().getCustomEntryTimeToLive());
assertNull(replicateExample.getAttributes().getCustomEntryIdleTimeout());
}
@Test
public void testPreloadedExampleExpirationAttributes() {
assertRegionMetaData(preloadedExample, "PreloadedExample", DataPolicy.PRELOADED);
assertExpirationAttributes(preloadedExample.getAttributes().getEntryTimeToLive(),
120, ExpirationAction.LOCAL_DESTROY);
assertNoExpiration(preloadedExample.getAttributes().getEntryIdleTimeout());
assertNull(preloadedExample.getAttributes().getCustomEntryTimeToLive());
assertNull(preloadedExample.getAttributes().getCustomEntryIdleTimeout());
}
@Test
public void testPartitionExampleExpirationAttributes() {
assertRegionMetaData(partitionExample, "PartitionExample", DataPolicy.PARTITION);
assertExpirationAttributes(partitionExample.getAttributes().getEntryTimeToLive(),
300, ExpirationAction.DESTROY);
assertNoExpiration(partitionExample.getAttributes().getEntryIdleTimeout());
assertNull(partitionExample.getAttributes().getCustomEntryTimeToLive());
assertCustomExpiry(partitionExample.getAttributes().getCustomEntryIdleTimeout(), "PartitionCustomExpiry",
120, ExpirationAction.INVALIDATE);
}
@Test
public void testLocalExampleExpirationAttributes() {
assertRegionMetaData(localExample, "LocalExample", DataPolicy.NORMAL);
assertNoExpiration(localExample.getAttributes().getEntryTimeToLive());
assertNoExpiration(localExample.getAttributes().getEntryIdleTimeout());
assertCustomExpiry(localExample.getAttributes().getCustomEntryTimeToLive(), "LocalTtlCustomExpiry",
180, ExpirationAction.LOCAL_DESTROY);
assertCustomExpiry(localExample.getAttributes().getCustomEntryIdleTimeout(), "LocalTtiCustomExpiry",
60, ExpirationAction.LOCAL_INVALIDATE);
}
public static class TestCustomExpiry<K, V> implements CustomExpiry<K, V> {
private ExpirationAction action;
private Integer timeout;
private String name;
@Override
public ExpirationAttributes getExpiry(final Region.Entry<K, V> kvEntry) {
Assert.state(timeout != null, "The expiration 'timeout' must be specified!");
Assert.state(action != null, "The expiration 'action' must be specified!");
return new ExpirationAttributes(timeout, action);
}
public void setAction(final ExpirationAction action) {
this.action = action;
}
public void setName(final String name) {
this.name = name;
}
public void setTimeout(final Integer timeout) {
this.timeout = timeout;
}
@Override
public void close() {
}
@Override
public String toString() {
return this.name;
}
}
}

View File

@@ -0,0 +1,30 @@
<?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:util="http://www.springframework.org/schema/util"
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
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd
">
<util:properties id="gemfireProperties">
<prop key="name">InvalidRegionExpirationAttributesNamespaceTest</prop>
<prop key="mcast-port">0</prop>
<prop key="log-level">config</prop>
</util:properties>
<gfe:cache properties-ref="gemfireProperties"/>
<gfe:replicated-region id="ReplicateExample" persistent="false">
<gfe:custom-entry-tti>
<bean class="org.springframework.data.gemfire.config.RegionExpirationAttributesNamespaceTest$TestCustomExpiry"
p:name="One" p:timeout="60" p:action="#{T(com.gemstone.gemfire.cache.ExpirationAction).DESTROY}"/>
<bean class="org.springframework.data.gemfire.config.RegionExpirationAttributesNamespaceTest$TestCustomExpiry"
p:name="Two" p:timeout="120" p:action="#{T(com.gemstone.gemfire.cache.ExpirationAction).INVALIDATE}"/>
</gfe:custom-entry-tti>
</gfe:replicated-region>
</beans>

View File

@@ -0,0 +1,56 @@
<?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:util="http://www.springframework.org/schema/util"
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
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd
">
<util:properties id="gemfireProperties">
<prop key="name">RegionExpirationAttributesNamespaceTest</prop>
<prop key="mcast-port">0</prop>
<prop key="log-level">config</prop>
</util:properties>
<gfe:cache properties-ref="gemfireProperties"/>
<gfe:replicated-region id="ReplicateExample" persistent="false">
<gfe:entry-ttl timeout="600" action="DESTROY"/>
<gfe:entry-tti timeout="300" action="INVALIDATE"/>
</gfe:replicated-region>
<!--
NOTE GemFire will switch the Region's DataPolicy when Entry Expiration Action settings
are "LOCAL_[DESTROY|INVAlIDATE]" based or the Eviction Action is "LOCAL_[DESTROY|INVALIDATE]".
-->
<gfe:replicated-region id="PreloadedExample" persistent="false">
<gfe:entry-ttl timeout="120" action="LOCAL_DESTROY"/>
</gfe:replicated-region>
<gfe:partitioned-region id="PartitionExample" persistent="false">
<gfe:entry-ttl timeout="300" action="DESTROY"/>
<gfe:custom-entry-tti>
<bean class="org.springframework.data.gemfire.config.RegionExpirationAttributesNamespaceTest$TestCustomExpiry"
p:name="PartitionCustomExpiry" p:timeout="120" p:action="#{T(com.gemstone.gemfire.cache.ExpirationAction).INVALIDATE}"/>
</gfe:custom-entry-tti>
</gfe:partitioned-region>
<gfe:local-region id="LocalExample" persistent="false">
<gfe:custom-entry-ttl>
<bean class="org.springframework.data.gemfire.config.RegionExpirationAttributesNamespaceTest$TestCustomExpiry"
p:name="LocalTtlCustomExpiry" p:timeout="180" p:action="#{T(com.gemstone.gemfire.cache.ExpirationAction).LOCAL_DESTROY}"/>
</gfe:custom-entry-ttl>
<gfe:custom-entry-tti ref="LocalTtiCustomExpiry"/>
</gfe:local-region>
<bean id="LocalTtiCustomExpiry" class="org.springframework.data.gemfire.config.RegionExpirationAttributesNamespaceTest$TestCustomExpiry">
<property name="name" value="LocalTtiCustomExpiry"/>
<property name="timeout" value="60"/>
<property name="action" value="#{T(com.gemstone.gemfire.cache.ExpirationAction).LOCAL_INVALIDATE}"/>
</bean>
</beans>