diff --git a/src/main/java/org/springframework/data/gemfire/RegionFactoryBean.java b/src/main/java/org/springframework/data/gemfire/RegionFactoryBean.java index 427df3bc..ab37a03a 100644 --- a/src/main/java/org/springframework/data/gemfire/RegionFactoryBean.java +++ b/src/main/java/org/springframework/data/gemfire/RegionFactoryBean.java @@ -68,7 +68,7 @@ public class RegionFactoryBean extends RegionLookupFactoryBean imple private Boolean enableGateway; private Boolean persistent; - private CacheListener cacheListeners[]; + private CacheListener[] cacheListeners; private CacheLoader cacheLoader; diff --git a/src/main/java/org/springframework/data/gemfire/SubRegionFactoryBean.java b/src/main/java/org/springframework/data/gemfire/SubRegionFactoryBean.java index 67f37c9d..cdaa917c 100644 --- a/src/main/java/org/springframework/data/gemfire/SubRegionFactoryBean.java +++ b/src/main/java/org/springframework/data/gemfire/SubRegionFactoryBean.java @@ -21,50 +21,42 @@ import org.springframework.beans.factory.BeanInitializationException; import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.InitializingBean; import org.springframework.util.Assert; +import org.springframework.util.ObjectUtils; import com.gemstone.gemfire.cache.AttributesFactory; +import com.gemstone.gemfire.cache.CacheListener; import com.gemstone.gemfire.cache.Region; +import com.gemstone.gemfire.cache.asyncqueue.AsyncEventQueue; +import com.gemstone.gemfire.cache.wan.GatewaySender; @SuppressWarnings("deprecation") /** - * FactoryBean for creating a Gemfire Region as a subregion + * FactoryBean for creating a Gemfire Region as a sub-Region. + *

* @author David Turanski - * + * @author John Blum * @param - Region Key Type * @param - Region Value Type */ +// TODO why does this class extend the com.gemstone.gemfire.cache.AttributesFactory class? AttributesFactory is deprecated! public class SubRegionFactoryBean extends AttributesFactory implements FactoryBean>, InitializingBean { protected final Log log = LogFactory.getLog(getClass()); - @SuppressWarnings("unused") - private String name; - - private String regionName; - - private Region subRegion; - - private Region parent; - private boolean lookupOnly; - @Override - public void afterPropertiesSet() throws Exception { - Assert.notNull(parent, "parent region must not be null"); + private CacheListener[] cacheListeners; - this.subRegion = parent.getSubregion(regionName); - if (this.subRegion == null) { - if (lookupOnly) { - throw new BeanInitializationException("Cannot find region [" + regionName + "] in cache " - + parent.getRegionService()); - } - else { - log.debug("creating subregion of [" + ( parent.getFullPath() == null ? parent.getName() : parent.getFullPath()) + "] with name " + regionName); - this.subRegion = this.parent.createSubregion(regionName, create()); - } - } - } + private Object[] asyncEventQueues; + private Object[] gatewaySenders; + + private Region parentRegion; + private Region subRegion; + + @SuppressWarnings("unused") + private String name; + private String regionName; @Override public Region getObject() throws Exception { @@ -73,6 +65,7 @@ public class SubRegionFactoryBean extends AttributesFactory implemen @Override public Class getObjectType() { + // TODO perhaps this should be 'return (subRegion != null ? subRegion.getClass() : Region.class);' for consistency. return Region.class; } @@ -81,6 +74,81 @@ public class SubRegionFactoryBean extends AttributesFactory implemen return true; } + @Override + public void afterPropertiesSet() throws Exception { + Assert.notNull(parentRegion, "The parent Region cannot be null."); + + this.subRegion = parentRegion.getSubregion(regionName); + + if (this.subRegion == null) { + if (lookupOnly) { + throw new BeanInitializationException(String.format("Cannot find Region [%1$s] in Cache %2$s", + regionName, parentRegion.getRegionService())); + } + else { + log.debug(String.format("Creating sub-Region of [%1$s] with name [%2$s]...", + (parentRegion.getFullPath() != null ? parentRegion.getFullPath() : parentRegion.getName()), + regionName)); + + if (!ObjectUtils.isEmpty(asyncEventQueues)) { + for (Object asyncEventQueue : asyncEventQueues) { + addAsyncEventQueueId(((AsyncEventQueue) asyncEventQueue).getId()); + } + } + + if (!ObjectUtils.isEmpty(cacheListeners)) { + for (CacheListener listener : cacheListeners) { + addCacheListener(listener); + } + } + + if (!ObjectUtils.isEmpty(gatewaySenders)) { + for (Object gatewaySender : gatewaySenders) { + addGatewaySenderId(((GatewaySender) gatewaySender).getId()); + } + } + + this.subRegion = this.parentRegion.createSubregion(regionName, create()); + } + } + } + + /** + * + * @param asyncEventQueues defined as Object for backward compatibility with Gemfire 6. + */ + public void setAsyncEventQueues(Object[] asyncEventQueues) { + this.asyncEventQueues = asyncEventQueues; + } + + /** + * Sets the cache listeners used for the region used by this factory. Used + * only when a new region is created.Overrides the settings specified + * through {@link #setAttributes(com.gemstone.gemfire.cache.RegionAttributes)}. + * + * @param cacheListeners the cacheListeners to set on a newly created region + */ + public void setCacheListeners(CacheListener[] cacheListeners) { + this.cacheListeners = cacheListeners; + } + + /** + * + * @param gatewaySenders + */ + public void setGatewaySenders(Object[] gatewaySenders) { + this.gatewaySenders = gatewaySenders; + } + + /** + * Set to true if the subregion should already exist, e.g., specified by + * <lookup-region> + * @param lookupOnly + */ + public void setLookupOnly(boolean lookupOnly) { + this.lookupOnly = lookupOnly; + } + /** * Set the bean name - the same as the subregion full path * @param name @@ -102,16 +170,7 @@ public class SubRegionFactoryBean extends AttributesFactory implemen * @param parent */ public void setParent(Region parent) { - this.parent = parent; - } - - /** - * Set to true if the subregion should already exist, e.g., specified by - * <lookup-region> - * @param lookupOnly - */ - public void setLookupOnly(boolean lookupOnly) { - this.lookupOnly = lookupOnly; + this.parentRegion = parent; } } diff --git a/src/test/java/org/springframework/data/gemfire/config/SubRegionSubElementNamespaceTest.java b/src/test/java/org/springframework/data/gemfire/config/SubRegionSubElementNamespaceTest.java new file mode 100644 index 00000000..acae2f6c --- /dev/null +++ b/src/test/java/org/springframework/data/gemfire/config/SubRegionSubElementNamespaceTest.java @@ -0,0 +1,111 @@ +/* + * 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.assertNotNull; +import static org.junit.Assert.assertTrue; + +import java.util.List; +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 com.gemstone.gemfire.cache.CacheListener; +import com.gemstone.gemfire.cache.Region; +import com.gemstone.gemfire.cache.asyncqueue.AsyncEvent; +import com.gemstone.gemfire.cache.asyncqueue.AsyncEventListener; +import com.gemstone.gemfire.cache.util.CacheListenerAdapter; + +/** + * The SubRegionSubElementNamespaceTest class... + *

+ * @author John Blum + * @see org.junit.Test + * @see org.springframework.test.context.ContextConfiguration + * @see org.springframework.test.context.junit4.SpringJUnit4ClassRunner + * @link https://jira.springsource.org/browse/SGF-219 + * @link https://jira.springsource.org/browse/SGF-220 + * @link https://jira.springsource.org/browse/SGF-221 + * @since 1.3.3 + */ +@ContextConfiguration(locations = "subregionsubelement-ns.xml", + initializers = GemfireTestApplicationContextInitializer.class) +@RunWith(SpringJUnit4ClassRunner.class) +@SuppressWarnings("unused") +public class SubRegionSubElementNamespaceTest { + + @Resource(name = "/Customers/Accounts") + private Region customersAccountsRegion; + + @Resource(name = "/Orders/Items") + private Region orderItemsRegion; + + @Resource(name = "/Parent/Child") + private Region parentChildRegion; + + @Test + public void testCustomersAccountsSubRegionCacheListener() { + assertNotNull(customersAccountsRegion); + assertNotNull(customersAccountsRegion.getAttributes()); + assertNotNull(customersAccountsRegion.getAttributes().getCacheListeners()); + + boolean found = false; + + for (CacheListener listener : customersAccountsRegion.getAttributes().getCacheListeners()) { + found |= (listener instanceof TestNoOpCacheListener); + } + + assertTrue(String.format("Expected a GemFire CacheListener of type (%1$s) to be registered on Region (%2$s)!", + TestNoOpCacheListener.class.getName(), customersAccountsRegion.getName()), found); + } + + @Test + public void testOrderItemsSubRegionGatewaySender() { + assertNotNull(orderItemsRegion); + assertNotNull(orderItemsRegion.getAttributes()); + assertNotNull(orderItemsRegion.getAttributes().getGatewaySenderIds()); + assertTrue(orderItemsRegion.getAttributes().getGatewaySenderIds().contains("testSender")); + } + + @Test + public void testParentChildSubRegionAsyncEventQueue() { + assertNotNull(parentChildRegion); + assertNotNull(parentChildRegion.getAttributes()); + assertNotNull(parentChildRegion.getAttributes().getAsyncEventQueueIds()); + assertTrue(parentChildRegion.getAttributes().getAsyncEventQueueIds().contains("testQueue")); + } + + public static final class TestNoOpCacheListener extends CacheListenerAdapter { + } + + public static final class TestNoOpAsyncEventListener implements AsyncEventListener { + + @Override + public boolean processEvents(final List events) { + throw new UnsupportedOperationException("Not Implemented!"); + } + + @Override + public void close() { + } + } + +} diff --git a/src/test/resources/org/springframework/data/gemfire/config/subregionsubelement-ns.xml b/src/test/resources/org/springframework/data/gemfire/config/subregionsubelement-ns.xml new file mode 100644 index 00000000..9dca5d0a --- /dev/null +++ b/src/test/resources/org/springframework/data/gemfire/config/subregionsubelement-ns.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +