diff --git a/src/main/java/org/springframework/data/gemfire/CacheFactoryBean.java b/src/main/java/org/springframework/data/gemfire/CacheFactoryBean.java index f1bf8ef6..20ecb3fd 100644 --- a/src/main/java/org/springframework/data/gemfire/CacheFactoryBean.java +++ b/src/main/java/org/springframework/data/gemfire/CacheFactoryBean.java @@ -77,6 +77,12 @@ import com.gemstone.gemfire.pdx.PdxSerializer; * @see org.springframework.beans.factory.InitializingBean * @see org.springframework.beans.factory.DisposableBean * @see org.springframework.dao.support.PersistenceExceptionTranslator + * @see com.gemstone.gemfire.cache.Cache + * @see com.gemstone.gemfire.cache.CacheFactory + * @see com.gemstone.gemfire.cache.DynamicRegionFactory + * @see com.gemstone.gemfire.cache.GemFireCache + * @see com.gemstone.gemfire.distributed.DistributedMember + * @see com.gemstone.gemfire.distributed.DistributedSystem */ @SuppressWarnings("unused") public class CacheFactoryBean implements BeanClassLoaderAware, BeanFactoryAware, BeanNameAware, FactoryBean, @@ -400,6 +406,7 @@ public class CacheFactoryBean implements BeanClassLoaderAware, BeanFactoryAware, * Post processes the GemFire Cache instance by loading any cache.xml, applying settings specified in SDG XML * configuration meta-data, and registering the appropriate Transaction Listeners, Writer and JNDI settings. * + * @param parameterized Class type extension of GemFireCache. * @param cache the GemFire Cache instance to process. * @return the GemFire Cache instance after processing. * @throws IOException if the cache.xml Resource could not be loaded and applied to the Cache instance. @@ -789,35 +796,44 @@ public class CacheFactoryBean implements BeanClassLoaderAware, BeanFactoryAware, } /** - * @return the beanClassLoader + * Gets a reference to the JRE ClassLoader used to load and create bean classes in the Spring container. + * + * @return the JRE ClassLoader used to load and created beans in the Spring container. + * @see java.lang.ClassLoader */ public ClassLoader getBeanClassLoader() { return beanClassLoader; } /** - * @return the beanFactory + * Gets a reference to the Spring BeanFactory that created this GemFire Cache FactoryBean. + * + * @return a reference to the Spring BeanFactory. + * @see org.springframework.beans.factory.BeanFactory */ public BeanFactory getBeanFactory() { return beanFactory; } - /** - * @return the beanFactoryLocator - */ + /* (non-Javadoc) */ public GemfireBeanFactoryLocator getBeanFactoryLocator() { return beanFactoryLocator; } /** - * @return the beanName + * Gets the Spring bean name for the GemFire Cache. + * + * @return a String value indicating the Spring container bean name for the GemFire Cache object/component. */ public String getBeanName() { return beanName; } /** - * @return the cacheXml + * Gets a reference to the GemFire native cache.xml file as a Spring Resource. + * + * @return the a reference to the GemFire native cache.xml as a Spring Resource. + * @see org.springframework.core.io.Resource */ public Resource getCacheXml() { return cacheXml; @@ -845,7 +861,10 @@ public class CacheFactoryBean implements BeanClassLoaderAware, BeanFactoryAware, } /** - * @return the properties + * Gets a reference to the GemFire System Properties. + * + * @return a reference to the GemFire System Properties. + * @see java.util.Properties */ public Properties getProperties() { return (properties != null ? properties : (properties = new Properties())); @@ -857,7 +876,7 @@ public class CacheFactoryBean implements BeanClassLoaderAware, BeanFactoryAware, } @Override - public Class getObjectType() { + public Class getObjectType() { return (cache != null ? cache.getClass() : Cache.class); } 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 5d02f1cf..cdce8994 100644 --- a/src/main/java/org/springframework/data/gemfire/client/ClientCacheFactoryBean.java +++ b/src/main/java/org/springframework/data/gemfire/client/ClientCacheFactoryBean.java @@ -27,6 +27,7 @@ import org.springframework.data.gemfire.config.GemfireConstants; import org.springframework.util.Assert; import org.springframework.util.StringUtils; +import com.gemstone.gemfire.cache.CacheClosedException; import com.gemstone.gemfire.cache.GemFireCache; import com.gemstone.gemfire.cache.client.ClientCache; import com.gemstone.gemfire.cache.client.ClientCacheFactory; @@ -219,32 +220,25 @@ public class ClientCacheFactoryBean extends CacheFactoryBean implements Applicat } /** - * Register for events after Pool and Regions have been created and iff non-durable client... + * Inform the GemFire cluster that this client cache is ready to receive events iff the client is non-durable. * * @param event the ApplicationContextEvent fired when the ApplicationContext is refreshed. - * @see org.springframework.context.Lifecycle#start() - * @see com.gemstone.gemfire.cache.client.ClientCache - * @see #readyForEvents(com.gemstone.gemfire.cache.GemFireCache) + * @see com.gemstone.gemfire.cache.client.ClientCache#readyForEvents() + * @see #getReadyForEvents() + * @see #getObject() */ @Override public void onApplicationEvent(final ContextRefreshedEvent event) { - readyForEvents(this.cache); - } - - /** - * Inform the GemFire cluster that this client cache is ready to receive events. - */ - private T readyForEvents(T clientCache) { - if (Boolean.TRUE.equals(getReadyForEvents()) && !clientCache.isClosed()) { + if (isReadyForEvents()) { try { - ((ClientCache) clientCache).readyForEvents(); + ((ClientCache) fetchCache()).readyForEvents(); } catch (IllegalStateException ignore) { - // cannot be called for a non-durable client so exception is thrown + // thrown if clientCache.readyForEvents() is called on a non-durable client + } + catch (CacheClosedException ignore) { } } - - return clientCache; } @Override @@ -262,6 +256,11 @@ public class ClientCacheFactoryBean extends CacheFactoryBean implements Applicat return Boolean.FALSE; } + @Override + public Class getObjectType() { + return (cache != null ? cache.getClass() : ClientCache.class); + } + /** * Sets whether the server(s) should keep the durable client's queue alive for the duration of the timeout * when the client voluntarily disconnects. @@ -288,7 +287,7 @@ public class ClientCacheFactoryBean extends CacheFactoryBean implements Applicat * @param pool the GemFire pool used by the Client Cache to obtain connections to the GemFire cluster. */ public void setPool(Pool pool) { - Assert.notNull(pool, "The GemFire Pool must not be null!"); + Assert.notNull(pool, "GemFire Pool must not be null"); this.pool = pool; } @@ -298,7 +297,7 @@ public class ClientCacheFactoryBean extends CacheFactoryBean implements Applicat * @param poolName set the name of the GemFire Pool used by the GemFire Client Cache. */ public void setPoolName(String poolName) { - Assert.hasText(poolName, "The Pool 'name' is required!"); + Assert.hasText(poolName, "Pool 'name' is required"); this.poolName = poolName; } @@ -331,6 +330,11 @@ public class ClientCacheFactoryBean extends CacheFactoryBean implements Applicat return this.readyForEvents; } + /* (non-Javadoc) */ + public boolean isReadyForEvents() { + return Boolean.TRUE.equals(getReadyForEvents()); + } + @Override public final Boolean getUseClusterConfiguration() { return Boolean.FALSE; 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 a0eb7491..4047f523 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 @@ -349,6 +349,13 @@ Defines a GemFire Client Cache instance used for creating or retrieving 'regions + + + + + T fetchCache() { + return (T) mockClientCache; + } + }; clientCacheFactoryBean.setReadyForEvents(true); - ReflectionUtils.setField(ReflectionUtils.findField(ClientCacheFactoryBean.class, - new org.springframework.util.ReflectionUtils.FieldFilter() { - @Override public boolean matches(final Field field) { - return field.getName().equals("cache"); - } - }), clientCacheFactoryBean, mockClientCache); - - assertThat(clientCacheFactoryBean.getReadyForEvents(), is(true)); + assertThat(clientCacheFactoryBean.isReadyForEvents(), is(true)); clientCacheFactoryBean.onApplicationEvent(mock(ContextRefreshedEvent.class, "MockContextRefreshedEvent")); - verify(mockClientCache, times(1)).isClosed(); verify(mockClientCache, times(1)).readyForEvents(); } @Test - public void onApplicationEventDoesNotSignalReadyForEventsWhenClientCacheIsClosed() { - ClientCache mockClientCache = mock(ClientCache.class, "MockClientCache"); + @SuppressWarnings("unchecked") + public void onApplicationEventDoesNotCallClientCacheReadyForEventsWhenClientCacheFactoryBeanReadyForEventsIsFalse() { + final ClientCache mockClientCache = mock(ClientCache.class, "MockClientCache"); - when(mockClientCache.isClosed()).thenReturn(true); + doThrow(new RuntimeException("test")).when(mockClientCache).readyForEvents(); - ClientCacheFactoryBean clientCacheFactoryBean = new ClientCacheFactoryBean(); + ClientCacheFactoryBean clientCacheFactoryBean = new ClientCacheFactoryBean() { + @Override protected T fetchCache() { + return (T) mockClientCache; + } + }; - clientCacheFactoryBean.setReadyForEvents(true); + clientCacheFactoryBean.setReadyForEvents(false); - ReflectionUtils.setField(ReflectionUtils.findField(ClientCacheFactoryBean.class, - new org.springframework.util.ReflectionUtils.FieldFilter() { - @Override public boolean matches(final Field field) { - return field.getName().equals("cache"); - } - }), clientCacheFactoryBean, mockClientCache); - - assertThat(clientCacheFactoryBean.getReadyForEvents(), is(true)); + assertThat(clientCacheFactoryBean.isReadyForEvents(), is(false)); clientCacheFactoryBean.onApplicationEvent(mock(ContextRefreshedEvent.class, "MockContextRefreshedEvent")); - verify(mockClientCache, times(1)).isClosed(); verify(mockClientCache, never()).readyForEvents(); } @Test - public void onApplicationEventDoesNotSignalReadyForEventsWhenClientCacheFactoryBeanReadyForEventsIsFalse() { - ClientCache mockClientCache = mock(ClientCache.class, "MockClientCache"); + @SuppressWarnings("unchecked") + public void onApplicationEventHandlesIllegalStateException() { + final ClientCache mockClientCache = mock(ClientCache.class, "MockClientCache"); - when(mockClientCache.isClosed()).thenReturn(false); + doThrow(new IllegalStateException("non-durable client")).when(mockClientCache).readyForEvents(); - ClientCacheFactoryBean clientCacheFactoryBean = new ClientCacheFactoryBean(); + ClientCacheFactoryBean clientCacheFactoryBean = new ClientCacheFactoryBean() { + @Override protected T fetchCache() { + return (T) mockClientCache; + } + }; - clientCacheFactoryBean.setReadyForEvents(false); + clientCacheFactoryBean.setReadyForEvents(true); - ReflectionUtils.setField(ReflectionUtils.findField(ClientCacheFactoryBean.class, - new org.springframework.util.ReflectionUtils.FieldFilter() { - @Override public boolean matches(final Field field) { - return field.getName().equals("cache"); - } - }), clientCacheFactoryBean, mockClientCache); - - assertThat(clientCacheFactoryBean.getReadyForEvents(), is(false)); + assertThat(clientCacheFactoryBean.isReadyForEvents(), is(true)); clientCacheFactoryBean.onApplicationEvent(mock(ContextRefreshedEvent.class, "MockContextRefreshedEvent")); - verify(mockClientCache, never()).isClosed(); - verify(mockClientCache, never()).readyForEvents(); + verify(mockClientCache, times(1)).readyForEvents(); + } + + @Test + @SuppressWarnings("unchecked") + public void onApplicationEventHandlesCacheClosedException() { + ClientCacheFactoryBean clientCacheFactoryBean = new ClientCacheFactoryBean() { + @Override protected T fetchCache() { + throw new CacheClosedException("test"); + } + }; + + clientCacheFactoryBean.setReadyForEvents(true); + + assertThat(clientCacheFactoryBean.isReadyForEvents(), is(true)); + + clientCacheFactoryBean.onApplicationEvent(mock(ContextRefreshedEvent.class, "MockContextRefreshedEvent")); } @Test @@ -541,7 +546,7 @@ public class ClientCacheFactoryBeanTest { } @Test(expected = IllegalArgumentException.class) - public void setPoolNameToInvalidValue() { + public void setPoolNameWithAnIllegalArgument() { try { new ClientCacheFactoryBean().setPoolName(" "); } diff --git a/src/test/java/org/springframework/data/gemfire/client/DurableClientCacheIntegrationTest.java b/src/test/java/org/springframework/data/gemfire/client/DurableClientCacheIntegrationTest.java index 24fd6dc2..ae39de7e 100644 --- a/src/test/java/org/springframework/data/gemfire/client/DurableClientCacheIntegrationTest.java +++ b/src/test/java/org/springframework/data/gemfire/client/DurableClientCacheIntegrationTest.java @@ -221,11 +221,7 @@ public class DurableClientCacheIntegrationTest extends AbstractGemFireClientServ @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { - if (RUN_COUNT.get() == 2 && bean instanceof ClientCache) { - // NOTE pending event count is possibly 3 because it includes the 2 puts from the client cache producer - // as well as the "marker" - assertThat(((ClientCache) bean).getDefaultPool().getPendingEventCount(), is(equalTo( - RUN_COUNT.get() == 1 ? -2 : 3))); + if (bean instanceof ClientCache) { pause(TimeUnit.SECONDS.toMillis(3)); } diff --git a/src/test/java/org/springframework/data/gemfire/test/GemfireTestApplicationContextInitializer.java b/src/test/java/org/springframework/data/gemfire/test/GemfireTestApplicationContextInitializer.java index e6606181..1e148fa7 100644 --- a/src/test/java/org/springframework/data/gemfire/test/GemfireTestApplicationContextInitializer.java +++ b/src/test/java/org/springframework/data/gemfire/test/GemfireTestApplicationContextInitializer.java @@ -10,7 +10,9 @@ * 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.test; + import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.context.ApplicationContextInitializer; @@ -19,30 +21,34 @@ import org.springframework.util.StringUtils; /** * @author David Turanski - * + * @author John Blum */ public class GemfireTestApplicationContextInitializer implements ApplicationContextInitializer { - private static Log logger = LogFactory.getLog(GemfireTestApplicationContextInitializer.class); + private static final Log LOG = LogFactory.getLog(GemfireTestApplicationContextInitializer.class); public static final String GEMFIRE_TEST_RUNNER_DISABLED = "org.springframework.data.gemfire.test.GemfireTestRunner.nomock"; - /* (non-Javadoc) + /* + * (non-Javadoc) * @see org.springframework.context.ApplicationContextInitializer#initialize(org.springframework.context.ConfigurableApplicationContext) */ @Override public void initialize(ConfigurableApplicationContext applicationContext) { - if (StringUtils.hasText(System.getProperty(GEMFIRE_TEST_RUNNER_DISABLED))) { - String value = System.getProperty(GEMFIRE_TEST_RUNNER_DISABLED); + String gemfireTestRunnerDisabled = System.getProperty(GEMFIRE_TEST_RUNNER_DISABLED, Boolean.FALSE.toString()); - if (!("NO".equalsIgnoreCase(value) || "FALSE".equalsIgnoreCase(value))) { - logger.warn(String.format("Mocks disabled. Using real GemFire components: %1$s = %2$s", - GEMFIRE_TEST_RUNNER_DISABLED, value)); - return; - } + if (isGemFireTestRunnerDisable(gemfireTestRunnerDisabled)) { + LOG.warn(String.format("WARNING - Mocks disabled; Using real GemFire components (%1$s = %2$s)", + GEMFIRE_TEST_RUNNER_DISABLED, gemfireTestRunnerDisabled)); } + else { + applicationContext.getBeanFactory().addBeanPostProcessor(new GemfireTestBeanPostProcessor()); + } + } - applicationContext.getBeanFactory().addBeanPostProcessor(new GemfireTestBeanPostProcessor()); + private boolean isGemFireTestRunnerDisable(final String systemPropertyValue) { + return (Boolean.valueOf(StringUtils.trimAllWhitespace(systemPropertyValue)) + || "yes".equalsIgnoreCase(systemPropertyValue)); } }