diff --git a/src/main/java/org/springframework/data/gemfire/PeerRegionFactoryBean.java b/src/main/java/org/springframework/data/gemfire/PeerRegionFactoryBean.java index 93c07c0d..ca190d05 100644 --- a/src/main/java/org/springframework/data/gemfire/PeerRegionFactoryBean.java +++ b/src/main/java/org/springframework/data/gemfire/PeerRegionFactoryBean.java @@ -57,6 +57,7 @@ import org.springframework.core.io.Resource; import org.springframework.data.gemfire.client.ClientRegionFactoryBean; import org.springframework.data.gemfire.eviction.EvictingRegionFactoryBean; import org.springframework.data.gemfire.expiration.ExpiringRegionFactoryBean; +import org.springframework.data.gemfire.util.CollectionUtils; import org.springframework.data.gemfire.util.RegionUtils; import org.springframework.util.Assert; import org.springframework.util.ObjectUtils; @@ -410,9 +411,13 @@ public abstract class PeerRegionFactoryBean extends ConfigurableRegionFact if (regionAttributes != null) { - // NOTE: this validation may not be strictly necessary depending on how the RegionAttributes were "created", + // NOTE: this validation may not be strictly necessary depending on how the RegionAttributes were "created". validateRegionAttributes(regionAttributes); + CollectionUtils.nullSafeSet(regionAttributes.getAsyncEventQueueIds()).stream() + .filter(StringUtils::hasText) + .forEach(regionFactory::addAsyncEventQueueId); + regionFactory.setCloningEnabled(regionAttributes.getCloningEnabled()); regionFactory.setCompressor(regionAttributes.getCompressor()); regionFactory.setConcurrencyChecksEnabled(regionAttributes.getConcurrencyChecksEnabled()); @@ -430,6 +435,10 @@ public abstract class PeerRegionFactoryBean extends ConfigurableRegionFact regionFactory.setEvictionAttributes(regionAttributes.getEvictionAttributes()); } + CollectionUtils.nullSafeSet(regionAttributes.getGatewaySenderIds()).stream() + .filter(StringUtils::hasText) + .forEach(regionFactory::addGatewaySenderId); + regionFactory.setIgnoreJTA(regionAttributes.getIgnoreJTA()); regionFactory.setIndexMaintenanceSynchronous(regionAttributes.getIndexMaintenanceSynchronous()); regionFactory.setInitialCapacity(regionAttributes.getInitialCapacity()); diff --git a/src/main/java/org/springframework/data/gemfire/RegionAttributesFactoryBean.java b/src/main/java/org/springframework/data/gemfire/RegionAttributesFactoryBean.java index e875e078..4a0339e1 100644 --- a/src/main/java/org/springframework/data/gemfire/RegionAttributesFactoryBean.java +++ b/src/main/java/org/springframework/data/gemfire/RegionAttributesFactoryBean.java @@ -13,13 +13,17 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.springframework.data.gemfire; +import java.util.Arrays; + import org.apache.geode.cache.AttributesFactory; import org.apache.geode.cache.RegionAttributes; + import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.InitializingBean; +import org.springframework.data.gemfire.util.ArrayUtils; +import org.springframework.util.StringUtils; /** * Spring-friendly bean for creating {@link RegionAttributes}. Eliminates the need of using a XML 'factory-method' tag. @@ -32,10 +36,10 @@ import org.springframework.beans.factory.InitializingBean; * @see org.apache.geode.cache.RegionAttributes */ @SuppressWarnings({ "unused" }) -public class RegionAttributesFactoryBean extends AttributesFactory +public class RegionAttributesFactoryBean extends AttributesFactory implements FactoryBean, InitializingBean { - private RegionAttributes regionAttributes; + private RegionAttributes regionAttributes; @Override public void afterPropertiesSet() throws Exception { @@ -43,13 +47,16 @@ public class RegionAttributesFactoryBean extends AttributesFactory } @Override - public RegionAttributes getObject() throws Exception { + public RegionAttributes getObject() throws Exception { return this.regionAttributes; } @Override public Class getObjectType() { - return this.regionAttributes != null ? this.regionAttributes.getClass() : RegionAttributes.class; + + return this.regionAttributes != null + ? this.regionAttributes.getClass() + : RegionAttributes.class; } @Override @@ -57,7 +64,23 @@ public class RegionAttributesFactoryBean extends AttributesFactory return true; } + public void setAsyncEventQueueIds(String[] asyncEventQueueIds) { + + Arrays.stream(ArrayUtils.nullSafeArray(asyncEventQueueIds, String.class)) + .filter(StringUtils::hasText) + .map(String::trim) + .forEach(this::addAsyncEventQueueId); + } + public void setIndexUpdateType(IndexMaintenancePolicyType indexUpdateType) { indexUpdateType.setIndexMaintenance(this); } + + public void setGatewaySenderIds(String[] gatewaySenderIds) { + + Arrays.stream(ArrayUtils.nullSafeArray(gatewaySenderIds, String.class)) + .filter(StringUtils::hasText) + .map(String::trim) + .forEach(this::addGatewaySenderId); + } } diff --git a/src/main/java/org/springframework/data/gemfire/config/xml/AbstractRegionParser.java b/src/main/java/org/springframework/data/gemfire/config/xml/AbstractRegionParser.java index 7fe826b2..f50b7a96 100644 --- a/src/main/java/org/springframework/data/gemfire/config/xml/AbstractRegionParser.java +++ b/src/main/java/org/springframework/data/gemfire/config/xml/AbstractRegionParser.java @@ -111,7 +111,9 @@ abstract class AbstractRegionParser extends AbstractSingleBeanDefinitionParser { String resolvedCacheReference = ParsingUtils.resolveCacheReference(element.getAttribute("cache-ref")); if (!subRegion) { + regionBuilder.addPropertyReference("cache", resolvedCacheReference); + ParsingUtils.setPropertyValue(element, regionBuilder, "close"); ParsingUtils.setPropertyValue(element, regionBuilder, "destroy"); } diff --git a/src/main/java/org/springframework/data/gemfire/config/xml/TemplateRegionParser.java b/src/main/java/org/springframework/data/gemfire/config/xml/TemplateRegionParser.java index 55d78e77..2fe2682c 100644 --- a/src/main/java/org/springframework/data/gemfire/config/xml/TemplateRegionParser.java +++ b/src/main/java/org/springframework/data/gemfire/config/xml/TemplateRegionParser.java @@ -13,24 +13,28 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.springframework.data.gemfire.config.xml; 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.PeerRegionFactoryBean; +import org.springframework.data.gemfire.RegionAttributesFactoryBean; + import org.w3c.dom.Element; /** * Bean definition parser for <gfe:*-region-template> SDG XML namespace (XSD) elements. * * @author John Blum - * @see PeerRegionFactoryBean - * @see AbstractRegionParser + * @see org.springframework.beans.factory.support.BeanDefinitionBuilder + * @see org.springframework.beans.factory.xml.ParserContext + * @see org.springframework.data.gemfire.PeerRegionFactoryBean + * @see org.springframework.data.gemfire.RegionAttributesFactoryBean + * @see org.springframework.data.gemfire.config.xml.AbstractRegionParser + * @see org.w3c.dom.Element * @since 1.5.0 */ -class TemplateRegionParser extends AbstractRegionParser { +class TemplateRegionParser extends AbstractPeerRegionParser { /** * {@inheritDoc} @@ -46,8 +50,9 @@ class TemplateRegionParser extends AbstractRegionParser { @Override protected void doParseRegion(Element element, ParserContext parserContext, BeanDefinitionBuilder builder, boolean subRegion) { - BeanDefinitionBuilder regionAttributesBuilder = BeanDefinitionBuilder.genericBeanDefinition( - RegionAttributesFactoryBean.class); + + BeanDefinitionBuilder regionAttributesBuilder = + BeanDefinitionBuilder.genericBeanDefinition(RegionAttributesFactoryBean.class); doParseRegionConfiguration(element, parserContext, builder, regionAttributesBuilder, subRegion); diff --git a/src/test/java/org/springframework/data/gemfire/wan/RegionsWithAsyncEventQueuesAndGatewaySendersUnitTests.java b/src/test/java/org/springframework/data/gemfire/wan/RegionsWithAsyncEventQueuesAndGatewaySendersUnitTests.java new file mode 100644 index 00000000..ce13a2b5 --- /dev/null +++ b/src/test/java/org/springframework/data/gemfire/wan/RegionsWithAsyncEventQueuesAndGatewaySendersUnitTests.java @@ -0,0 +1,135 @@ +/* + * Copyright 2018 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 + * + * https://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.wan; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; + +import javax.annotation.Resource; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import org.apache.geode.cache.DataPolicy; +import org.apache.geode.cache.Region; +import org.apache.geode.cache.RegionAttributes; +import org.apache.geode.cache.asyncqueue.AsyncEventListener; + +import org.springframework.data.gemfire.support.AbstractFactoryBeanSupport; +import org.springframework.lang.Nullable; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringRunner; + +/** + * The RegionsWithAsyncEventQueuesAndGatewaySendersUnitTests class... + * + * @author John Blum + * @since 1.0.0 + */ +@RunWith(SpringRunner.class) +@ContextConfiguration +@SuppressWarnings("unused") +public class RegionsWithAsyncEventQueuesAndGatewaySendersUnitTests { + + @Resource(name = "TemplateBasedLocalRegion") + private Region templateBasedLocalRegion; + + @Resource(name = "LocalRegion") + private Region localRegion; + + @Resource(name = "PartitionRegion") + private Region partitionRegion; + + @Resource(name = "ReplicateRegion") + private Region replicateRegion; + + private void assertRegion(Region region, String name, DataPolicy dataPolicy) { + + assertThat(region).isNotNull(); + assertThat(region.getName()).isEqualTo(name); + + RegionAttributes regionAttributes = region.getAttributes(); + + assertThat(regionAttributes).isNotNull(); + assertThat(regionAttributes.getDataPolicy()).isEqualTo(dataPolicy); + } + + @Test + public void templateBasedlocalRegionConfigurationIsCorrect() { + + assertRegion(this.templateBasedLocalRegion, "TemplateBasedLocalRegion", DataPolicy.NORMAL); + + assertThat(this.templateBasedLocalRegion.getAttributes().getAsyncEventQueueIds()) + .containsExactlyInAnyOrder("X", "Y", "Z"); + + assertThat(this.templateBasedLocalRegion.getAttributes().getGatewaySenderIds()) + .containsExactlyInAnyOrder("99", "100", "101"); + } + + @Test + public void localRegionConfigurationIsCorrect() { + + assertRegion(this.localRegion, "LocalRegion", DataPolicy.NORMAL); + + assertThat(this.localRegion.getAttributes().getAsyncEventQueueIds()) + .containsExactlyInAnyOrder("A", "B", "C", "D", "E"); + + assertThat(this.localRegion.getAttributes().getGatewaySenderIds()) + .containsExactlyInAnyOrder("1", "2", "3", "4", "5"); + } + + @Test + public void partitionRegionConfigurationIsCorrect() { + + assertRegion(this.partitionRegion, "PartitionRegion", DataPolicy.PARTITION); + + assertThat(this.partitionRegion.getAttributes().getAsyncEventQueueIds()) + .containsExactlyInAnyOrder("E", "F", "G", "H", "I"); + + assertThat(this.partitionRegion.getAttributes().getGatewaySenderIds()) + .containsExactlyInAnyOrder("5", "6", "7", "8", "9"); + } + + @Test + public void sreplicateRegionConfigurationIsCorrect() { + + assertRegion(this.replicateRegion, "ReplicateRegion", DataPolicy.REPLICATE); + + assertThat(this.replicateRegion.getAttributes().getAsyncEventQueueIds()) + .containsExactlyInAnyOrder("E", "J", "K", "L", "M"); + + assertThat(this.replicateRegion.getAttributes().getGatewaySenderIds()) + .containsExactlyInAnyOrder("5", "10", "11", "12", "13"); + } + + public static final class AsyncEventListenerFactoryBean extends AbstractFactoryBeanSupport { + + private final AsyncEventListener mockAsyncEventListener = mock(AsyncEventListener.class); + + @Nullable @Override + public AsyncEventListener getObject() { + return this.mockAsyncEventListener; + } + + @Nullable @Override + public Class getObjectType() { + + return this.mockAsyncEventListener != null + ? this.mockAsyncEventListener.getClass() + : AsyncEventListener.class; + } + } +} diff --git a/src/test/resources/org/springframework/data/gemfire/wan/RegionsWithAsyncEventQueuesAndGatewaySendersUnitTests-context.xml b/src/test/resources/org/springframework/data/gemfire/wan/RegionsWithAsyncEventQueuesAndGatewaySendersUnitTests-context.xml new file mode 100644 index 00000000..08520d01 --- /dev/null +++ b/src/test/resources/org/springframework/data/gemfire/wan/RegionsWithAsyncEventQueuesAndGatewaySendersUnitTests-context.xml @@ -0,0 +1,90 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +