diff --git a/src/main/java/org/springframework/data/gemfire/CacheFactoryBean.java b/src/main/java/org/springframework/data/gemfire/CacheFactoryBean.java index 2669345d..3f90119a 100644 --- a/src/main/java/org/springframework/data/gemfire/CacheFactoryBean.java +++ b/src/main/java/org/springframework/data/gemfire/CacheFactoryBean.java @@ -76,9 +76,15 @@ 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, +public class CacheFactoryBean implements BeanClassLoaderAware, BeanFactoryAware, BeanNameAware, FactoryBean, InitializingBean, DisposableBean, PersistenceExceptionTranslator { protected boolean close = true; @@ -96,7 +102,7 @@ public class CacheFactoryBean implements BeanClassLoaderAware, BeanFactoryAware, protected Boolean pdxReadSerialized; protected Boolean useClusterConfiguration; - protected GemFireCache cache; + protected Cache cache; protected ClassLoader beanClassLoader; @@ -226,7 +232,7 @@ public class CacheFactoryBean implements BeanClassLoaderAware, BeanFactoryAware, } /* (non-Javadoc) */ - private GemFireCache init() throws Exception { + private Cache init() throws Exception { initBeanFactoryLocator(); final ClassLoader currentThreadContextClassLoader = Thread.currentThread().getContextClassLoader(); @@ -396,6 +402,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. @@ -785,35 +792,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; @@ -841,14 +857,17 @@ 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())); } @Override - public GemFireCache getObject() throws Exception { + public Cache getObject() throws Exception { return 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 637e8115..1c7e4461 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 @@ -336,6 +330,11 @@ public class ClientCacheFactoryBean extends CacheFactoryBean implements Applicat return readyForEvents; } + /* (non-Javadoc) */ + public boolean isReadyForEvents() { + return Boolean.TRUE.equals(getReadyForEvents()); + } + @Override public final void setUseClusterConfiguration(Boolean useClusterConfiguration) { throw new UnsupportedOperationException("Shared, cluster configuration is not applicable to clients."); 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 + + + + + + + + + + diff --git a/src/test/java/org/springframework/data/gemfire/client/ClientCacheFactoryBeanTest.java b/src/test/java/org/springframework/data/gemfire/client/ClientCacheFactoryBeanTest.java index 507b6e39..44d19f13 100644 --- a/src/test/java/org/springframework/data/gemfire/client/ClientCacheFactoryBeanTest.java +++ b/src/test/java/org/springframework/data/gemfire/client/ClientCacheFactoryBeanTest.java @@ -27,13 +27,13 @@ import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.any; import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import java.lang.reflect.Field; import java.util.Properties; import org.junit.Test; @@ -42,8 +42,8 @@ import org.springframework.beans.factory.BeanInitializationException; import org.springframework.context.event.ContextRefreshedEvent; import org.springframework.data.gemfire.TestUtils; import org.springframework.data.gemfire.config.GemfireConstants; -import org.springframework.data.util.ReflectionUtils; +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; @@ -60,7 +60,7 @@ import com.gemstone.gemfire.pdx.PdxSerializer; * @see org.mockito.Mockito * @see org.junit.Test * @see org.springframework.data.gemfire.client.ClientCacheFactoryBean - * @see org.springframework.data.gemfire.TestUtils + * @see com.gemstone.gemfire.cache.client.ClientCache * @since 1.7.0 */ public class ClientCacheFactoryBeanTest { @@ -415,78 +415,83 @@ public class ClientCacheFactoryBeanTest { } @Test - public void onApplicationEventSignalsReadyForEvents() throws Exception { - ClientCache mockClientCache = mock(ClientCache.class, "MockClientCache"); + @SuppressWarnings("unchecked") + public void onApplicationEventCallsClientCacheReadyForEvents() { + final ClientCache mockClientCache = mock(ClientCache.class, "MockClientCache"); - when(mockClientCache.isClosed()).thenReturn(false); - - ClientCacheFactoryBean clientCacheFactoryBean = new ClientCacheFactoryBean(); + ClientCacheFactoryBean clientCacheFactoryBean = new ClientCacheFactoryBean() { + @Override protected 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..ec45b2ad 100644 --- a/src/test/java/org/springframework/data/gemfire/client/DurableClientCacheIntegrationTest.java +++ b/src/test/java/org/springframework/data/gemfire/client/DurableClientCacheIntegrationTest.java @@ -19,6 +19,7 @@ package org.springframework.data.gemfire.client; import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.notNullValue; +import static org.hamcrest.number.OrderingComparison.greaterThanOrEqualTo; import static org.junit.Assert.assertThat; import static org.junit.Assume.assumeThat; @@ -221,12 +222,16 @@ 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))); - pause(TimeUnit.SECONDS.toMillis(3)); + if (bean instanceof ClientCache) { + if (RUN_COUNT.get() == 1) { + assertThat(((ClientCache) bean).getDefaultPool().getPendingEventCount(), is(equalTo(-2))); + } + else { + // 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(greaterThanOrEqualTo(2))); + pause(TimeUnit.SECONDS.toMillis(3)); + } } return bean; 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)); } }