diff --git a/src/main/java/org/springframework/data/gemfire/CacheFactoryBean.java b/src/main/java/org/springframework/data/gemfire/CacheFactoryBean.java index ea8ccaf4..a3f05f39 100644 --- a/src/main/java/org/springframework/data/gemfire/CacheFactoryBean.java +++ b/src/main/java/org/springframework/data/gemfire/CacheFactoryBean.java @@ -89,6 +89,7 @@ public class CacheFactoryBean implements BeanNameAware, BeanFactoryAware, BeanCl protected BeanFactory beanFactory; protected Boolean copyOnRead; + protected Boolean enableAutoReconnect; protected Boolean pdxIgnoreUnreadFields; protected Boolean pdxPersistent; protected Boolean pdxReadSerialized; @@ -258,16 +259,14 @@ public class CacheFactoryBean implements BeanNameAware, BeanFactoryAware, BeanCl catch (CacheClosedException ex) { initializeDynamicRegionFactory(); - Object factory = createFactory(this.properties); + Object factory = createFactory(getProperties()); - // GemFire 6.6 specific options if (isPdxSettingsSpecified()) { Assert.isTrue(ClassUtils.isPresent("com.gemstone.gemfire.pdx.PdxSerializer", beanClassLoader), "Cannot set PDX options since GemFire 6.6 not detected."); applyPdxOptions(factory); } - // fall back to cache creation cache = (Cache) createCache(factory); messagePrefix = "Created new"; } @@ -275,20 +274,20 @@ public class CacheFactoryBean implements BeanNameAware, BeanFactoryAware, BeanCl if (this.copyOnRead != null) { cache.setCopyOnRead(this.copyOnRead); } + if (gatewayConflictResolver != null) { + cache.setGatewayConflictResolver((GatewayConflictResolver) gatewayConflictResolver); + } if (lockLease != null) { cache.setLockLease(lockLease); } if (lockTimeout != null) { cache.setLockTimeout(lockTimeout); } - if (searchTimeout != null) { - cache.setSearchTimeout(searchTimeout); - } if (messageSyncInterval != null) { cache.setMessageSyncInterval(messageSyncInterval); } - if (gatewayConflictResolver != null) { - cache.setGatewayConflictResolver((GatewayConflictResolver) gatewayConflictResolver); + if (searchTimeout != null) { + cache.setSearchTimeout(searchTimeout); } DistributedSystem system = cache.getDistributedSystem(); @@ -306,7 +305,7 @@ public class CacheFactoryBean implements BeanNameAware, BeanFactoryAware, BeanCl cache.loadCacheXml(cacheXml.getInputStream()); if (log.isDebugEnabled()) { - log.debug("Initialized cache from " + cacheXml); + log.debug(String.format("Initialized Cache from '%1$s'.", cacheXml)); } } @@ -404,12 +403,12 @@ public class CacheFactoryBean implements BeanNameAware, BeanFactoryAware, BeanCl return (cache != null ? cache : ((CacheFactory) factory).create()); } - protected GemFireCache fetchCache() { - return (cache != null ? cache : CacheFactory.getAnyInstance()); + protected Object createFactory(Properties gemfireProperties) { + return new CacheFactory(gemfireProperties); } - protected Object createFactory(Properties props) { - return new CacheFactory(props); + protected GemFireCache fetchCache() { + return (cache != null ? cache : CacheFactory.getAnyInstance()); } @Override @@ -481,6 +480,15 @@ public class CacheFactoryBean implements BeanNameAware, BeanFactoryAware, BeanCl this.beanName = name; } + /** + * Sets the cache configuration. + * + * @param cacheXml the cacheXml to set + */ + public void setCacheXml(Resource cacheXml) { + this.cacheXml = cacheXml; + } + /** * Sets the cache properties. * @@ -491,12 +499,10 @@ public class CacheFactoryBean implements BeanNameAware, BeanFactoryAware, BeanCl } /** - * Sets the cache configuration. - * - * @param cacheXml the cacheXml to set + * @param lazyInitialize set to false to force cache initialization if no other bean references it */ - public void setCacheXml(Resource cacheXml) { - this.cacheXml = cacheXml; + public void setLazyInitialize(boolean lazyInitialize) { + this.lazyInitialize = lazyInitialize; } /** @@ -512,6 +518,10 @@ public class CacheFactoryBean implements BeanNameAware, BeanFactoryAware, BeanCl this.useBeanFactoryLocator = usage; } + public void setEnableAutoReconnect(final Boolean enableAutoReconnect) { + this.enableAutoReconnect = enableAutoReconnect; + } + /** * Sets the {@link PdxSerializable} for this cache. Applicable on GemFire * 6.6 or higher. The argument is of type object for compatibility with @@ -701,10 +711,17 @@ public class CacheFactoryBean implements BeanNameAware, BeanFactoryAware, BeanCl } /** - * @param lazyInitialize set to false to force cache initialization if no other bean references it + * @return the beanClassLoader */ - public void setLazyInitialize(boolean lazyInitialize) { - this.lazyInitialize = lazyInitialize; + public ClassLoader getBeanClassLoader() { + return beanClassLoader; + } + + /** + * @return the beanName + */ + public String getBeanName() { + return beanName; } /** @@ -718,21 +735,15 @@ public class CacheFactoryBean implements BeanNameAware, BeanFactoryAware, BeanCl * @return the properties */ public Properties getProperties() { + if (properties == null) { + properties = new Properties(); + } + return properties; } - /** - * @return the beanClassLoader - */ - public ClassLoader getBeanClassLoader() { - return beanClassLoader; - } - - /** - * @return the beanName - */ - public String getBeanName() { - return beanName; + public Boolean getEnableAutoReconnect() { + return enableAutoReconnect; } /** @@ -864,12 +875,19 @@ public class CacheFactoryBean implements BeanNameAware, BeanFactoryAware, BeanCl return lazyInitialize; } + protected void postProcessPropertiesBeforeInitialization(Properties gemfireProperties) { + gemfireProperties.setProperty("disable-auto-reconnect", String.valueOf( + !Boolean.TRUE.equals(getEnableAutoReconnect()))); + } + /* (non-Javadoc) * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet() */ @Override public void afterPropertiesSet() throws Exception { - if (!lazyInitialize) { + postProcessPropertiesBeforeInitialization(getProperties()); + + if (!isLazyInitialize()) { init(); } } diff --git a/src/main/java/org/springframework/data/gemfire/client/ClientCacheFactoryBean.java b/src/main/java/org/springframework/data/gemfire/client/ClientCacheFactoryBean.java index 5f16be45..4d7d4466 100644 --- a/src/main/java/org/springframework/data/gemfire/client/ClientCacheFactoryBean.java +++ b/src/main/java/org/springframework/data/gemfire/client/ClientCacheFactoryBean.java @@ -86,11 +86,12 @@ public class ClientCacheFactoryBean extends CacheFactoryBean { @Override protected GemFireCache createCache(Object factory) { - ClientCacheFactory ccf = (ClientCacheFactory) factory; - initializePool(ccf); + ClientCacheFactory clientCacheFactory = (ClientCacheFactory) factory; + + initializePool(clientCacheFactory); // Now create the cache - GemFireCache cache = ccf.create(); + GemFireCache cache = clientCacheFactory.create(); // Register for events after pool/regions been created and iff non-durable client readyForEvents(); @@ -100,8 +101,8 @@ public class ClientCacheFactoryBean extends CacheFactoryBean { } @Override - protected Object createFactory(Properties props) { - return new ClientCacheFactory(props); + protected Object createFactory(Properties gemfireProperties) { + return new ClientCacheFactory(gemfireProperties); } @Override @@ -109,10 +110,6 @@ public class ClientCacheFactoryBean extends CacheFactoryBean { return ClientCacheFactory.getAnyInstance(); } - public Properties getProperties() { - return this.properties; - } - private void initializePool(ClientCacheFactory ccf) { Pool p = pool; @@ -189,20 +186,18 @@ public class ClientCacheFactoryBean extends CacheFactoryBean { } } - /** - * Inform the GemFire cluster that this client cache is ready to receive events. - */ - private void readyForEvents(){ - ClientCache clientCache = ClientCacheFactory.getAnyInstance(); + @Override + protected void postProcessPropertiesBeforeInitialization(final Properties gemfireProperties) { + } - if (Boolean.TRUE.equals(readyForEvents) && !clientCache.isClosed()) { - try { - clientCache.readyForEvents(); - } - catch (IllegalStateException ignore) { - // Cannot be called for a non-durable client so exception is thrown. - } - } + @Override + public final Boolean getEnableAutoReconnect() { + return Boolean.FALSE; + } + + @Override + public final void setEnableAutoReconnect(final Boolean enableAutoReconnect) { + throw new UnsupportedOperationException("Auto-reconnect is not supported on ClientCache."); } /** @@ -235,11 +230,11 @@ public class ClientCacheFactoryBean extends CacheFactoryBean { public void setReadyForEvents(Boolean readyForEvents){ this.readyForEvents = readyForEvents; } - + public Boolean getReadyForEvents(){ return this.readyForEvents; } - + @Override protected void applyPdxOptions(Object factory) { if (factory instanceof ClientCacheFactory) { @@ -247,4 +242,20 @@ public class ClientCacheFactoryBean extends CacheFactoryBean { } } + /** + * Inform the GemFire cluster that this client cache is ready to receive events. + */ + private void readyForEvents(){ + ClientCache clientCache = ClientCacheFactory.getAnyInstance(); + + if (Boolean.TRUE.equals(readyForEvents) && !clientCache.isClosed()) { + try { + clientCache.readyForEvents(); + } + catch (IllegalStateException ignore) { + // cannot be called for a non-durable client so exception is thrown + } + } + } + } diff --git a/src/main/java/org/springframework/data/gemfire/config/CacheParser.java b/src/main/java/org/springframework/data/gemfire/config/CacheParser.java index 0e186183..258b1e67 100644 --- a/src/main/java/org/springframework/data/gemfire/config/CacheParser.java +++ b/src/main/java/org/springframework/data/gemfire/config/CacheParser.java @@ -56,49 +56,54 @@ class CacheParser extends AbstractSimpleBeanDefinitionParser { ParsingUtils.setPropertyValue(element, builder, "cache-xml-location", "cacheXml"); ParsingUtils.setPropertyReference(element, builder, "properties-ref", "properties"); - ParsingUtils.setPropertyReference(element, builder, "pdx-serializer-ref", "pdxSerializer"); - parsePdxDiskStore(element, parserContext, builder); - ParsingUtils.setPropertyValue(element, builder, "pdx-persistent"); - ParsingUtils.setPropertyValue(element, builder, "pdx-read-serialized"); - ParsingUtils.setPropertyValue(element, builder, "pdx-ignore-unread-fields"); - ParsingUtils.setPropertyValue(element, builder, "use-bean-factory-locator"); + ParsingUtils.setPropertyValue(element, builder, "close"); ParsingUtils.setPropertyValue(element, builder, "copy-on-read"); - ParsingUtils.setPropertyValue(element, builder, "lock-timeout"); - ParsingUtils.setPropertyValue(element, builder, "lock-lease"); - ParsingUtils.setPropertyValue(element, builder, "message-sync-interval"); - ParsingUtils.setPropertyValue(element, builder, "search-timeout"); ParsingUtils.setPropertyValue(element, builder, "critical-heap-percentage"); ParsingUtils.setPropertyValue(element, builder, "eviction-heap-percentage"); - ParsingUtils.setPropertyValue(element, builder, "close"); + ParsingUtils.setPropertyValue(element, builder, "enable-auto-reconnect"); + ParsingUtils.setPropertyValue(element, builder, "lock-lease"); + ParsingUtils.setPropertyValue(element, builder, "lock-timeout"); + ParsingUtils.setPropertyValue(element, builder, "message-sync-interval"); + ParsingUtils.setPropertyReference(element, builder, "pdx-serializer-ref", "pdxSerializer"); + ParsingUtils.setPropertyValue(element, builder, "pdx-read-serialized"); + ParsingUtils.setPropertyValue(element, builder, "pdx-ignore-unread-fields"); + ParsingUtils.setPropertyValue(element, builder, "pdx-persistent"); + parsePdxDiskStore(element, parserContext, builder); + ParsingUtils.setPropertyValue(element, builder, "search-timeout"); ParsingUtils.setPropertyValue(element, builder, "lazy-init","lazyInitialize"); + ParsingUtils.setPropertyValue(element, builder, "use-bean-factory-locator"); List txListeners = DomUtils.getChildElementsByTagName(element, "transaction-listener"); + if (!CollectionUtils.isEmpty(txListeners)) { ManagedList transactionListeners = new ManagedList(); for (Element txListener : txListeners) { - transactionListeners.add(ParsingUtils.parseRefOrNestedBeanDeclaration(parserContext, txListener, - builder)); + transactionListeners.add(ParsingUtils.parseRefOrNestedBeanDeclaration( + parserContext, txListener, builder)); } builder.addPropertyValue("transactionListeners", transactionListeners); } + Element txWriter = DomUtils.getChildElementByTagName(element, "transaction-writer"); + if (txWriter != null) { - builder.addPropertyValue("transactionWriter", - ParsingUtils.parseRefOrNestedBeanDeclaration(parserContext, txWriter, builder)); + builder.addPropertyValue("transactionWriter", ParsingUtils.parseRefOrNestedBeanDeclaration( + parserContext, txWriter, builder)); } Element gatewayConflictResolver = DomUtils.getChildElementByTagName(element, "gateway-conflict-resolver"); + if (gatewayConflictResolver != null) { - ParsingUtils.throwExceptionIfNotGemfireV7(element.getLocalName(), "gateway-conflict-resolver", - parserContext); - builder.addPropertyValue("gatewayConflictResolver", - ParsingUtils.parseRefOrSingleNestedBeanDeclaration(parserContext, gatewayConflictResolver, builder)); + ParsingUtils.throwExceptionIfNotGemfireV7(element.getLocalName(), "gateway-conflict-resolver", parserContext); + builder.addPropertyValue("gatewayConflictResolver", ParsingUtils.parseRefOrSingleNestedBeanDeclaration( + parserContext, gatewayConflictResolver, builder)); } Element function = DomUtils.getChildElementByTagName(element, "function"); + if (function != null) { - builder.addPropertyValue("functions", - ParsingUtils.parseRefOrNestedBeanDeclaration(parserContext, function, builder)); + builder.addPropertyValue("functions", ParsingUtils.parseRefOrNestedBeanDeclaration( + parserContext, function, builder)); } parseDynamicRegionFactory(element, builder); @@ -130,6 +135,7 @@ class CacheParser extends AbstractSimpleBeanDefinitionParser { private void parseDynamicRegionFactory(Element element, BeanDefinitionBuilder builder) { Element dynamicRegionFactory = DomUtils.getChildElementByTagName(element, "dynamic-region-factory"); + if (dynamicRegionFactory != null) { BeanDefinitionBuilder dynamicRegionSupport = buildDynamicRegionSupport(dynamicRegionFactory); postProcessDynamicRegionSupport(element, dynamicRegionSupport); @@ -137,35 +143,40 @@ class CacheParser extends AbstractSimpleBeanDefinitionParser { } } - /** - * @param dynamicRegionSupport BDB for <dynamic-region-factory> - * element - */ - protected void postProcessDynamicRegionSupport(Element element, BeanDefinitionBuilder dynamicRegionSupport) { - - } - private BeanDefinitionBuilder buildDynamicRegionSupport(Element dynamicRegionFactory) { - BeanDefinitionBuilder result = null; if (dynamicRegionFactory != null) { - BeanDefinitionBuilder dynamicRegionSupport = BeanDefinitionBuilder - .genericBeanDefinition(CacheFactoryBean.DynamicRegionSupport.class); - String diskDir = dynamicRegionFactory.getAttribute("disk-dir"); - if (StringUtils.hasText(diskDir)) { - dynamicRegionSupport.addPropertyValue("diskDir", diskDir); + BeanDefinitionBuilder dynamicRegionSupport = BeanDefinitionBuilder.genericBeanDefinition( + CacheFactoryBean.DynamicRegionSupport.class); + + String diskDirectory = dynamicRegionFactory.getAttribute("disk-dir"); + + if (StringUtils.hasText(diskDirectory)) { + dynamicRegionSupport.addPropertyValue("diskDir", diskDirectory); } + String persistent = dynamicRegionFactory.getAttribute("persistent"); + if (StringUtils.hasText(persistent)) { dynamicRegionSupport.addPropertyValue("persistent", persistent); } String registerInterest = dynamicRegionFactory.getAttribute("register-interest"); + if (StringUtils.hasText(registerInterest)) { dynamicRegionSupport.addPropertyValue("registerInterest", registerInterest); } - result = dynamicRegionSupport; + + return dynamicRegionSupport; } - return result; + + return null; + } + + /** + * @param dynamicRegionSupport BDB for <dynamic-region-factory> + * element + */ + protected void postProcessDynamicRegionSupport(Element element, BeanDefinitionBuilder dynamicRegionSupport) { } private void parseJndiBindings(Element element, BeanDefinitionBuilder builder) { @@ -222,11 +233,13 @@ class CacheParser extends AbstractSimpleBeanDefinitionParser { protected String resolveId(Element element, AbstractBeanDefinition definition, ParserContext parserContext) throws BeanDefinitionStoreException { String name = super.resolveId(element, definition, parserContext); + if (!StringUtils.hasText(name)) { name = GemfireConstants.DEFAULT_GEMFIRE_CACHE_NAME; - //For backward compatibility - parserContext.getRegistry().registerAlias(GemfireConstants.DEFAULT_GEMFIRE_CACHE_NAME, "gemfire-cache"); + // Set Cache bean alias for backwards compatibility... + parserContext.getRegistry().registerAlias(name, "gemfire-cache"); } + return name; } 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 0ddc045c..5ebac4f9 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 @@ -117,15 +117,6 @@ Configures a data source to be bound to a JNDI context for use with Gemfire tran - - - - - namespace and its 'prop ]]> + + + + + @@ -160,6 +159,45 @@ when the same cache is used in multiple application context/bean factories insid ]]> + + + + + + + + + + + + + + + + + + + + @@ -169,6 +207,15 @@ domain classes which are added to the cache in portable data exchange (PDX) form ]]> + + + + + @@ -179,15 +226,6 @@ If not set, the metadata will go in the default disk store. ]]> - - - - - @@ -216,44 +254,6 @@ do not need to pay the cost of preserving the unread fields since you will never ]]> - - - - - - - - - - - - - - - - - - - - @@ -271,14 +271,24 @@ Defines a GemFire Cache instance used for creating or retrieving 'regions'. - + +By default, GemFire 7.5 and later will attempt to reconnect and reinitialize the cache when it has been forced out +of the distributed system by a network-partition event, or has otherwise been shunned by other members. + +An auto-reconnect causes all the GemFire component references (e.g. Cache, Regions, Gateways, etc) that may have +been injected into and SDG-based application to become stale. Even when using GemFire's public Java API directly, +GemFire makes no guarantees to automatically refresh any returned references to application objects that now are +stale. + +Therefore, in Spring Data GemFire, the default behavior will continue to be not to 'auto-reconnect'. This behavior +is not recommended for applications that are 'peer' Caches injecting GemFire components, like the Cache, or Regions +into appliaction components (e.g. @Repository POJOs). + +Enabling 'auto-reconnect' is only recommended for Spring bootstrapped GemFire Server's that use the Spring Data GemFire +XML namespace to configure GemFire instead of GemFire's cache.xml. + ]]> + + + + + diff --git a/src/test/java/org/springframework/data/gemfire/CacheAutoReconnectIntegrationTests.java b/src/test/java/org/springframework/data/gemfire/CacheAutoReconnectIntegrationTests.java new file mode 100644 index 00000000..b2c3f7cf --- /dev/null +++ b/src/test/java/org/springframework/data/gemfire/CacheAutoReconnectIntegrationTests.java @@ -0,0 +1,75 @@ +/* + * 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.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assume.assumeNotNull; + +import java.io.File; + +import org.junit.After; +import org.junit.Test; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.context.support.ClassPathXmlApplicationContext; +import org.springframework.data.gemfire.config.GemfireConstants; + +import com.gemstone.gemfire.cache.Cache; + +/** + * The CacheAutoReconnectIntegrationTests class is a tests suite of test cases testing Spring Data GemFire's support + * of GemFire's Auto-Reconnect functionality release in 8.0. + * + * @author John Blum + * @see org.junit.Test + * @since 1.5.0 + */ +public class CacheAutoReconnectIntegrationTests { + + private ConfigurableApplicationContext applicationContext; + + @After + public void tearDown() { + assumeNotNull(applicationContext); + applicationContext.close(); + } + + protected Cache getCache(String configLocation) { + String baseConfigLocation = File.separator.concat( + getClass().getPackage().getName().replace('.', File.separatorChar)); + applicationContext = new ClassPathXmlApplicationContext(baseConfigLocation.concat(File.separator).concat(configLocation)); + return applicationContext.getBean(GemfireConstants.DEFAULT_GEMFIRE_CACHE_NAME, Cache.class); + } + + @Test + public void testAutoReconnectDisabled() { + Cache cache = getCache("cacheAutoReconnectDisabledIntegrationTests.xml"); + assertNotNull(cache.getDistributedSystem()); + assertNotNull(cache.getDistributedSystem().getProperties()); + assertTrue(Boolean.valueOf(cache.getDistributedSystem().getProperties().getProperty("disable-auto-reconnect"))); + } + + @Test + public void testAutoReconnectEnabled() { + Cache cache = getCache("cacheAutoReconnectEnabledIntegrationTests.xml"); + assertNotNull(cache.getDistributedSystem()); + assertNotNull(cache.getDistributedSystem().getProperties()); + assertFalse(Boolean.valueOf(cache.getDistributedSystem().getProperties().getProperty("disable-auto-reconnect"))); + } + +} diff --git a/src/test/java/org/springframework/data/gemfire/config/CacheNamespaceTest.java b/src/test/java/org/springframework/data/gemfire/config/CacheNamespaceTest.java index 2283054d..7a1189cb 100644 --- a/src/test/java/org/springframework/data/gemfire/config/CacheNamespaceTest.java +++ b/src/test/java/org/springframework/data/gemfire/config/CacheNamespaceTest.java @@ -19,11 +19,14 @@ package org.springframework.data.gemfire.config; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.nullValue; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; +import java.util.Properties; + import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; @@ -45,100 +48,179 @@ import com.gemstone.gemfire.cache.util.TimestampedEntryEvent; /** * @author Costin Leau + * @author John Blum */ @RunWith(SpringJUnit4ClassRunner.class) -@ContextConfiguration(locations="/org/springframework/data/gemfire/config/cache-ns.xml", - initializers=GemfireTestApplicationContextInitializer.class) +@ContextConfiguration(locations = "cache-ns.xml", initializers = GemfireTestApplicationContextInitializer.class) +@SuppressWarnings("unused") public class CacheNamespaceTest{ - @Autowired ApplicationContext ctx; - + + @Autowired + private ApplicationContext context; + @Test - public void testBasicCache() throws Exception { - assertTrue(ctx.containsBean("gemfireCache")); - //Check alias is registered - assertTrue(ctx.containsBean("gemfire-cache")); - // - CacheFactoryBean cfb = (CacheFactoryBean) ctx.getBean("&gemfireCache"); - assertNull(TestUtils.readField("cacheXml", cfb)); - assertNull(TestUtils.readField("properties", cfb)); + public void testNoNamedCache() throws Exception { + assertTrue(context.containsBean("gemfireCache")); + assertTrue(context.containsBean("gemfire-cache")); // assert alias is registered + + Cache gemfireCache = context.getBean("gemfireCache", Cache.class); + + assertNotNull(gemfireCache); + assertNotNull(gemfireCache.getDistributedSystem()); + assertNotNull(gemfireCache.getDistributedSystem().getProperties()); + assertTrue(Boolean.parseBoolean(gemfireCache.getDistributedSystem().getProperties() + .getProperty("disable-auto-reconnect"))); + + CacheFactoryBean cacheFactoryBean = context.getBean("&gemfireCache", CacheFactoryBean.class); + + assertNull(TestUtils.readField("cacheXml", cacheFactoryBean)); + + Properties gemfireProperties = cacheFactoryBean.getProperties(); + + assertNotNull(gemfireProperties); + assertTrue(gemfireProperties.containsKey("disable-auto-reconnect")); + assertTrue(Boolean.parseBoolean(gemfireProperties.getProperty("disable-auto-reconnect"))); + assertFalse(cacheFactoryBean.getEnableAutoReconnect()); } @Test public void testNamedCache() throws Exception { - assertTrue(ctx.containsBean("cache-with-name")); - CacheFactoryBean cfb = (CacheFactoryBean) ctx.getBean("&cache-with-name"); - assertNull(TestUtils.readField("cacheXml", cfb)); - assertNull(TestUtils.readField("properties", cfb)); + assertTrue(context.containsBean("cache-with-name")); + + Cache gemfireCache = context.getBean("gemfireCache", Cache.class); + + assertTrue(Boolean.parseBoolean(gemfireCache.getDistributedSystem().getProperties() + .getProperty("disable-auto-reconnect"))); + + CacheFactoryBean cacheFactoryBean = context.getBean("&cache-with-name", CacheFactoryBean.class); + + assertNull(TestUtils.readField("cacheXml", cacheFactoryBean)); + + Properties gemfireProperties = cacheFactoryBean.getProperties(); + + assertNotNull(gemfireProperties); + assertTrue(gemfireProperties.containsKey("disable-auto-reconnect")); + assertTrue(Boolean.parseBoolean(gemfireProperties.getProperty("disable-auto-reconnect"))); + assertFalse(cacheFactoryBean.getEnableAutoReconnect()); } @Test - public void testCacheWithXml() throws Exception { - assertTrue(ctx.containsBean("cache-with-xml")); - CacheFactoryBean cfb = (CacheFactoryBean) ctx.getBean("&cache-with-xml"); - Resource res = TestUtils.readField("cacheXml", cfb); - assertEquals("gemfire-cache.xml", res.getFilename()); - assertEquals(ctx.getBean("props"), TestUtils.readField("properties", cfb)); + public void testCacheWithXmlAndProperties() throws Exception { + assertTrue(context.containsBean("cache-with-xml-and-props")); - assertEquals(Boolean.FALSE, TestUtils.readField("pdxIgnoreUnreadFields", cfb)); - assertEquals(Boolean.TRUE, TestUtils.readField("pdxPersistent", cfb)); + CacheFactoryBean cacheFactoryBean = context.getBean("&cache-with-xml-and-props", CacheFactoryBean.class); + Resource cacheXmlResource = TestUtils.readField("cacheXml", cacheFactoryBean); + + assertEquals("gemfire-cache.xml", cacheXmlResource.getFilename()); + assertTrue(context.containsBean("gemfireProperties")); + assertEquals(context.getBean("gemfireProperties"), TestUtils.readField("properties", cacheFactoryBean)); + assertEquals(Boolean.TRUE, TestUtils.readField("pdxReadSerialized", cacheFactoryBean)); + assertEquals(Boolean.FALSE, TestUtils.readField("pdxIgnoreUnreadFields", cacheFactoryBean)); + assertEquals(Boolean.TRUE, TestUtils.readField("pdxPersistent", cacheFactoryBean)); } @Test public void testCacheWithGatewayConflictResolver() { - Cache cache = ctx.getBean("cache-with-conflict-resolver", Cache.class); - assertNotNull(cache.getGatewayConflictResolver()); - assertTrue(cache.getGatewayConflictResolver() instanceof TestConflictResolver); - } + Cache cache = context.getBean("cache-with-gateway-conflict-resolver", Cache.class); - @Test(expected = IllegalArgumentException.class) - public void testNoBeanFactory() throws Exception { - assertTrue(ctx.containsBean("no-bl")); - CacheFactoryBean cfb = (CacheFactoryBean) ctx.getBean("&no-bl"); - - assertThat(ReflectionTestUtils.getField(cfb, "factoryLocator"), is(nullValue())); - - GemfireBeanFactoryLocator locator = new GemfireBeanFactoryLocator(); - try { - assertNotNull(locator.useBeanFactory("cache-with-name")); - locator.useBeanFactory("no-bl"); - } - finally { - locator.destroy(); - } + assertTrue(cache.getGatewayConflictResolver() instanceof TestGatewayConflictResolver); } @Test - public void testBasicClientCache() throws Exception { - assertTrue(ctx.containsBean("client-cache")); - ClientCacheFactoryBean cfb = (ClientCacheFactoryBean) ctx.getBean("&client-cache"); - assertNull(TestUtils.readField("cacheXml", cfb)); - assertNull(TestUtils.readField("properties", cfb)); + public void testCacheWithAutoReconnectDisabled() { + assertTrue(context.containsBean("cache-with-auto-reconnect-disabled")); + + Cache gemfireCache = context.getBean("cache-with-auto-reconnect-disabled", Cache.class); + + assertTrue(Boolean.parseBoolean(gemfireCache.getDistributedSystem().getProperties() + .getProperty("disable-auto-reconnect"))); + + CacheFactoryBean cacheFactoryBean = context.getBean("&cache-with-auto-reconnect-disabled", CacheFactoryBean.class); + + assertFalse(cacheFactoryBean.getEnableAutoReconnect()); } @Test - public void testBasicClientCacheWithXml() throws Exception { - assertTrue(ctx.containsBean("client-cache-with-xml")); - ClientCacheFactoryBean cfb = (ClientCacheFactoryBean) ctx.getBean("&client-cache-with-xml"); - Resource res = TestUtils.readField("cacheXml", cfb); - assertEquals("gemfire-client-cache.xml", res.getFilename()); + public void testCacheWithAutoReconnectEnabled() { + assertTrue(context.containsBean("cache-with-auto-reconnect-enabled")); + + Cache gemfireCache = context.getBean("cache-with-auto-reconnect-enabled", Cache.class); + + assertFalse(Boolean.parseBoolean(gemfireCache.getDistributedSystem().getProperties() + .getProperty("disable-auto-reconnect"))); + + CacheFactoryBean cacheFactoryBean = context.getBean("&cache-with-auto-reconnect-enabled", CacheFactoryBean.class); + + assertTrue(cacheFactoryBean.getEnableAutoReconnect()); } @Test public void testHeapTunedCache() throws Exception { - assertTrue(ctx.containsBean("heap-tuned-cache")); - CacheFactoryBean cfb = (CacheFactoryBean) ctx.getBean("&heap-tuned-cache"); - Float chp = (Float) TestUtils.readField("criticalHeapPercentage", cfb); - Float ehp = (Float) TestUtils.readField("evictionHeapPercentage", cfb); - assertEquals(70, chp, 0.0001); - assertEquals(60, ehp, 0.0001); + assertTrue(context.containsBean("heap-tuned-cache")); + + CacheFactoryBean cacheFactoryBean = context.getBean("&heap-tuned-cache", CacheFactoryBean.class); + + Float criticalHeapPercentage = (Float) TestUtils.readField("criticalHeapPercentage", cacheFactoryBean); + Float evictionHeapPercentage = (Float) TestUtils.readField("evictionHeapPercentage", cacheFactoryBean); + + assertEquals(70.0f, criticalHeapPercentage, 0.0001); + assertEquals(60.0f, evictionHeapPercentage, 0.0001); } - public static class TestConflictResolver implements GatewayConflictResolver { - @Override - public void onEvent(TimestampedEntryEvent arg0, GatewayConflictHelper arg1) { - // TODO Auto-generated method stub + @Test(expected = IllegalArgumentException.class) + public void testNoBeanFactoryLocator() throws Exception { + assertTrue(context.containsBean("no-bean-factory-locator")); + CacheFactoryBean cacheFactoryBean = context.getBean("&no-bean-factory-locator", CacheFactoryBean.class); + + assertThat(ReflectionTestUtils.getField(cacheFactoryBean, "factoryLocator"), is(nullValue())); + + GemfireBeanFactoryLocator beanFactoryLocator = new GemfireBeanFactoryLocator(); + + try { + assertNotNull(beanFactoryLocator.useBeanFactory("cache-with-name")); + beanFactoryLocator.useBeanFactory("no-bean-factory-locator"); + } + finally { + beanFactoryLocator.destroy(); } } + + @Test + public void testNamedClientCache() throws Exception { + assertTrue(context.containsBean("client-cache-with-name")); + + ClientCacheFactoryBean clientCacheFactoryBean = context.getBean("&client-cache-with-name", ClientCacheFactoryBean.class); + + assertNull(TestUtils.readField("cacheXml", clientCacheFactoryBean)); + + Properties gemfireProperties = clientCacheFactoryBean.getProperties(); + + assertNotNull(gemfireProperties); + assertTrue(gemfireProperties.isEmpty()); + } + + @Test + public void testClientCacheWithXml() throws Exception { + assertTrue(context.containsBean("client-cache-with-xml")); + + ClientCacheFactoryBean clientCacheFactoryBean = context.getBean("&client-cache-with-xml", ClientCacheFactoryBean.class); + Resource cacheXmlResource = TestUtils.readField("cacheXml", clientCacheFactoryBean); + + assertEquals("gemfire-client-cache.xml", cacheXmlResource.getFilename()); + + Properties gemfireProperties = clientCacheFactoryBean.getProperties(); + + assertNotNull(gemfireProperties); + assertTrue(gemfireProperties.isEmpty()); + } + + public static class TestGatewayConflictResolver implements GatewayConflictResolver { + @Override + public void onEvent(TimestampedEntryEvent arg0, GatewayConflictHelper arg1) { + throw new UnsupportedOperationException("Not Implemented!"); + } + } + } diff --git a/src/test/java/org/springframework/data/gemfire/test/MockCacheFactoryBean.java b/src/test/java/org/springframework/data/gemfire/test/MockCacheFactoryBean.java index 11a06a24..9523526d 100644 --- a/src/test/java/org/springframework/data/gemfire/test/MockCacheFactoryBean.java +++ b/src/test/java/org/springframework/data/gemfire/test/MockCacheFactoryBean.java @@ -37,14 +37,17 @@ public class MockCacheFactoryBean extends CacheFactoryBean { this(); if (cacheFactoryBean != null) { this.factoryLocator = cacheFactoryBean.getBeanFactoryLocator(); + this.lazyInitialize = cacheFactoryBean.isLazyInitialize(); + this.beanClassLoader = cacheFactoryBean.getBeanClassLoader(); this.beanFactory = cacheFactoryBean.getBeanFactory(); this.beanName = cacheFactoryBean.getBeanName(); - this.beanClassLoader = cacheFactoryBean.getBeanClassLoader(); this.cacheXml = cacheFactoryBean.getCacheXml(); + this.properties = cacheFactoryBean.getProperties(); this.copyOnRead = cacheFactoryBean.getCopyOnRead(); this.criticalHeapPercentage = cacheFactoryBean.getCriticalHeapPercentage(); - this.dynamicRegionSupport = cacheFactoryBean.getDynamicRegionSupport(); this.evictionHeapPercentage = cacheFactoryBean.getEvictionHeapPercentage(); + this.dynamicRegionSupport = cacheFactoryBean.getDynamicRegionSupport(); + this.enableAutoReconnect = cacheFactoryBean.getEnableAutoReconnect(); this.gatewayConflictResolver = cacheFactoryBean.getGatewayConflictResolver(); this.jndiDataSources = cacheFactoryBean.getJndiDataSources(); this.lockLease = cacheFactoryBean.getLockLease(); @@ -55,23 +58,20 @@ public class MockCacheFactoryBean extends CacheFactoryBean { this.pdxPersistent = cacheFactoryBean.getPdxPersistent(); this.pdxReadSerialized = cacheFactoryBean.getPdxReadSerialized(); this.pdxSerializer = cacheFactoryBean.getPdxSerializer(); - this.properties = cacheFactoryBean.getProperties(); this.searchTimeout = cacheFactoryBean.getSearchTimeout(); this.transactionListeners = cacheFactoryBean.getTransactionListeners(); this.transactionWriter = cacheFactoryBean.getTransactionWriter(); - this.properties = cacheFactoryBean.getProperties(); - this.lazyInitialize = cacheFactoryBean.isLazyInitialize(); } } - + @Override - protected Object createFactory(Properties props) { - setProperties(props); - return new CacheFactory(props); + protected Object createFactory(Properties gemfireProperties) { + setProperties(gemfireProperties); + return new CacheFactory(gemfireProperties); } - + protected GemFireCache fetchCache() { - ((StubCache)cache).setProperties(this.properties); + ((StubCache) cache).setProperties(this.properties); return cache; } diff --git a/src/test/java/org/springframework/data/gemfire/test/MockClientCacheFactoryBean.java b/src/test/java/org/springframework/data/gemfire/test/MockClientCacheFactoryBean.java index edc8b522..4e008ab3 100644 --- a/src/test/java/org/springframework/data/gemfire/test/MockClientCacheFactoryBean.java +++ b/src/test/java/org/springframework/data/gemfire/test/MockClientCacheFactoryBean.java @@ -62,8 +62,8 @@ public class MockClientCacheFactoryBean extends ClientCacheFactoryBean { } @Override - protected Object createFactory(Properties props) { - ((StubCache)cache).setProperties(props); - return new ClientCacheFactory(props); + protected Object createFactory(Properties gemfireProperties) { + ((StubCache)cache).setProperties(gemfireProperties); + return new ClientCacheFactory(gemfireProperties); } } diff --git a/src/test/java/org/springframework/data/gemfire/test/StubCache.java b/src/test/java/org/springframework/data/gemfire/test/StubCache.java index 9eefb77b..8414dd01 100644 --- a/src/test/java/org/springframework/data/gemfire/test/StubCache.java +++ b/src/test/java/org/springframework/data/gemfire/test/StubCache.java @@ -740,23 +740,29 @@ public class StubCache implements Cache { } DistributedSystem mockDistributedSystem() { - DistributedSystem ds = mock(DistributedSystem.class); - DistributedMember dm = mockDistributedMember(); - when(ds.getName()).thenAnswer(new Answer() { + DistributedSystem mockDistributedSystem = mock(DistributedSystem.class); + + when(mockDistributedSystem.getName()).thenAnswer(new Answer() { @Override public String answer(InvocationOnMock invocation) throws Throwable { return getName(); - } + } }); - when(ds.getDistributedMember()).thenReturn(dm); - return ds; + + when(mockDistributedSystem.getProperties()).thenReturn(this.properties); + + DistributedMember mockDistributedMember = mockDistributedMember(); + + when(mockDistributedSystem.getDistributedMember()).thenReturn(mockDistributedMember); + + return mockDistributedSystem; } DistributedMember mockDistributedMember() { - DistributedMember dm = mock(DistributedMember.class); - when(dm.getHost()).thenReturn("mockDistributedMember.host"); - when(dm.getName()).thenReturn("mockDistributedMember"); - return dm; + DistributedMember mockDistributedMember = mock(DistributedMember.class); + when(mockDistributedMember.getHost()).thenReturn("mockDistributedMember.host"); + when(mockDistributedMember.getName()).thenReturn("mockDistributedMember"); + return mockDistributedMember; } CacheServer mockCacheServer() { @@ -764,84 +770,89 @@ public class StubCache implements Cache { } GatewayHub mockGatewayHub() { - final Gateway gw = mock(Gateway.class); - final GatewayQueueAttributes queueAttributes= mock(GatewayQueueAttributes.class); - when(gw.getQueueAttributes()).thenReturn(queueAttributes); - GatewayHub gwh = mock(GatewayHub.class); - when(gwh.addGateway(anyString(),anyInt())).thenAnswer(new Answer() { + final Gateway gateway = mock(Gateway.class); + when(gateway.getQueueAttributes()).thenReturn(mock(GatewayQueueAttributes.class)); + + GatewayHub gatewayHub = mock(GatewayHub.class); + + when(gatewayHub.addGateway(anyString(),anyInt())).thenAnswer(new Answer() { @Override public Gateway answer(InvocationOnMock invocation) throws Throwable { - // TODO Auto-generated method stub - return gw; + return gateway; } - + }); - return gwh; + + return gatewayHub; } QueryService mockQueryService() throws RegionNotFoundException, IndexInvalidException, IndexNameConflictException, IndexExistsException, UnsupportedOperationException { - - QueryService qs = mock(QueryService.class); - - when(qs.getIndexes()).thenReturn(new ArrayList()); - - - when(qs.createIndex(anyString(), anyString(),anyString())).thenAnswer(new Answer(){ + QueryService queryService = mock(QueryService.class); + + when(queryService.getIndexes()).thenReturn(new ArrayList()); + + when(queryService.createIndex(anyString(), anyString(),anyString())).thenAnswer(new Answer() { @Override public Index answer(InvocationOnMock invocation) throws Throwable { - String indexName = (String)invocation.getArguments()[0]; - String indexedExpression = (String)invocation.getArguments()[1]; - String fromClause = (String)invocation.getArguments()[2]; - return mockIndex(indexName, com.gemstone.gemfire.cache.query.IndexType.FUNCTIONAL, indexedExpression, fromClause, null); + String indexName = (String) invocation.getArguments()[0]; + String indexedExpression = (String) invocation.getArguments()[1]; + String fromClause = (String) invocation.getArguments()[2]; + return mockIndex(indexName, com.gemstone.gemfire.cache.query.IndexType.FUNCTIONAL, indexedExpression, + fromClause, null); } }); - when(qs.createIndex(anyString(), anyString(),anyString(),anyString())).thenAnswer(new Answer(){ + + when(queryService.createIndex(anyString(), anyString(),anyString(),anyString())).thenAnswer(new Answer() { @Override public Index answer(InvocationOnMock invocation) throws Throwable { - String indexName = (String)invocation.getArguments()[0]; - String indexedExpression = (String)invocation.getArguments()[1]; - String fromClause = (String)invocation.getArguments()[2]; - String imports = (String)invocation.getArguments()[3]; - return mockIndex(indexName, com.gemstone.gemfire.cache.query.IndexType.FUNCTIONAL, indexedExpression, fromClause, imports); + String indexName = (String) invocation.getArguments()[0]; + String indexedExpression = (String) invocation.getArguments()[1]; + String fromClause = (String) invocation.getArguments()[2]; + String imports = (String) invocation.getArguments()[3]; + return mockIndex(indexName, com.gemstone.gemfire.cache.query.IndexType.FUNCTIONAL, indexedExpression, + fromClause, imports); } }); - - when(qs.createKeyIndex(anyString(), anyString(),anyString())).thenAnswer(new Answer(){ + + when(queryService.createKeyIndex(anyString(), anyString(),anyString())).thenAnswer(new Answer() { @Override public Index answer(InvocationOnMock invocation) throws Throwable { - String indexName = (String)invocation.getArguments()[0]; - String indexedExpression = (String)invocation.getArguments()[1]; - String fromClause = (String)invocation.getArguments()[2]; - - return mockIndex(indexName, com.gemstone.gemfire.cache.query.IndexType.PRIMARY_KEY, indexedExpression, fromClause, null); + String indexName = (String) invocation.getArguments()[0]; + String indexedExpression = (String) invocation.getArguments()[1]; + String fromClause = (String) invocation.getArguments()[2]; + + return mockIndex(indexName, com.gemstone.gemfire.cache.query.IndexType.PRIMARY_KEY, indexedExpression, + fromClause, null); } }); - - when(qs.createHashIndex(anyString(), anyString(),anyString())).thenAnswer(new Answer(){ + + when(queryService.createHashIndex(anyString(), anyString(),anyString())).thenAnswer(new Answer() { @Override public Index answer(InvocationOnMock invocation) throws Throwable { - String indexName = (String)invocation.getArguments()[0]; - String indexedExpression = (String)invocation.getArguments()[1]; - String fromClause = (String)invocation.getArguments()[2]; - - return mockIndex(indexName, com.gemstone.gemfire.cache.query.IndexType.HASH, indexedExpression, fromClause, null); + String indexName = (String) invocation.getArguments()[0]; + String indexedExpression = (String) invocation.getArguments()[1]; + String fromClause = (String) invocation.getArguments()[2]; + + return mockIndex(indexName, com.gemstone.gemfire.cache.query.IndexType.HASH, indexedExpression, + fromClause, null); } }); - - when(qs.createHashIndex(anyString(), anyString(),anyString(),anyString())).thenAnswer(new Answer(){ + + when(queryService.createHashIndex(anyString(), anyString(),anyString(),anyString())).thenAnswer(new Answer() { @Override public Index answer(InvocationOnMock invocation) throws Throwable { - String indexName = (String)invocation.getArguments()[0]; - String indexedExpression = (String)invocation.getArguments()[1]; - String fromClause = (String)invocation.getArguments()[2]; - String imports = (String)invocation.getArguments()[3]; - - return mockIndex(indexName, com.gemstone.gemfire.cache.query.IndexType.HASH, indexedExpression, fromClause, imports); + String indexName = (String) invocation.getArguments()[0]; + String indexedExpression = (String) invocation.getArguments()[1]; + String fromClause = (String) invocation.getArguments()[2]; + String imports = (String) invocation.getArguments()[3]; + + return mockIndex(indexName, com.gemstone.gemfire.cache.query.IndexType.HASH, indexedExpression, + fromClause, imports); } }); - - return qs; + + return queryService; } @SuppressWarnings({ "rawtypes", "unchecked", "unused" }) @@ -868,8 +879,8 @@ public class StubCache implements Cache { return this.allRegions; } - public void setProperties(Properties props) { - this.properties = props; + public void setProperties(Properties gemfireProperties) { + this.properties = gemfireProperties; } @Override @@ -882,13 +893,13 @@ public class StubCache implements Cache { return this; } + @Override + public void stopReconnecting() { + } + @Override public boolean waitUntilReconnected(final long l, final TimeUnit timeUnit) throws InterruptedException { return false; } - @Override - public void stopReconnecting() { - } - } diff --git a/src/test/resources/org/springframework/data/gemfire/cacheAutoReconnectDisabledIntegrationTests.xml b/src/test/resources/org/springframework/data/gemfire/cacheAutoReconnectDisabledIntegrationTests.xml new file mode 100644 index 00000000..abea9752 --- /dev/null +++ b/src/test/resources/org/springframework/data/gemfire/cacheAutoReconnectDisabledIntegrationTests.xml @@ -0,0 +1,21 @@ + + + + + CacheAutoReconnectIntegrationTests + 0 + config + + + + + diff --git a/src/test/resources/org/springframework/data/gemfire/cacheAutoReconnectEnabledIntegrationTests.xml b/src/test/resources/org/springframework/data/gemfire/cacheAutoReconnectEnabledIntegrationTests.xml new file mode 100644 index 00000000..e0bc54c7 --- /dev/null +++ b/src/test/resources/org/springframework/data/gemfire/cacheAutoReconnectEnabledIntegrationTests.xml @@ -0,0 +1,21 @@ + + + + + CacheAutoReconnectIntegrationTests + 0 + config + + + + + diff --git a/src/test/resources/org/springframework/data/gemfire/config/cache-ns.xml b/src/test/resources/org/springframework/data/gemfire/config/cache-ns.xml index 00dd6a72..5f4a8173 100644 --- a/src/test/resources/org/springframework/data/gemfire/config/cache-ns.xml +++ b/src/test/resources/org/springframework/data/gemfire/config/cache-ns.xml @@ -1,43 +1,48 @@ - - + + - + - - - - + + false - - - - - + + + + + + + + + + + + + + + + + + + - + - - - - - - - - + -