diff --git a/src/main/java/org/springframework/data/gemfire/client/PoolFactoryBean.java b/src/main/java/org/springframework/data/gemfire/client/PoolFactoryBean.java index fa43de2f..f6c3cdc9 100644 --- a/src/main/java/org/springframework/data/gemfire/client/PoolFactoryBean.java +++ b/src/main/java/org/springframework/data/gemfire/client/PoolFactoryBean.java @@ -30,6 +30,7 @@ import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.InitializingBean; import org.springframework.data.gemfire.support.ConnectionEndpoint; import org.springframework.data.gemfire.support.ConnectionEndpointList; +import org.springframework.data.gemfire.util.CollectionUtils; import org.springframework.data.gemfire.util.DistributedSystemUtils; import org.springframework.util.Assert; import org.springframework.util.StringUtils; @@ -81,6 +82,8 @@ public class PoolFactoryBean implements FactoryBean, InitializingBean, Dis private Pool pool; + private Properties gemfireProperties; + private String beanName; private String name; @@ -207,13 +210,16 @@ public class PoolFactoryBean implements FactoryBean, InitializingBean, Dis * @see java.util.Properties */ protected Properties resolveGemfireProperties() { + gemfireProperties = (gemfireProperties != null ? gemfireProperties : new Properties()); + try { ClientCacheFactoryBean clientCacheFactoryBean = beanFactory.getBean(ClientCacheFactoryBean.class); - return clientCacheFactoryBean.resolveProperties(); + CollectionUtils.mergePropertiesIntoMap(clientCacheFactoryBean.resolveProperties(), gemfireProperties); } catch (Exception ignore) { - return null; } + + return gemfireProperties; } /** @@ -317,6 +323,10 @@ public class PoolFactoryBean implements FactoryBean, InitializingBean, Dis this.pingInterval = pingInterval; } + public void setProperties(Properties gemfireProperties) { + this.gemfireProperties = gemfireProperties; + } + public void setPrSingleHopEnabled(boolean prSingleHopEnabled) { this.prSingleHopEnabled = prSingleHopEnabled; } 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 86443eed..1a2432d4 100644 --- a/src/main/java/org/springframework/data/gemfire/config/CacheParser.java +++ b/src/main/java/org/springframework/data/gemfire/config/CacheParser.java @@ -22,6 +22,7 @@ import org.springframework.beans.factory.BeanDefinitionStoreException; import org.springframework.beans.factory.support.AbstractBeanDefinition; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.support.BeanDefinitionReaderUtils; +import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.support.ManagedList; import org.springframework.beans.factory.support.ManagedMap; import org.springframework.beans.factory.xml.AbstractSimpleBeanDefinitionParser; @@ -43,6 +44,7 @@ import com.gemstone.gemfire.internal.datasource.ConfigProperty; * @author Costin Leau * @author Oliver Gierke * @author David Turanski + * @author John Blum */ class CacheParser extends AbstractSimpleBeanDefinitionParser { @@ -55,7 +57,7 @@ class CacheParser extends AbstractSimpleBeanDefinitionParser { protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) { super.doParse(element, builder); - registerCustomGemFireBeanFactoryPostProcessors(parserContext); + registerGemFireBeanFactoryPostProcessors(getRegistry(parserContext)); ParsingUtils.setPropertyValue(element, builder, "cache-xml-location", "cacheXml"); ParsingUtils.setPropertyReference(element, builder, "properties-ref", "properties"); @@ -115,9 +117,15 @@ class CacheParser extends AbstractSimpleBeanDefinitionParser { parseJndiBindings(element, builder); } - private void registerCustomGemFireBeanFactoryPostProcessors(final ParserContext parserContext) { + /* (non-Javadoc) */ + protected BeanDefinitionRegistry getRegistry(ParserContext parserContext) { + return parserContext.getRegistry(); + } + + /* (non-Javadoc) */ + void registerGemFireBeanFactoryPostProcessors(BeanDefinitionRegistry registry) { BeanDefinitionReaderUtils.registerWithGeneratedName(BeanDefinitionBuilder.genericBeanDefinition( - CustomEditorRegistrationBeanFactoryPostProcessor.class).getBeanDefinition(), parserContext.getRegistry()); + CustomEditorRegistrationBeanFactoryPostProcessor.class).getBeanDefinition(), registry); } private void parsePdxDiskStore(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) { @@ -126,14 +134,14 @@ class CacheParser extends AbstractSimpleBeanDefinitionParser { final String pdxDiskStoreName = element.getAttribute("pdx-disk-store"); if (!StringUtils.isEmpty(pdxDiskStoreName)) { - registerPdxDiskStoreAwareBeanFactoryPostProcessor(parserContext, pdxDiskStoreName); + registerPdxDiskStoreAwareBeanFactoryPostProcessor(getRegistry(parserContext), pdxDiskStoreName); } } - private void registerPdxDiskStoreAwareBeanFactoryPostProcessor(ParserContext parserContext, String pdxDiskStoreName) { + /* (non-Javadoc) */ + void registerPdxDiskStoreAwareBeanFactoryPostProcessor(BeanDefinitionRegistry registry, String pdxDiskStoreName) { BeanDefinitionReaderUtils.registerWithGeneratedName( - createPdxDiskStoreAwareBeanFactoryPostProcessorBeanDefinition(pdxDiskStoreName), - parserContext.getRegistry()); + createPdxDiskStoreAwareBeanFactoryPostProcessorBeanDefinition(pdxDiskStoreName), registry); } private AbstractBeanDefinition createPdxDiskStoreAwareBeanFactoryPostProcessorBeanDefinition(String pdxDiskStoreName) { @@ -183,8 +191,7 @@ class CacheParser extends AbstractSimpleBeanDefinitionParser { } /** - * @param dynamicRegionSupport BDB for <dynamic-region-factory> - * element + * @param dynamicRegionSupport BDB for <dynamic-region-factory> element. */ protected void postProcessDynamicRegionSupport(Element element, BeanDefinitionBuilder dynamicRegionSupport) { } diff --git a/src/main/java/org/springframework/data/gemfire/config/ClientCacheParser.java b/src/main/java/org/springframework/data/gemfire/config/ClientCacheParser.java index a83c385a..26c38ebb 100644 --- a/src/main/java/org/springframework/data/gemfire/config/ClientCacheParser.java +++ b/src/main/java/org/springframework/data/gemfire/config/ClientCacheParser.java @@ -17,6 +17,8 @@ package org.springframework.data.gemfire.config; import org.springframework.beans.factory.support.BeanDefinitionBuilder; +import org.springframework.beans.factory.support.BeanDefinitionReaderUtils; +import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.xml.ParserContext; import org.springframework.data.gemfire.client.ClientCacheFactoryBean; import org.w3c.dom.Element; @@ -27,6 +29,7 @@ import org.w3c.dom.Element; * @author Costin Leau * @author David Turanski * @author Lyndon Adams + * @author John Blum */ class ClientCacheParser extends CacheParser { @@ -43,10 +46,18 @@ class ClientCacheParser extends CacheParser { ParsingUtils.setPropertyValue(element, builder, "keep-alive"); ParsingUtils.setPropertyValue(element, builder, "pool-name"); ParsingUtils.setPropertyValue(element, builder, "ready-for-events"); + registerClientCachePoolGemfirePropertiesSyncingBeanFactoryPostProcessor(getRegistry(parserContext)); + } + + /* (non-Javadoc) */ + void registerClientCachePoolGemfirePropertiesSyncingBeanFactoryPostProcessor(BeanDefinitionRegistry registry) { + BeanDefinitionReaderUtils.registerWithGeneratedName(BeanDefinitionBuilder.genericBeanDefinition( + ClientCachePoolGemfirePropertiesSyncingBeanFactoryPostProcessor.class).getBeanDefinition(), registry); } @Override protected void postProcessDynamicRegionSupport(Element element, BeanDefinitionBuilder dynamicRegionSupport) { ParsingUtils.setPropertyValue(element, dynamicRegionSupport, "pool-name"); } + } diff --git a/src/main/java/org/springframework/data/gemfire/config/ClientCachePoolGemfirePropertiesSyncingBeanFactoryPostProcessor.java b/src/main/java/org/springframework/data/gemfire/config/ClientCachePoolGemfirePropertiesSyncingBeanFactoryPostProcessor.java new file mode 100644 index 00000000..4b39d3f4 --- /dev/null +++ b/src/main/java/org/springframework/data/gemfire/config/ClientCachePoolGemfirePropertiesSyncingBeanFactoryPostProcessor.java @@ -0,0 +1,82 @@ +/* + * Copyright 2012 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 org.springframework.beans.BeansException; +import org.springframework.beans.PropertyValue; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.config.BeanFactoryPostProcessor; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.beans.factory.config.RuntimeBeanReference; +import org.springframework.data.gemfire.client.ClientCacheFactoryBean; +import org.springframework.data.gemfire.client.PoolFactoryBean; +import org.springframework.util.StringUtils; + +/** + * The ClientCachePoolGemfirePropertiesSyncingBeanFactoryPostProcessor class is a Spring {@link BeanFactoryPostProcessor} + * implementation responsible for making sure the GemFire {@link java.util.Properties} between the GemFire ClientCache + * and GemFire Pool are identical. + * + * @author John Blum + * @see org.springframework.beans.factory.config.BeanDefinition + * @see org.springframework.beans.factory.config.BeanFactoryPostProcessor + * @see org.springframework.beans.factory.config.ConfigurableListableBeanFactory + * @see org.springframework.data.gemfire.client.ClientCacheFactoryBean + * @see org.springframework.data.gemfire.client.PoolFactoryBean + * @since 1.8.0 + */ +@SuppressWarnings("unused") +class ClientCachePoolGemfirePropertiesSyncingBeanFactoryPostProcessor implements BeanFactoryPostProcessor { + + protected static final String PROPERTIES_PROPERTY_NAME = "properties"; + + /** + * Post processes the given {@link ConfigurableListableBeanFactory} by syncing the gemfire.properties used + * to configure the GemFire Distributed System constructed by the {@link PoolFactoryBean} during Pool creation + * and resolved by the {@link ClientCacheFactoryBean} during ClientCache creation. + * + * @param beanFactory the {@link ConfigurableListableBeanFactory} to post process. + * @throws BeansException if errors occur during post processing. + * @see org.springframework.beans.factory.config.ConfigurableListableBeanFactory + */ + public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { + BeanDefinition poolFactoryBeanDefinition = null; + String gemfirePropertiesBeanName = null; + + for (String beanName : beanFactory.getBeanDefinitionNames()) { + BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName); + + if (ClientCacheFactoryBean.class.getName().equals(beanDefinition.getBeanClassName())) { + PropertyValue gemfirePropertiesPropertyValue = beanDefinition.getPropertyValues() + .getPropertyValue(PROPERTIES_PROPERTY_NAME); + + gemfirePropertiesBeanName = (gemfirePropertiesPropertyValue != null + ? ((RuntimeBeanReference) gemfirePropertiesPropertyValue.getValue()).getBeanName() : null); + } + else if (PoolFactoryBean.class.getName().equals(beanDefinition.getBeanClassName())) { + poolFactoryBeanDefinition = beanDefinition; + } + } + + if (poolFactoryBeanDefinition != null && StringUtils.hasText(gemfirePropertiesBeanName)) { + poolFactoryBeanDefinition.getPropertyValues().add(PROPERTIES_PROPERTY_NAME, + new RuntimeBeanReference(gemfirePropertiesBeanName)); + } + } + +} diff --git a/src/test/java/org/springframework/data/gemfire/client/PoolFactoryBeanTest.java b/src/test/java/org/springframework/data/gemfire/client/PoolFactoryBeanTest.java index 23985d03..3566b7ce 100644 --- a/src/test/java/org/springframework/data/gemfire/client/PoolFactoryBeanTest.java +++ b/src/test/java/org/springframework/data/gemfire/client/PoolFactoryBeanTest.java @@ -16,11 +16,14 @@ 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.CoreMatchers.nullValue; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.any; import static org.mockito.Matchers.eq; @@ -41,6 +44,7 @@ import org.junit.rules.ExpectedException; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.data.gemfire.TestUtils; +import org.springframework.data.gemfire.test.support.CollectionUtils; import org.springframework.data.util.ReflectionUtils; import com.gemstone.gemfire.cache.client.Pool; @@ -51,7 +55,9 @@ import com.gemstone.gemfire.cache.client.PoolFactory; * of the PoolFactoryBean class. * * @author John Blum + * @see org.junit.Rule * @see org.junit.Test + * @see org.junit.rules.ExpectedException * @see org.mockito.Mockito * @see org.springframework.data.gemfire.client.PoolFactoryBean * @see com.gemstone.gemfire.cache.client.Pool @@ -89,7 +95,7 @@ public class PoolFactoryBeanTest { } @Override void doDistributedSystemConnect(Properties properties) { - assertSame(gemfireProperties, properties); + assertThat(properties, is(equalTo(gemfireProperties))); } }; @@ -180,7 +186,8 @@ public class PoolFactoryBeanTest { Properties expectedGemfireProperties = new Properties(); - expectedGemfireProperties.setProperty("name", "testResolveGemfireProperties"); + expectedGemfireProperties.setProperty("name", "resolveGemfirePropertiesTest"); + clientCacheFactoryBean.setProperties(expectedGemfireProperties); PoolFactoryBean poolFactoryBean = new PoolFactoryBean(); @@ -189,7 +196,40 @@ public class PoolFactoryBeanTest { Properties resolvedGemfireProperties = poolFactoryBean.resolveGemfireProperties(); - assertSame(expectedGemfireProperties, resolvedGemfireProperties); + assertThat(resolvedGemfireProperties, is(equalTo(expectedGemfireProperties))); + } + + @Test + public void resolveMergedGemfireProperties() { + BeanFactory mockBeanFactory = mock(BeanFactory.class, "MockBeanFactory"); + + ClientCacheFactoryBean clientCacheFactoryBean = new ClientCacheFactoryBean(); + + when(mockBeanFactory.getBean(eq(ClientCacheFactoryBean.class))).thenReturn(clientCacheFactoryBean); + + Properties poolGemfireProperties = new Properties(); + Properties expectedGemfireProperties = new Properties(); + + poolGemfireProperties.setProperty("name", "resolveMergedGemfirePropertiesTest"); + poolGemfireProperties.setProperty("log-level", "warning"); + + CollectionUtils.mergePropertiesIntoMap(poolGemfireProperties, expectedGemfireProperties); + + expectedGemfireProperties.setProperty("log-level", "config"); + expectedGemfireProperties.setProperty("durableClientId", "123"); + expectedGemfireProperties.setProperty("durableClientTimeout", "60"); + + clientCacheFactoryBean.setProperties(expectedGemfireProperties); + + PoolFactoryBean poolFactoryBean = new PoolFactoryBean(); + + poolFactoryBean.setBeanFactory(mockBeanFactory); + poolFactoryBean.setProperties(poolGemfireProperties); + + Properties resolvedGemfireProperties = poolFactoryBean.resolveGemfireProperties(); + + assertThat(resolvedGemfireProperties.getProperty("log-level"), is(equalTo("config"))); + assertThat(resolvedGemfireProperties, is(equalTo(expectedGemfireProperties))); } @Test @@ -203,7 +243,10 @@ public class PoolFactoryBeanTest { poolFactoryBean.setBeanFactory(mockBeanFactory); - assertNull(poolFactoryBean.resolveGemfireProperties()); + Properties gemfireProperties = poolFactoryBean.resolveGemfireProperties(); + + assertThat(gemfireProperties, is(notNullValue())); + assertThat(gemfireProperties.isEmpty(), is(true)); } @Test diff --git a/src/test/java/org/springframework/data/gemfire/config/ClientCacheParserTest.java b/src/test/java/org/springframework/data/gemfire/config/ClientCacheParserTest.java new file mode 100644 index 00000000..eb21989a --- /dev/null +++ b/src/test/java/org/springframework/data/gemfire/config/ClientCacheParserTest.java @@ -0,0 +1,161 @@ +/* + * Copyright 2012 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.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; +import static org.hamcrest.Matchers.nullValue; +import static org.junit.Assert.assertThat; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyString; +import static org.mockito.Matchers.eq; +import static org.mockito.Matchers.isNotNull; +import static org.mockito.Matchers.same; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.util.concurrent.atomic.AtomicReference; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.runners.MockitoJUnitRunner; +import org.mockito.stubbing.Answer; +import org.springframework.beans.PropertyValues; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.support.BeanDefinitionBuilder; +import org.springframework.beans.factory.support.BeanDefinitionRegistry; +import org.springframework.beans.factory.xml.ParserContext; +import org.springframework.data.gemfire.client.ClientCacheFactoryBean; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; + +/** + * The ClientCacheParserTest class is a test suite of test cases testing the contract and functionality of the + * ClientCacheParser class. + * + * @author John Blum + * @see org.junit.Test + * @see org.junit.runner.RunWith + * @see org.mockito.Mock + * @see org.mockito.Mockito + * @see org.mockito.runners.MockitoJUnitRunner + * @since 1.8.0 + */ +@RunWith(MockitoJUnitRunner.class) +public class ClientCacheParserTest { + + @Mock + private Element mockElement; + + @Test + @SuppressWarnings("all") + public void beanClassEqualsClientCacheFactoryBean() { + assertThat((Class) new ClientCacheParser().getBeanClass(mockElement), + is(equalTo(ClientCacheFactoryBean.class))); + } + + @Test + public void doParseSetsPropertiesAndRegistersClientCachePoolGemfirePropertiesSyncingBeanFactoryPostProcessor() { + NodeList mockNodeList = mock(NodeList.class); + + when(mockNodeList.getLength()).thenReturn(0); + when(mockElement.getAttribute(eq("durable-client-id"))).thenReturn("123"); + when(mockElement.getAttribute(eq("durable-client-timeout"))).thenReturn("60"); + when(mockElement.getAttribute(eq("keep-alive"))).thenReturn("false"); + when(mockElement.getAttribute(eq("pool-name"))).thenReturn("testPool"); + when(mockElement.getAttribute(eq("ready-for-events"))).thenReturn(null); + when(mockElement.getChildNodes()).thenReturn(mockNodeList); + + final AtomicReference beanDefinitionReference = new AtomicReference(null); + + final BeanDefinitionRegistry mockRegistry = mock(BeanDefinitionRegistry.class); + + doAnswer(new Answer() { + public Void answer(InvocationOnMock invocation) throws Throwable { + BeanDefinition beanFactoryPostProcessorBeanDefinition = + invocation.getArgumentAt(1, BeanDefinition.class); + + if (ClientCachePoolGemfirePropertiesSyncingBeanFactoryPostProcessor.class.getName().equals( + beanFactoryPostProcessorBeanDefinition.getBeanClassName())) { + beanDefinitionReference.compareAndSet(null, beanFactoryPostProcessorBeanDefinition); + } + + return null; + } + }).when(mockRegistry).registerBeanDefinition(isNotNull(String.class), any(BeanDefinition.class)); + + when(mockRegistry.containsBeanDefinition(anyString())).thenReturn(false); + + BeanDefinitionBuilder clientCacheBuilder = BeanDefinitionBuilder.genericBeanDefinition(); + + ClientCacheParser clientCacheParser = new ClientCacheParser() { + @Override protected BeanDefinitionRegistry getRegistry(ParserContext parserContext) { + return mockRegistry; + } + }; + + clientCacheParser.doParse(mockElement, null, clientCacheBuilder); + + BeanDefinition clientCacheBeanDefinition = clientCacheBuilder.getBeanDefinition(); + + assertThat(clientCacheBeanDefinition, is(notNullValue())); + + PropertyValues propertyValues = clientCacheBeanDefinition.getPropertyValues(); + + assertThat(propertyValues, is(notNullValue())); + assertThat((String) propertyValues.getPropertyValue("durableClientId").getValue(), is(equalTo("123"))); + assertThat((String) propertyValues.getPropertyValue("durableClientTimeout").getValue(), is(equalTo("60"))); + assertThat((String) propertyValues.getPropertyValue("keepAlive").getValue(), is(equalTo("false"))); + assertThat((String) propertyValues.getPropertyValue("poolName").getValue(), is(equalTo("testPool"))); + assertThat(propertyValues.getPropertyValue("readyForEvents"), is(nullValue())); + assertThat(beanDefinitionReference.get(), is(notNullValue())); + + verify(mockElement, times(1)).getAttribute(eq("durable-client-id")); + verify(mockElement, times(1)).getAttribute(eq("durable-client-timeout")); + verify(mockElement, times(1)).getAttribute(eq("keep-alive")); + verify(mockElement, times(1)).getAttribute(eq("pool-name")); + verify(mockElement, times(1)).getAttribute(eq("ready-for-events")); + verify(mockRegistry, times(1)).registerBeanDefinition(isNotNull(String.class), + same(beanDefinitionReference.get())); + } + + @Test + public void postProcessDynamicRegionSupportParsesPoolName() { + when(mockElement.getAttribute(eq("pool-name"))).thenReturn("testPool"); + + BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(); + + new ClientCacheParser().postProcessDynamicRegionSupport(mockElement, builder); + + BeanDefinition beanDefinition = builder.getBeanDefinition(); + + assertThat(beanDefinition, is(notNullValue())); + assertThat(beanDefinition.getPropertyValues(), is(notNullValue())); + assertThat(beanDefinition.getPropertyValues().getPropertyValue("poolName"), is(notNullValue())); + assertThat((String) beanDefinition.getPropertyValues().getPropertyValue("poolName").getValue(), is(equalTo("testPool"))); + + verify(mockElement, times(1)).getAttribute(eq("pool-name")); + } + +} diff --git a/src/test/java/org/springframework/data/gemfire/config/ClientCachePoolGemfirePropertiesSyncingBeanFactoryPostProcessorTest.java b/src/test/java/org/springframework/data/gemfire/config/ClientCachePoolGemfirePropertiesSyncingBeanFactoryPostProcessorTest.java new file mode 100644 index 00000000..6efa365b --- /dev/null +++ b/src/test/java/org/springframework/data/gemfire/config/ClientCachePoolGemfirePropertiesSyncingBeanFactoryPostProcessorTest.java @@ -0,0 +1,158 @@ +/* + * Copyright 2012 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.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.nullValue; +import static org.junit.Assert.assertThat; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.beans.factory.config.RuntimeBeanReference; +import org.springframework.beans.factory.support.BeanDefinitionBuilder; +import org.springframework.data.gemfire.client.ClientCacheFactoryBean; +import org.springframework.data.gemfire.client.PoolFactoryBean; + +/** + * The ClientCachePoolGemfirePropertiesSyncingBeanFactoryPostProcessorTest class is a test suite of test cases testing + * the contract and functionality of the ClientCachePoolGemfirePropertiesSyncingBeanFactoryPostProcessor class. + * + * @author John Blum + * @see org.junit.Test + * @see org.junit.runner.RunWith + * @see org.mockito.Mock + * @see org.mockito.Mockito + * @see org.mockito.runners.MockitoJUnitRunner + * @see org.springframework.data.gemfire.config.ClientCachePoolGemfirePropertiesSyncingBeanFactoryPostProcessor + * @since 1.0.0 + */ +@RunWith(MockitoJUnitRunner.class) +public class ClientCachePoolGemfirePropertiesSyncingBeanFactoryPostProcessorTest { + + protected static final String PROPERTIES_PROPERTY_NAME_SHORTCUT = + ClientCachePoolGemfirePropertiesSyncingBeanFactoryPostProcessor.PROPERTIES_PROPERTY_NAME; + + private ClientCachePoolGemfirePropertiesSyncingBeanFactoryPostProcessor beanFactoryPostProcessor = + new ClientCachePoolGemfirePropertiesSyncingBeanFactoryPostProcessor(); + + @Mock + private ConfigurableListableBeanFactory mockBeanFactory; + + protected String getBeanReference(Object reference) { + return (reference instanceof RuntimeBeanReference ? ((RuntimeBeanReference) reference).getBeanName() : null); + } + + protected BeanDefinition newBeanDefinition(Class type) { + return BeanDefinitionBuilder.genericBeanDefinition(type).getBeanDefinition(); + } + + protected T[] toArray(T... array) { + return array; + } + + @Test + public void postProcessSyncsGemfireProperties() { + BeanDefinition objectBean = newBeanDefinition(Object.class); + BeanDefinition clientCacheBean = newBeanDefinition(ClientCacheFactoryBean.class); + + clientCacheBean.getPropertyValues().addPropertyValue(PROPERTIES_PROPERTY_NAME_SHORTCUT, + new RuntimeBeanReference("gemfireProperties")); + + BeanDefinition poolBean = newBeanDefinition(PoolFactoryBean.class); + + when(mockBeanFactory.getBeanDefinitionNames()).thenReturn(toArray("objectBean", "clientCacheBean", "poolBean")); + when(mockBeanFactory.getBeanDefinition(eq("objectBean"))).thenReturn(objectBean); + when(mockBeanFactory.getBeanDefinition(eq("clientCacheBean"))).thenReturn(clientCacheBean); + when(mockBeanFactory.getBeanDefinition(eq("poolBean"))).thenReturn(poolBean); + + assertThat(poolBean.getPropertyValues().getPropertyValue(PROPERTIES_PROPERTY_NAME_SHORTCUT), is(nullValue())); + + beanFactoryPostProcessor.postProcessBeanFactory(mockBeanFactory); + + assertThat(getBeanReference(poolBean.getPropertyValues().getPropertyValue(PROPERTIES_PROPERTY_NAME_SHORTCUT).getValue()), + is(equalTo("gemfireProperties"))); + + verify(mockBeanFactory, times(1)).getBeanDefinitionNames(); + verify(mockBeanFactory, times(1)).getBeanDefinition(eq("objectBean")); + verify(mockBeanFactory, times(1)).getBeanDefinition(eq("clientCacheBean")); + verify(mockBeanFactory, times(1)).getBeanDefinition(eq("poolBean")); + } + + @Test + public void postProcessDoesNotSyncGemfirePropertiesWhenNoClientCacheFactoryBeanIsDeclared() { + BeanDefinition poolBean = newBeanDefinition(PoolFactoryBean.class); + + when(mockBeanFactory.getBeanDefinitionNames()).thenReturn(toArray("poolBean")); + when(mockBeanFactory.getBeanDefinition(eq("poolBean"))).thenReturn(poolBean); + + assertThat(poolBean.getPropertyValues().getPropertyValue(PROPERTIES_PROPERTY_NAME_SHORTCUT), is(nullValue())); + + beanFactoryPostProcessor.postProcessBeanFactory(mockBeanFactory); + + assertThat(poolBean.getPropertyValues().getPropertyValue(PROPERTIES_PROPERTY_NAME_SHORTCUT), is(nullValue())); + + verify(mockBeanFactory, times(1)).getBeanDefinitionNames(); + verify(mockBeanFactory, times(1)).getBeanDefinition(eq("poolBean")); + } + + @Test + public void postProcessDoesNotSyncGemfirePropertiesWhenNoPoolFactoryBeanIsDeclared() { + BeanDefinition clientCacheBean = newBeanDefinition(ClientCacheFactoryBean.class); + + clientCacheBean.getPropertyValues().addPropertyValue(PROPERTIES_PROPERTY_NAME_SHORTCUT, + new RuntimeBeanReference("gemfireProperties")); + + when(mockBeanFactory.getBeanDefinitionNames()).thenReturn(toArray("clientCacheBean")); + when(mockBeanFactory.getBeanDefinition(eq("clientCacheBean"))).thenReturn(clientCacheBean); + + beanFactoryPostProcessor.postProcessBeanFactory(mockBeanFactory); + + verify(mockBeanFactory, times(1)).getBeanDefinitionNames(); + verify(mockBeanFactory, times(1)).getBeanDefinition(eq("clientCacheBean")); + } + + @Test + public void postProcessDoesNotSyncWhenGemfirePropertiesAreUnspecified() { + BeanDefinition clientCacheBean = newBeanDefinition(ClientCacheFactoryBean.class); + BeanDefinition poolBean = newBeanDefinition(PoolFactoryBean.class); + + when(mockBeanFactory.getBeanDefinitionNames()).thenReturn(toArray("clientCacheBean", "poolBean")); + when(mockBeanFactory.getBeanDefinition(eq("clientCacheBean"))).thenReturn(clientCacheBean); + when(mockBeanFactory.getBeanDefinition(eq("poolBean"))).thenReturn(poolBean); + + assertThat(poolBean.getPropertyValues().getPropertyValue(PROPERTIES_PROPERTY_NAME_SHORTCUT), is(nullValue())); + + beanFactoryPostProcessor.postProcessBeanFactory(mockBeanFactory); + + assertThat(poolBean.getPropertyValues().getPropertyValue(PROPERTIES_PROPERTY_NAME_SHORTCUT), is(nullValue())); + + verify(mockBeanFactory, times(1)).getBeanDefinitionNames(); + verify(mockBeanFactory, times(1)).getBeanDefinition(eq("clientCacheBean")); + verify(mockBeanFactory, times(1)).getBeanDefinition(eq("poolBean")); + } + +}