diff --git a/src/main/java/org/springframework/data/gemfire/client/ClientRegionFactoryBean.java b/src/main/java/org/springframework/data/gemfire/client/ClientRegionFactoryBean.java index f1676455..49990194 100644 --- a/src/main/java/org/springframework/data/gemfire/client/ClientRegionFactoryBean.java +++ b/src/main/java/org/springframework/data/gemfire/client/ClientRegionFactoryBean.java @@ -105,6 +105,7 @@ public class ClientRegionFactoryBean extends RegionLookupFactoryBean // map region attributes onto the client region factory if (attributes != null) { factory.setCloningEnabled(attributes.getCloningEnabled()); + factory.setConcurrencyChecksEnabled(attributes.getConcurrencyChecksEnabled()); factory.setConcurrencyLevel(attributes.getConcurrencyLevel()); factory.setCustomEntryIdleTimeout(attributes.getCustomEntryIdleTimeout()); factory.setCustomEntryTimeToLive(attributes.getCustomEntryTimeToLive()); 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 198b24db..05ec4475 100644 --- a/src/main/java/org/springframework/data/gemfire/config/ClientRegionParser.java +++ b/src/main/java/org/springframework/data/gemfire/config/ClientRegionParser.java @@ -46,7 +46,7 @@ class ClientRegionParser extends AbstractRegionParser { } @Override - protected void doParseRegion(Element element, ParserContext parserContext, BeanDefinitionBuilder builder, + protected void doParseRegion(Element element, ParserContext parserContext, BeanDefinitionBuilder regionBuilder, boolean subRegion) { validateDataPolicyShortcutAttributesMutualExclusion(element, parserContext); @@ -54,30 +54,32 @@ class ClientRegionParser extends AbstractRegionParser { String resolvedCacheRef = ParsingUtils.resolveCacheReference(element.getAttribute("cache-ref")); if (!subRegion) { - builder.addPropertyReference("cache", resolvedCacheRef); - ParsingUtils.setPropertyValue(element, builder, "close"); - ParsingUtils.setPropertyValue(element, builder, "destroy"); + regionBuilder.addPropertyReference("cache", resolvedCacheRef); + ParsingUtils.setPropertyValue(element, regionBuilder, "close"); + ParsingUtils.setPropertyValue(element, regionBuilder, "destroy"); } - ParsingUtils.setPropertyValue(element, builder, "name"); - ParsingUtils.setPropertyValue(element, builder, "data-policy", "dataPolicyName"); - ParsingUtils.setPropertyValue(element, builder, "ignore-if-exists", "lookupEnabled"); - ParsingUtils.setPropertyValue(element, builder, "persistent"); - ParsingUtils.setPropertyValue(element, builder, "pool-name"); - ParsingUtils.setPropertyValue(element, builder, "shortcut"); + ParsingUtils.setPropertyValue(element, regionBuilder, "name"); + ParsingUtils.setPropertyValue(element, regionBuilder, "data-policy", "dataPolicyName"); + ParsingUtils.setPropertyValue(element, regionBuilder, "ignore-if-exists", "lookupEnabled"); + ParsingUtils.setPropertyValue(element, regionBuilder, "persistent"); + ParsingUtils.setPropertyValue(element, regionBuilder, "pool-name"); + ParsingUtils.setPropertyValue(element, regionBuilder, "shortcut"); - parseDiskStoreAttribute(element, builder); + parseDiskStoreAttribute(element, regionBuilder); // Client RegionAttributes for overflow/eviction, expiration and statistics BeanDefinitionBuilder regionAttributesBuilder = BeanDefinitionBuilder.genericBeanDefinition( RegionAttributesFactoryBean.class); + mergeTemplateRegionAttributes(element, parserContext, regionBuilder, regionAttributesBuilder); + ParsingUtils.parseOptionalRegionAttributes(parserContext, element, regionAttributesBuilder); ParsingUtils.parseStatistics(element, regionAttributesBuilder); ParsingUtils.parseExpiration(parserContext, element, regionAttributesBuilder); ParsingUtils.parseEviction(parserContext, element, regionAttributesBuilder); - builder.addPropertyValue("attributes", regionAttributesBuilder.getBeanDefinition()); + regionBuilder.addPropertyValue("attributes", regionAttributesBuilder.getBeanDefinition()); List subElements = DomUtils.getChildElements(element); @@ -87,16 +89,16 @@ class ClientRegionParser extends AbstractRegionParser { String subElementLocalName = subElement.getLocalName(); if ("cache-listener".equals(subElementLocalName)) { - builder.addPropertyValue("cacheListeners", ParsingUtils.parseRefOrNestedBeanDeclaration( - parserContext, subElement, builder)); + regionBuilder.addPropertyValue("cacheListeners", ParsingUtils.parseRefOrNestedBeanDeclaration( + parserContext, subElement, regionBuilder)); } else if ("cache-loader".equals(subElementLocalName)) { - builder.addPropertyValue("cacheLoader", ParsingUtils.parseRefOrNestedBeanDeclaration( - parserContext, subElement, builder)); + regionBuilder.addPropertyValue("cacheLoader", ParsingUtils.parseRefOrNestedBeanDeclaration( + parserContext, subElement, regionBuilder)); } else if ("cache-writer".equals(subElementLocalName)) { - builder.addPropertyValue("cacheWriter", ParsingUtils.parseRefOrNestedBeanDeclaration( - parserContext, subElement, builder)); + regionBuilder.addPropertyValue("cacheWriter", ParsingUtils.parseRefOrNestedBeanDeclaration( + parserContext, subElement, regionBuilder)); } else if ("key-interest".equals(subElementLocalName)) { interests.add(parseKeyInterest(subElement, parserContext)); @@ -107,7 +109,7 @@ class ClientRegionParser extends AbstractRegionParser { } if (!interests.isEmpty()) { - builder.addPropertyValue("interests", interests); + regionBuilder.addPropertyValue("interests", interests); } if (!subRegion) { diff --git a/src/main/resources/org/springframework/data/gemfire/config/spring-gemfire-1.5.xsd b/src/main/resources/org/springframework/data/gemfire/config/spring-gemfire-1.5.xsd index e670dae5..1444c384 100644 --- a/src/main/resources/org/springframework/data/gemfire/config/spring-gemfire-1.5.xsd +++ b/src/main/resources/org/springframework/data/gemfire/config/spring-gemfire-1.5.xsd @@ -1905,6 +1905,16 @@ The action to take when performing eviction. + + + + + templateBasedClientRegion; + + protected void assertCacheListeners(final Region region, final String... expectedNames) { + assertNotNull(region); + assertNotNull(region.getAttributes()); + assertNotNull(region.getAttributes().getCacheListeners()); + assertEquals(expectedNames.length, region.getAttributes().getCacheListeners().length); + + for (CacheListener cacheListener : region.getAttributes().getCacheListeners()) { + assertTrue(cacheListener instanceof TestCacheListener); + assertTrue(Arrays.asList(expectedNames).contains(cacheListener.toString())); + } + } + + protected void assertCacheLoader(final Region region, final String expectedName) { + assertNotNull(region); + assertNotNull(region.getAttributes()); + assertTrue(region.getAttributes().getCacheLoader() instanceof TestCacheLoader); + assertEquals(expectedName, region.getAttributes().getCacheLoader().toString()); + } + + protected void assertCacheWriter(final Region region, final String expectedName) { + assertNotNull(region); + assertNotNull(region.getAttributes()); + assertTrue(region.getAttributes().getCacheWriter() instanceof TestCacheWriter); + assertEquals(expectedName, region.getAttributes().getCacheWriter().toString()); + } + + protected void assertDefaultEvictionAttributes(final EvictionAttributes evictionAttributes) { + assumeNotNull(evictionAttributes); + assertEvictionAttributes(evictionAttributes, EvictionAction.NONE, EvictionAlgorithm.NONE, 0, null); + } + + protected void assertEvictionAttributes(final EvictionAttributes evictionAttributes, + final EvictionAction expectedAction, + final EvictionAlgorithm expectedAlgorithm, + final int expectedMaximum, + final ObjectSizer expectedObjectSizer) + { + assertNotNull("The 'EvictionAttributes' must not be null!", evictionAttributes); + assertEquals(expectedAction, evictionAttributes.getAction()); + assertEquals(expectedAlgorithm, evictionAttributes.getAlgorithm()); + assertEquals(expectedMaximum, evictionAttributes.getMaximum()); + assertEquals(expectedObjectSizer, evictionAttributes.getObjectSizer()); + } + + protected void assertDefaultExpirationAttributes(final ExpirationAttributes expirationAttributes) { + assumeNotNull(expirationAttributes); + assertEquals(ExpirationAction.INVALIDATE, expirationAttributes.getAction()); + assertEquals(0, expirationAttributes.getTimeout()); + } + + protected void assertExpirationAttributes(final ExpirationAttributes expirationAttributes, + final ExpirationAction expectedAction, + final int expectedTimeout) + { + assertNotNull("The 'ExpirationAttributes' must not be null!", expirationAttributes); + assertEquals(expectedAction, expirationAttributes.getAction()); + assertEquals(expectedTimeout, expirationAttributes.getTimeout()); + } + + protected void assertDefaultRegionAttributes(final Region region) { + assertNotNull("The Region must not be null!", region); + assertNotNull(String.format("The Region (%1$s) must have 'RegionAttributes' defined!", + region.getFullPath()), region.getAttributes()); + assertNull(region.getAttributes().getCompressor()); + assertNull(region.getAttributes().getCustomEntryIdleTimeout()); + assertNull(region.getAttributes().getCustomEntryTimeToLive()); + assertNull(region.getAttributes().getDiskStoreName()); + assertFalse(region.getAttributes().getEnableGateway()); + assertNullEmpty(region.getAttributes().getGatewayHubId()); + assertFalse(region.getAttributes().getMulticastEnabled()); + assertDefaultExpirationAttributes(region.getAttributes().getRegionTimeToLive()); + assertDefaultExpirationAttributes(region.getAttributes().getRegionIdleTimeout()); + } + + protected static void assertEmpty(final Object[] array) { + assertTrue((array == null || array.length == 0)); + } + + protected static void assertEmpty(final Iterable collection) { + assertTrue(collection == null || !collection.iterator().hasNext()); + } + + protected static void assertNullEmpty(final String value) { + assertFalse(StringUtils.hasText(value)); + } + + protected static void assertRegionMetaData(final Region region, final String expectedRegionName) { + assertRegionMetaData(region, expectedRegionName, Region.SEPARATOR + expectedRegionName); + } + + protected static void assertRegionMetaData(final Region region, final String expectedRegionName, final String expectedRegionPath) { + assertNotNull(String.format("The '%1$s' Region was not properly configured and initialized!", + expectedRegionName), region); + assertEquals(expectedRegionName, region.getName()); + assertEquals(expectedRegionPath, region.getFullPath()); + assertNotNull(String.format("The '%1$s' Region must have RegionAttributes defined!", + expectedRegionName), region.getAttributes()); + } + + @Test + public void testTemplateBasedClientRegion() { + assertRegionMetaData(templateBasedClientRegion, "TemplateBasedClientRegion"); + assertDefaultRegionAttributes(templateBasedClientRegion); + assertCacheListeners(templateBasedClientRegion, "XYZ"); + assertCacheLoader(templateBasedClientRegion, "A"); + assertCacheWriter(templateBasedClientRegion, "B"); + assertFalse(templateBasedClientRegion.getAttributes().getCloningEnabled()); + assertFalse(templateBasedClientRegion.getAttributes().getConcurrencyChecksEnabled()); + assertEquals(16, templateBasedClientRegion.getAttributes().getConcurrencyLevel()); + assertEquals(DataPolicy.NORMAL, templateBasedClientRegion.getAttributes().getDataPolicy()); + assertFalse(templateBasedClientRegion.getAttributes().isDiskSynchronous()); + assertEvictionAttributes(templateBasedClientRegion.getAttributes().getEvictionAttributes(), + EvictionAction.OVERFLOW_TO_DISK, EvictionAlgorithm.LRU_ENTRY, 1024, null); + assertEquals(51, templateBasedClientRegion.getAttributes().getInitialCapacity()); + assertEquals(Integer.class, templateBasedClientRegion.getAttributes().getKeyConstraint()); + assertEquals("0.85", String.valueOf(templateBasedClientRegion.getAttributes().getLoadFactor())); + assertEquals("ServerPool", templateBasedClientRegion.getAttributes().getPoolName()); + assertTrue(templateBasedClientRegion.getAttributes().getStatisticsEnabled()); + assertEquals(Object.class, templateBasedClientRegion.getAttributes().getValueConstraint()); + templateBasedClientRegion.getInterestList(); + } + + 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 implements CacheLoader { + + private String name; + + public void setName(final String name) { + this.name = name; + } + + @Override + public Object load(final LoaderHelper loaderHelper) throws CacheLoaderException { + return null; + } + + @Override + public void close() { + } + + @Override + public String toString() { + return name; + } + } + + 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; + } + } + +} diff --git a/src/test/resources/org/springframework/data/gemfire/config/TemplateClientRegionNamespaceTest-context.xml b/src/test/resources/org/springframework/data/gemfire/config/TemplateClientRegionNamespaceTest-context.xml new file mode 100644 index 00000000..454a5dcf --- /dev/null +++ b/src/test/resources/org/springframework/data/gemfire/config/TemplateClientRegionNamespaceTest-context.xml @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +