From 3f72ab89283967ff6c5f1e0e1897fb6838f8ecc9 Mon Sep 17 00:00:00 2001 From: John Blum Date: Mon, 19 Jan 2015 18:16:06 -0800 Subject: [PATCH] SGF-289 - Enumeration restrictions (xsd:enumeration) should be avoided in the XML schema. Removed the XSD enumeration restriction on the 'type' attribute of the 'evictionType' XSD complex-type definition in the SDG XML namespace schema, which is used by the 'eviction' sub-elements in the LOCAL, PARTITION and REPLICATE Region element schema types. In addition, created the ExpirationAttributesFactoryBean class in the org.springframework.data.gemfire package which serves as a Spring FactoryBean and builder for constructing GemFire EvictionAttributes used in Region configuration. Updated tests to assert and validate the use of property placeholders on both the Eviction 'type' and Expiration 'action' attributes in the Spring Data GemFire XML namespace configuration meta-data. --- .../data/gemfire/CacheFactoryBean.java | 9 +- .../data/gemfire/ExpirationActionType.java | 2 + .../ExpirationAttributesFactoryBean.java | 120 ++++++++++++++++++ .../data/gemfire/config/ParsingUtils.java | 35 +++-- .../gemfire/config/spring-gemfire-1.6.xsd | 38 ++---- .../gemfire/ExpirationActionTypeTest.java | 6 + .../ExpirationAttributesFactoryBeanTest.java | 96 ++++++++++++++ ...victionAttributesNamespaceTest-context.xml | 12 +- ...irationAttributesNamespaceTest-context.xml | 14 +- 9 files changed, 278 insertions(+), 54 deletions(-) create mode 100644 src/main/java/org/springframework/data/gemfire/ExpirationAttributesFactoryBean.java create mode 100644 src/test/java/org/springframework/data/gemfire/ExpirationAttributesFactoryBeanTest.java diff --git a/src/main/java/org/springframework/data/gemfire/CacheFactoryBean.java b/src/main/java/org/springframework/data/gemfire/CacheFactoryBean.java index e776648f..d368d562 100644 --- a/src/main/java/org/springframework/data/gemfire/CacheFactoryBean.java +++ b/src/main/java/org/springframework/data/gemfire/CacheFactoryBean.java @@ -912,8 +912,13 @@ public class CacheFactoryBean implements BeanClassLoaderAware, BeanFactoryAware, /* (non-Javadoc) */ private void initBeanFactory() { if (getBeanFactory() instanceof ConfigurableBeanFactory) { - ((ConfigurableBeanFactory) getBeanFactory()).registerCustomEditor(IndexMaintenanceType.class, - IndexMaintenanceTypeConverter.class); + ConfigurableBeanFactory beanFactory = (ConfigurableBeanFactory) getBeanFactory(); + + beanFactory.registerCustomEditor(EvictionType.class, EvictionTypeConverter.class); + beanFactory.registerCustomEditor(ExpirationActionType.class, ExpirationActionTypeConverter.class); + beanFactory.registerCustomEditor(IndexMaintenanceType.class, IndexMaintenanceTypeConverter.class); + beanFactory.registerCustomEditor(IndexType.class, IndexTypeConverter.class); + beanFactory.registerCustomEditor(SubscriptionType.class, SubscriptionTypeConverter.class); } } diff --git a/src/main/java/org/springframework/data/gemfire/ExpirationActionType.java b/src/main/java/org/springframework/data/gemfire/ExpirationActionType.java index db6b7953..6fdbbc50 100644 --- a/src/main/java/org/springframework/data/gemfire/ExpirationActionType.java +++ b/src/main/java/org/springframework/data/gemfire/ExpirationActionType.java @@ -32,6 +32,8 @@ public enum ExpirationActionType { LOCAL_DESTROY(ExpirationAction.LOCAL_DESTROY), LOCAL_INVALIDATE(ExpirationAction.LOCAL_INVALIDATE); + public static final ExpirationActionType DEFAULT = ExpirationActionType.INVALIDATE; + private final ExpirationAction expirationAction; /** diff --git a/src/main/java/org/springframework/data/gemfire/ExpirationAttributesFactoryBean.java b/src/main/java/org/springframework/data/gemfire/ExpirationAttributesFactoryBean.java new file mode 100644 index 00000000..96ccb313 --- /dev/null +++ b/src/main/java/org/springframework/data/gemfire/ExpirationAttributesFactoryBean.java @@ -0,0 +1,120 @@ +/* + * 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 org.springframework.beans.factory.FactoryBean; +import org.springframework.beans.factory.InitializingBean; + +import com.gemstone.gemfire.cache.ExpirationAttributes; + +/** + * The ExpirationAttributesFactoryBean class is a Spring FactoryBean used to create GemFire ExpirationAttributes + * to specify Expiration policies for Region Time-to-Live (TTL) and Idle-Timeouts (TTI) as well as + * Entry Time-to-Live (TTL) and Idle-Timeouts (TTI). + * + * @author John Blum + * @see org.springframework.beans.factory.FactoryBean + * @see org.springframework.beans.factory.InitializingBean + * @see com.gemstone.gemfire.cache.ExpirationAttributes + * @since 1.6.0 + */ +@SuppressWarnings("unused") +public class ExpirationAttributesFactoryBean implements FactoryBean, InitializingBean { + + protected static final int DEFAULT_TIMEOUT = 0; + + protected static final ExpirationActionType DEFAULT_EXPIRATION_ACTION = ExpirationActionType.DEFAULT; + + private ExpirationAttributes expirationAttributes; + + private Integer timeout; + + private ExpirationActionType action; + + /* non-Javadoc */ + @Override + public ExpirationAttributes getObject() throws Exception { + return expirationAttributes; + } + + /* non-Javadoc */ + @Override + public Class getObjectType() { + return (expirationAttributes != null ? expirationAttributes.getClass() : ExpirationAttributes.class); + } + + /* non-Javadoc */ + @Override + public boolean isSingleton() { + return true; + } + + /** + * Sets the action to perform when a Region or an Entry expire. + * + * @param action the type of action to perform on expiration + * @see org.springframework.data.gemfire.ExpirationActionType + */ + public void setAction(ExpirationActionType action) { + this.action = action; + } + + /** + * Gets the action to perform when a Region or an Entry expires. + * + * @return the type of action to perform on expiration. + * @see org.springframework.data.gemfire.ExpirationActionType + * @see com.gemstone.gemfire.cache.ExpirationAttributes#getAction() + */ + public ExpirationActionType getAction() { + return (action != null ? action : DEFAULT_EXPIRATION_ACTION); + } + + /** + * Sets the number of seconds before a Region or an Entry expires. + * + * @param timeout the number of seconds before a Region or an Entry expires. + */ + public void setTimeout(final Integer timeout) { + this.timeout = timeout; + } + + /** + * Gets the number of seconds before a Region or an Entry expires. + * + * @return the number of seconds before a Region or an Entry expires. + * @see com.gemstone.gemfire.cache.ExpirationAttributes#getTimeout() + */ + public int getTimeout() { + return (timeout != null ? timeout : DEFAULT_TIMEOUT); + } + + /** + * Initializes the GemFire ExpirationAttributes produced by this factory. + * + * @throws Exception if the construction of the ExpirationAttributes was not successful. + * @see #getAction() + * @see #getTimeout() + * @see org.springframework.data.gemfire.ExpirationActionType#getExpirationAction() + * @see com.gemstone.gemfire.cache.ExpirationAttributes + */ + @Override + public void afterPropertiesSet() throws Exception { + expirationAttributes = new ExpirationAttributes(getTimeout(), getAction().getExpirationAction()); + } + +} 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 0061448f..86d85cda 100644 --- a/src/main/java/org/springframework/data/gemfire/config/ParsingUtils.java +++ b/src/main/java/org/springframework/data/gemfire/config/ParsingUtils.java @@ -26,9 +26,9 @@ import org.springframework.beans.factory.support.ManagedList; import org.springframework.beans.factory.xml.ParserContext; import org.springframework.core.Conventions; import org.springframework.data.gemfire.EvictionAttributesFactoryBean; -import org.springframework.data.gemfire.EvictionType; import org.springframework.data.gemfire.ExpirationActionType; import org.springframework.data.gemfire.ExpirationActionTypeConverter; +import org.springframework.data.gemfire.ExpirationAttributesFactoryBean; import org.springframework.data.gemfire.GemfireUtils; import org.springframework.data.gemfire.SubscriptionAttributesFactoryBean; import org.springframework.data.gemfire.SubscriptionType; @@ -198,10 +198,10 @@ abstract class ParsingUtils { setPropertyValue(evictionElement, evictionAttributesBuilder, "action"); setPropertyValue(evictionElement, evictionAttributesBuilder, "threshold"); - String evictionType = evictionElement.getAttribute("type"); + String typeAttributeValue = evictionElement.getAttribute("type"); - if (StringUtils.hasText(evictionType)) { - evictionAttributesBuilder.addPropertyValue("type", EvictionType.valueOf(evictionType.toUpperCase())); + if (StringUtils.hasText(typeAttributeValue)) { + evictionAttributesBuilder.addPropertyValue("type", StringUtils.trimWhitespace(typeAttributeValue)); } Element objectSizerElement = DomUtils.getChildElementByTagName(evictionElement, "object-sizer"); @@ -212,7 +212,8 @@ abstract class ParsingUtils { evictionAttributesBuilder.addPropertyValue("ObjectSizer", sizer); } - regionAttributesBuilder.addPropertyValue("evictionAttributes", evictionAttributesBuilder.getBeanDefinition()); + regionAttributesBuilder.addPropertyValue("evictionAttributes", + evictionAttributesBuilder.getBeanDefinition()); return true; } @@ -263,8 +264,8 @@ abstract class ParsingUtils { } } - static void parseStatistics(Element element, BeanDefinitionBuilder attrBuilder) { - setPropertyValue(element, attrBuilder, "statistics", "statisticsEnabled"); + static void parseStatistics(Element element, BeanDefinitionBuilder regionAttributesBuilder) { + setPropertyValue(element, regionAttributesBuilder, "statistics", "statisticsEnabled"); } /** @@ -379,23 +380,19 @@ abstract class ParsingUtils { private static boolean parseExpiration(Element rootElement, String elementName, String propertyName, BeanDefinitionBuilder regionAttributesBuilder) { + Element expirationElement = DomUtils.getChildElementByTagName(rootElement, elementName); if (expirationElement != null) { - String timeoutAttribute = expirationElement.getAttribute("timeout"); - String expirationTimeout = (StringUtils.hasText(timeoutAttribute) ? timeoutAttribute : "0"); + String actionAttributeValue = expirationElement.getAttribute("action"); + String timeoutAttributeValue = expirationElement.getAttribute("timeout"); - String actionAttribute = StringUtils.trimAllWhitespace(expirationElement.getAttribute("action")); + BeanDefinitionBuilder expirationAttributesBuilder = BeanDefinitionBuilder.genericBeanDefinition( + ExpirationAttributesFactoryBean.class); - ExpirationActionType expirationActionType = new ExpirationActionTypeConverter().convert(actionAttribute); - ExpirationAction expirationAction = (expirationActionType != null - ? expirationActionType.getExpirationAction() : ExpirationAction.INVALIDATE); - - BeanDefinitionBuilder expirationAttributes = BeanDefinitionBuilder.genericBeanDefinition( - ExpirationAttributes.class); - expirationAttributes.addConstructorArgValue(expirationTimeout); - expirationAttributes.addConstructorArgValue(expirationAction); - regionAttributesBuilder.addPropertyValue(propertyName, expirationAttributes.getBeanDefinition()); + expirationAttributesBuilder.addPropertyValue("action", actionAttributeValue); + expirationAttributesBuilder.addPropertyValue("timeout", timeoutAttributeValue); + regionAttributesBuilder.addPropertyValue(propertyName, expirationAttributesBuilder.getBeanDefinition()); return true; } diff --git a/src/main/resources/org/springframework/data/gemfire/config/spring-gemfire-1.6.xsd b/src/main/resources/org/springframework/data/gemfire/config/spring-gemfire-1.6.xsd index 94d5baad..612d7b80 100644 --- a/src/main/resources/org/springframework/data/gemfire/config/spring-gemfire-1.6.xsd +++ b/src/main/resources/org/springframework/data/gemfire/config/spring-gemfire-1.6.xsd @@ -1603,38 +1603,20 @@ Entity computing sizes for objects stored into the grid. - - - - - - - - - - - - - - - - - - - - + + + + diff --git a/src/test/java/org/springframework/data/gemfire/ExpirationActionTypeTest.java b/src/test/java/org/springframework/data/gemfire/ExpirationActionTypeTest.java index 681624e8..e5c325e6 100644 --- a/src/test/java/org/springframework/data/gemfire/ExpirationActionTypeTest.java +++ b/src/test/java/org/springframework/data/gemfire/ExpirationActionTypeTest.java @@ -35,6 +35,12 @@ import com.gemstone.gemfire.cache.ExpirationAction; */ public class ExpirationActionTypeTest { + @Test + public void testDefault() { + assertEquals(ExpirationActionType.INVALIDATE, ExpirationActionType.DEFAULT); + assertEquals(ExpirationAction.INVALIDATE, ExpirationActionType.DEFAULT.getExpirationAction()); + } + @Test public void testValueOf() { assertEquals(ExpirationActionType.DESTROY, ExpirationActionType.valueOf(ExpirationAction.DESTROY)); diff --git a/src/test/java/org/springframework/data/gemfire/ExpirationAttributesFactoryBeanTest.java b/src/test/java/org/springframework/data/gemfire/ExpirationAttributesFactoryBeanTest.java new file mode 100644 index 00000000..8445cb10 --- /dev/null +++ b/src/test/java/org/springframework/data/gemfire/ExpirationAttributesFactoryBeanTest.java @@ -0,0 +1,96 @@ +/* + * 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.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +import com.gemstone.gemfire.cache.ExpirationAction; +import com.gemstone.gemfire.cache.ExpirationAttributes; + +/** + * The ExpirationAttributesFactoryBeanTest class is a test suite of test cases testing the contract and functionality + * of the ExpirationAttributesFactoryBean class. + * + * @author John Blum + * @see org.junit.Test + * @see org.springframework.data.gemfire.ExpirationAttributesFactoryBean + * @since 1.6.0 + */ +public class ExpirationAttributesFactoryBeanTest { + + @Test + public void testIsSingleton() { + assertTrue(new ExpirationAttributesFactoryBean().isSingleton()); + } + + @Test + public void testSetAndGetAction() { + ExpirationAttributesFactoryBean expirationAttributesFactoryBean = new ExpirationAttributesFactoryBean(); + + assertEquals(ExpirationAttributesFactoryBean.DEFAULT_EXPIRATION_ACTION, + expirationAttributesFactoryBean.getAction()); + + expirationAttributesFactoryBean.setAction(ExpirationActionType.LOCAL_DESTROY); + + assertEquals(ExpirationActionType.LOCAL_DESTROY, expirationAttributesFactoryBean.getAction()); + + expirationAttributesFactoryBean.setAction(null); + + assertEquals(ExpirationAttributesFactoryBean.DEFAULT_EXPIRATION_ACTION, + expirationAttributesFactoryBean.getAction()); + } + + @Test + public void testSetAndGetTimeout() { + ExpirationAttributesFactoryBean expirationAttributesFactoryBean = new ExpirationAttributesFactoryBean(); + + assertEquals(0, expirationAttributesFactoryBean.getTimeout()); + + expirationAttributesFactoryBean.setTimeout(60000); + + assertEquals(60000, expirationAttributesFactoryBean.getTimeout()); + + expirationAttributesFactoryBean.setTimeout(null); + + assertEquals(0, expirationAttributesFactoryBean.getTimeout()); + } + + @Test + public void testAfterPropertiesSet() throws Exception { + ExpirationAttributesFactoryBean expirationAttributesFactoryBean = new ExpirationAttributesFactoryBean(); + + assertNull(expirationAttributesFactoryBean.getObject()); + assertEquals(ExpirationAttributes.class, expirationAttributesFactoryBean.getObjectType()); + + expirationAttributesFactoryBean.setAction(ExpirationActionType.DESTROY); + expirationAttributesFactoryBean.setTimeout(8192); + expirationAttributesFactoryBean.afterPropertiesSet(); + + ExpirationAttributes expirationAttributes = expirationAttributesFactoryBean.getObject(); + + assertNotNull(expirationAttributes); + assertEquals(ExpirationAction.DESTROY, expirationAttributes.getAction()); + assertEquals(8192, expirationAttributes.getTimeout()); + assertEquals(expirationAttributes.getClass(), expirationAttributesFactoryBean.getObjectType()); + } + +} diff --git a/src/test/resources/org/springframework/data/gemfire/config/RegionEvictionAttributesNamespaceTest-context.xml b/src/test/resources/org/springframework/data/gemfire/config/RegionEvictionAttributesNamespaceTest-context.xml index 385654fe..e84b8bdc 100644 --- a/src/test/resources/org/springframework/data/gemfire/config/RegionEvictionAttributesNamespaceTest-context.xml +++ b/src/test/resources/org/springframework/data/gemfire/config/RegionEvictionAttributesNamespaceTest-context.xml @@ -1,14 +1,22 @@ + + heap_percentage + + + + RegionEvictionAttributesNamespaceTest 0 @@ -26,11 +34,11 @@ - + - + diff --git a/src/test/resources/org/springframework/data/gemfire/config/RegionExpirationAttributesNamespaceTest-context.xml b/src/test/resources/org/springframework/data/gemfire/config/RegionExpirationAttributesNamespaceTest-context.xml index 29fa02f3..c703e633 100644 --- a/src/test/resources/org/springframework/data/gemfire/config/RegionExpirationAttributesNamespaceTest-context.xml +++ b/src/test/resources/org/springframework/data/gemfire/config/RegionExpirationAttributesNamespaceTest-context.xml @@ -1,15 +1,23 @@ + + Destroy + + + + RegionExpirationAttributesNamespaceTest 0 @@ -19,20 +27,20 @@ - + - +