diff --git a/src/main/java/org/springframework/data/gemfire/CacheFactoryBean.java b/src/main/java/org/springframework/data/gemfire/CacheFactoryBean.java index 44b04c88..44ab080c 100644 --- a/src/main/java/org/springframework/data/gemfire/CacheFactoryBean.java +++ b/src/main/java/org/springframework/data/gemfire/CacheFactoryBean.java @@ -16,6 +16,8 @@ package org.springframework.data.gemfire; +import static org.springframework.data.gemfire.support.GemfireBeanFactoryLocator.newBeanFactoryLocator; + import java.io.File; import java.io.IOException; import java.util.Arrays; @@ -54,6 +56,7 @@ import org.springframework.core.io.Resource; import org.springframework.dao.DataAccessException; import org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor; import org.springframework.dao.support.PersistenceExceptionTranslator; +import org.springframework.data.gemfire.support.GemfireBeanFactoryLocator; import org.springframework.data.gemfire.util.CollectionUtils; import org.springframework.util.Assert; import org.springframework.util.ObjectUtils; @@ -139,15 +142,23 @@ public class CacheFactoryBean implements BeanClassLoaderAware, BeanFactoryAware, private TransactionWriter transactionWriter; - /* - * (non-Javadoc) + /** + * @inheritDoc * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet() */ @Override public void afterPropertiesSet() throws Exception { + initBeanFactoryLocator(); postProcessBeforeCacheInitialization(resolveProperties()); } + /* (non-Javadoc) */ + private void initBeanFactoryLocator() { + if (useBeanFactoryLocator && beanFactoryLocator == null) { + beanFactoryLocator = newBeanFactoryLocator(this.beanFactory, this.beanName); + } + } + /* (non-Javadoc) */ protected void postProcessBeforeCacheInitialization(Properties gemfireProperties) { if (GemfireUtils.isGemfireVersion8OrAbove()) { @@ -180,9 +191,7 @@ public class CacheFactoryBean implements BeanClassLoaderAware, BeanFactoryAware, /* (non-Javadoc) */ Cache init() throws Exception { - initBeanFactoryLocator(); - - final ClassLoader currentThreadContextClassLoader = Thread.currentThread().getContextClassLoader(); + ClassLoader currentThreadContextClassLoader = Thread.currentThread().getContextClassLoader(); try { // use bean ClassLoader to load Spring configured, GemFire Declarable classes @@ -209,16 +218,6 @@ public class CacheFactoryBean implements BeanClassLoaderAware, BeanFactoryAware, } } - /* (non-Javadoc) */ - private void initBeanFactoryLocator() { - if (useBeanFactoryLocator && beanFactoryLocator == null) { - beanFactoryLocator = new GemfireBeanFactoryLocator(); - beanFactoryLocator.setBeanFactory(beanFactory); - beanFactoryLocator.setBeanName(beanName); - beanFactoryLocator.afterPropertiesSet(); - } - } - /** * If Dynamic Regions are enabled, create and initialize a DynamicRegionFactory before creating the Cache. */ diff --git a/src/main/java/org/springframework/data/gemfire/DeclarableSupport.java b/src/main/java/org/springframework/data/gemfire/DeclarableSupport.java deleted file mode 100644 index 8781043c..00000000 --- a/src/main/java/org/springframework/data/gemfire/DeclarableSupport.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * 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 java.util.Properties; - -import org.apache.geode.cache.CacheCallback; -import org.apache.geode.cache.Declarable; -import org.springframework.beans.factory.BeanFactory; -import org.springframework.beans.factory.access.BeanFactoryReference; - -/** - * Convenience class for Spring-aware GemFire Declarable components. Provides a reference to the current - * Spring ApplicationContext, e.g. for Spring bean lookup or resource loading. - * - * Note that in most cases, one can just declare the same components as Spring beans, through {@link RegionFactoryBean} - * which gives access to the full Spring container capabilities and does not enforce the {@link Declarable} interface - * to be implemented. - * - * @author Costin Leau - * @author John Blum - * @see org.springframework.beans.factory.BeanFactory - * @see org.springframework.beans.factory.access.BeanFactoryReference - * @see org.apache.geode.cache.CacheCallback - * @see org.apache.geode.cache.Declarable - */ -@SuppressWarnings("unused") -public abstract class DeclarableSupport implements CacheCallback, Declarable { - - private String beanFactoryKey = null; - - private BeanFactoryReference beanFactoryReference = null; - - public DeclarableSupport() { - } - - /** - * Gets a reference to the configured Spring BeanFactory. - * - * @return a Spring BeanFactory reference. - * @see org.springframework.beans.factory.BeanFactory - */ - protected BeanFactory getBeanFactory() { - return beanFactoryReference.getFactory(); - } - - /** - * Sets the key under which the enclosing BeanFactory can be found. Needed only if multiple BeanFactories - * are used with GemFire inside the same class loader / class space. - * - * @param key a String specifying the key used to lookup the "enclosing" BeanFactory in the presence - * of multiple BeanFactories. - * @see org.springframework.data.gemfire.GemfireBeanFactoryLocator - */ - public void setFactoryKey(String key) { - this.beanFactoryKey = key; - } - - /** - * This Declarable implementation uses the init method as a lifecycle hook to initialize the bean factory locator. - * - * {@inheritDoc} - * - * @see org.springframework.data.gemfire.GemfireBeanFactoryLocator - * @see #setFactoryKey(String) - */ - @Override - public final void init(Properties parameters) { - beanFactoryReference = new GemfireBeanFactoryLocator().useBeanFactory(beanFactoryKey); - initInstance(parameters); - } - - /** - * Initialize this Declarable object with the given Properties. - * - * @param props the Properties (parameters) used to initialize this Declarable. - * @see org.apache.geode.cache.Declarable#init(java.util.Properties) - * @see java.util.Properties - * @see #init(Properties) - */ - protected void initInstance(Properties props) { - } - - /* (non-Javadoc) */ - @Override - public void close() { - beanFactoryReference.release(); - beanFactoryReference = null; - } - -} diff --git a/src/main/java/org/springframework/data/gemfire/GemfireBeanFactoryLocator.java b/src/main/java/org/springframework/data/gemfire/GemfireBeanFactoryLocator.java deleted file mode 100644 index 52badccd..00000000 --- a/src/main/java/org/springframework/data/gemfire/GemfireBeanFactoryLocator.java +++ /dev/null @@ -1,166 +0,0 @@ -/* - * 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 java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.springframework.beans.BeansException; -import org.springframework.beans.FatalBeanException; -import org.springframework.beans.factory.BeanFactory; -import org.springframework.beans.factory.BeanFactoryAware; -import org.springframework.beans.factory.BeanNameAware; -import org.springframework.beans.factory.DisposableBean; -import org.springframework.beans.factory.InitializingBean; -import org.springframework.beans.factory.access.BeanFactoryLocator; -import org.springframework.beans.factory.access.BeanFactoryReference; -import org.springframework.util.Assert; -import org.springframework.util.ObjectUtils; -import org.springframework.util.StringUtils; - -/** - * {@link BeanFactoryLocator} used for storing Spring application context/bean factory for Gemfire - * user components (or {@link org.apache.geode.cache.Declarable}. As opposed to the "traditional" - * {@link org.springframework.beans.factory.access.SingletonBeanFactoryLocator} this implementation does - * not require any configuration file; it rather assume declaration inside an application context - * (usually through {@link org.apache.geode.cache.CacheFactory} which it will store under the name - * and aliases of the bean (so the same "registry" can be used for storing multiple BeanFactories). - * If there is only one BeanFactory registered then a null value can be used with {@link #setBeanName(String)}. - * - * In most cases, one does not need to use this class directly as it is used internally - * by {@link org.apache.geode.cache.CacheFactory}. - * - * @author Costin Leau - * @author John Blum - */ -public class GemfireBeanFactoryLocator implements BeanFactoryLocator, BeanFactoryAware, BeanNameAware, DisposableBean, - InitializingBean { - - private static final Log log = LogFactory.getLog(GemfireBeanFactoryLocator.class); - - // alias/bean name <-> BeanFactory lookup - private static final ConcurrentMap beanFactories = new ConcurrentHashMap(); - - // default factory to return - private static volatile boolean canUseDefaultBeanFactory = true; - private static volatile BeanFactory defaultFactory = null; - - private static class SimpleBeanFactoryReference implements BeanFactoryReference { - - private BeanFactory beanFactory; - - SimpleBeanFactoryReference(BeanFactory beanFactory) { - this.beanFactory = beanFactory; - } - - public BeanFactory getFactory() { - Assert.state(beanFactory != null, "The BeanFactory has already been released or closed"); - return beanFactory; - } - - public void release() throws FatalBeanException { - beanFactory = null; - } - } - - private BeanFactory beanFactory; - private String[] names; - - // default factory name - private String factoryName = GemfireBeanFactoryLocator.class.getName(); - - public void afterPropertiesSet() { - // add the factory as default if possible (if it's the only one) - synchronized (GemfireBeanFactoryLocator.class) { - canUseDefaultBeanFactory = beanFactories.isEmpty(); - if (canUseDefaultBeanFactory) { - if (defaultFactory == null) { - defaultFactory = beanFactory; - if (log.isDebugEnabled()) - log.debug("default beanFactoryReference=" + defaultFactory); - } - else { - if (log.isDebugEnabled()) - log.debug("more then one beanFactory - default not possible to determine"); - canUseDefaultBeanFactory = false; - defaultFactory = null; - } - } - } - - // add aliases - if (StringUtils.hasText(factoryName)) { - String[] aliases = beanFactory.getAliases(factoryName); - names = ObjectUtils.addObjectToArray(aliases, factoryName); - - for (String name : names) { - if (log.isDebugEnabled()) - log.debug("adding key=" + name + " w/ reference=" + beanFactory); - - if (beanFactories.containsKey(name) && !beanFactory.equals(beanFactories.get(name)) - || beanFactories.putIfAbsent(name, beanFactory) != null) { - throw new IllegalArgumentException("a beanFactoryReference already exists for key " + factoryName); - } - } - } - } - - public void destroy() { - if (names != null) { - for (String name : names) { - beanFactories.remove(name); - } - } - if (beanFactory == defaultFactory) { - synchronized (GemfireBeanFactoryLocator.class) { - defaultFactory = null; - canUseDefaultBeanFactory = beanFactories.isEmpty(); - } - } - } - - public BeanFactoryReference useBeanFactory(final String factoryKey) throws BeansException { - // see if there is a default FactoryBean - BeanFactory factory; - - if (!StringUtils.hasText(factoryKey)) { - if (!canUseDefaultBeanFactory) - throw new IllegalArgumentException( - "a non-null factoryKey needs to be specified as there are more then one factoryKeys available; " - + beanFactories.keySet()); - factory = defaultFactory; - } - else { - factory = beanFactories.get(factoryKey); - if (factory == null) - throw new IllegalArgumentException("there is no beanFactory under key " + factoryKey); - } - - return new SimpleBeanFactoryReference(factory); - } - - public void setBeanName(String name) { - factoryName = name; - } - - public void setBeanFactory(BeanFactory beanFactory) throws BeansException { - this.beanFactory = beanFactory; - } - -} diff --git a/src/main/java/org/springframework/data/gemfire/LazyWiringDeclarableSupport.java b/src/main/java/org/springframework/data/gemfire/LazyWiringDeclarableSupport.java deleted file mode 100644 index 792667a4..00000000 --- a/src/main/java/org/springframework/data/gemfire/LazyWiringDeclarableSupport.java +++ /dev/null @@ -1,324 +0,0 @@ -/* - * 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 java.util.Properties; -import java.util.concurrent.atomic.AtomicReference; - -import org.apache.geode.cache.Declarable; -import org.springframework.beans.factory.BeanFactory; -import org.springframework.beans.factory.DisposableBean; -import org.springframework.beans.factory.access.BeanFactoryReference; -import org.springframework.beans.factory.wiring.BeanConfigurerSupport; -import org.springframework.beans.factory.wiring.BeanWiringInfo; -import org.springframework.beans.factory.wiring.BeanWiringInfoResolver; -import org.springframework.context.ApplicationListener; -import org.springframework.context.ConfigurableApplicationContext; -import org.springframework.context.event.ContextRefreshedEvent; -import org.springframework.data.gemfire.support.SpringContextBootstrappingInitializer; -import org.springframework.util.Assert; -import org.springframework.util.ObjectUtils; -import org.springframework.util.StringUtils; - -/** - * The LazyWiringDeclarableSupport class is an implementation of the GemFire Declarable interface that enables support - * for wiring GemFire components with Spring bean dependencies defined in the Spring context. - * - * @author John Blum - * @see java.util.Properties - * @see org.springframework.beans.factory.DisposableBean - * @see org.springframework.beans.factory.wiring.BeanConfigurerSupport - * @see org.springframework.beans.factory.wiring.BeanWiringInfo - * @see org.springframework.beans.factory.wiring.BeanWiringInfoResolver - * @see org.springframework.context.ApplicationListener - * @see org.springframework.context.ConfigurableApplicationContext - * @see org.springframework.context.event.ContextRefreshedEvent - * @see org.springframework.data.gemfire.DeclarableSupport - * @see org.springframework.data.gemfire.WiringDeclarableSupport - * @see org.springframework.data.gemfire.support.SpringContextBootstrappingInitializer - * @see org.apache.geode.cache.Declarable - * @since 1.3.4 - */ -@SuppressWarnings("unused") -public abstract class LazyWiringDeclarableSupport implements ApplicationListener, Declarable, - DisposableBean { - - // name of the template bean defined in the Spring context for wiring this Declarable instance. - protected static final String BEAN_NAME_PARAMETER = "bean-name"; - - // atomic reference to the parameter passed by GemFire when this Declarable was constructed - // and the init method was called. - private final AtomicReference parametersReference = new AtomicReference(); - - // condition determining the initialization state of this Declarable - volatile boolean initialized = false; - - private BeanFactoryReference beanFactoryReference = null; - - private String factoryKey = null; - - /** - * Constructs an instance of the LazyWiringDeclarableSupport class registered with the - * SpringContextBootstrappingInitializer. This Declarable will receive notifications from the - * SpringContextBootstrappingInitializer when the Spring context is created and initialized (refreshed). - * The notification is necessary in order for this Declarable component to be configured and properly initialized - * with any required Spring bean dependencies. - * - * @see org.springframework.data.gemfire.support.SpringContextBootstrappingInitializer - * #register(org.springframework.context.ApplicationListener) - */ - public LazyWiringDeclarableSupport() { - SpringContextBootstrappingInitializer.register(this); - } - - /** - * Set the key used to locate (lookup) the Spring BeanFactory. - * - * @param factoryKey the key used to locate the Spring BeanFactory. - * @see org.springframework.beans.factory.BeanFactory - * @see org.springframework.data.gemfire.GemfireBeanFactoryLocator - * @see #getFactoryKey() - */ - public final void setFactoryKey(final String factoryKey) { - this.factoryKey = factoryKey; - } - - /** - * Gets the key used to locate (lookup) the Spring BeanFactory. - * - * @return the key used to locate the Spring BeanFactory. - * @see org.springframework.beans.factory.BeanFactory - * @see org.springframework.data.gemfire.GemfireBeanFactoryLocator - * @see #setFactoryKey(String) - */ - protected String getFactoryKey() { - return factoryKey; - } - - /** - * Asserts that this Declarable object has been properly configured and initialized by the Spring container - * after GemFire has constructed this Declarable object during startup. It is recommended to call this method - * in any GemFire CacheCallback/Declarable object operational method (e.g. CacheLoader.load(..)) before use - * in order to ensure that this Declarable was properly constructed, configured and initialized. - * - * @throws IllegalStateException if the Declarable object has not been properly configured or initialized - * by the Spring container. - * @see #init(java.util.Properties) - * @see #isInitialized() - */ - protected void assertInitialized() { - Assert.state(isInitialized(), String.format( - "This Declarable object (%1$s) has not been properly configured and initialized", - getClass().getName())); - } - - /** - * Asserts that this Declarable object has not yet been used, or activated prior to being fully configured - * and initialized. It is possible, though rare, that the init(:Properties) might be called multiple times - * by GemFire before the Spring container configure, initializes and puts this component to use. - * - * @throws java.lang.IllegalStateException if the Declarable object has already been configured and initialized - * by the Spring container. - * @see #init(java.util.Properties) - * @see #isInitialized() - */ - protected void assertUninitialized() { - Assert.state(!isInitialized(), String.format( - "This Declarable object (%1$s) has already been configured and initialized", - getClass().getName())); - } - - /** - * Performs the actual configuration and initialization of this Declarable object before use. This method - * is triggered by an ApplicationEvent (specifically, the ContextRefreshedEvent) indicating that the Spring context - * has been created and refreshed. - * - * @param beanFactory the ConfigurableListableBeanFactory used to configure and initialize this Declarable GemFire - * component. - * @param parameters Properties instance containing the parameters from GemFire's configuration file - * (e.g. cache.xml) to configure and initialize this Declarable object. - * @throws IllegalArgumentException if the bean-name parameter was specified in GemFire configuration meta-data - * but no bean with the specified name could be found in the Spring context. - * @see #init(java.util.Properties) - * @see #doPostInit(java.util.Properties) - * @see org.springframework.beans.factory.wiring.BeanConfigurerSupport - * @see org.springframework.beans.factory.wiring.BeanWiringInfo - * @see org.springframework.beans.factory.wiring.BeanWiringInfoResolver - */ - void doInit(final BeanFactory beanFactory, final Properties parameters) { - synchronized (this) { - if (isNotInitialized()) { - BeanConfigurerSupport beanConfigurer = new BeanConfigurerSupport(); - - beanConfigurer.setBeanFactory(beanFactory); - - final String templateBeanName = parameters.getProperty(BEAN_NAME_PARAMETER); - - if (StringUtils.hasText(templateBeanName)) { - if (beanFactory.containsBean(templateBeanName)) { - beanConfigurer.setBeanWiringInfoResolver(new BeanWiringInfoResolver() { - @Override public BeanWiringInfo resolveWiringInfo(final Object beanInstance) { - return new BeanWiringInfo(templateBeanName); - } - }); - } - else { - throw new IllegalArgumentException(String.format( - "No bean with name '%1$s' was found in the Spring context '%2$s'.", templateBeanName, beanFactory)); - } - } - - beanConfigurer.afterPropertiesSet(); - beanConfigurer.configureBean(this); - beanConfigurer.destroy(); - - initialized = true; - } - } - - doPostInit(parameters); - } - - /** - * Default no operation method performed post initialization of this Declarable GemFire component to be overridden - * by subclasses for application specific extension and behavior. - * - * @param parameters Properties instance containing the parameters from GemFire's configuration file - * (e.g. cache.xml) to configure and initialize this Declarable object. - * @see #doInit(BeanFactory, Properties) - */ - protected void doPostInit(final Properties parameters) { - } - - /** - * Initialization method called by GemFire with configured parameters once this Declarable object has been - * constructed during GemFire startup using an <initalizer> element in GemFire's configuration meta-data. - * - * @param parameters the configured parameters passed from the GemFire configuration (e.g. cache.xml) to this - * Declarable as a Properties instance. - * @throws IllegalStateException if this Declarable object has already been configured/initialized - * by the Spring container and is currently active. - * @see #doInit(BeanFactory, Properties) - * @see java.util.Properties - */ - @Override - public final void init(final Properties parameters) { - parametersReference.set(parameters); - - try { - doInit(locateBeanFactory(getFactoryKey()), nullSafeGetParameters()); - } - catch (IllegalStateException ignore) { - // the BeanFactory does not exist or has been released and or closed, so ignore - } - } - - /** - * Determines whether this Declarable object has been configured and initialized (i.e. the doInit method - * has been called) by the Spring container. - * - * @return a boolean value indicating whether this Declarable object has been configured and initialized - * by the Spring container. - * @see #assertInitialized() - * @see #doInit(BeanFactory, Properties) - */ - protected boolean isInitialized() { - return initialized; - } - - /** - * Determines whether this Declarable object has been configured and initialized (i.e. the doInit method - * has been called) by the Spring container. - * - * @return a boolean value indicating whether this Declarable object has been configured and initialized - * by the Spring container. - * @see #doInit(BeanFactory, Properties) - * @see #isInitialized() - */ - protected boolean isNotInitialized() { - return !isInitialized(); - } - - /** - * Locates an existing Spring BeanFactory. - * - * @param factoryKey the key used to locate (lookup) the Spring BeanFactory. - * @return a reference to the Spring BeanFactory if it exists. - * @throws IllegalStateException if the BeanFactory has already been released or closed. - * @see org.springframework.data.gemfire.GemfireBeanFactoryLocator - * @see org.springframework.beans.factory.BeanFactory - */ - protected BeanFactory locateBeanFactory(String factoryKey) { - if (beanFactoryReference == null) { - beanFactoryReference = new GemfireBeanFactoryLocator().useBeanFactory(factoryKey); - } - - return beanFactoryReference.getFactory(); - } - - /** - * Null-safe operation to return the parameters passed to this Declarable object when created by GemFire from it's - * configuration meta-data. - * - * @return a Properties object containing the a parameters specified for this Declarable, or an - * empty Properties object if no parameters were supplied. - * @see java.util.Properties - */ - protected Properties nullSafeGetParameters() { - Properties parameters = parametersReference.get(); - return (parameters != null ? parameters : new Properties()); - } - - /** - * Event handler method called when GemFire has created and initialized (refreshed) the Spring ApplicationContext - * using the SpringContextBootstrappingInitializer Declarable class. - * - * @param event the ContextRefreshedEvent published by the Spring ApplicationContext after it is successfully - * created and initialized by GemFire. - * @throws IllegalArgumentException if the ApplicationContext is not an instance of ConfigurableApplicationContext. - * @see #doInit(BeanFactory, Properties) - * @see #nullSafeGetParameters() - * @see org.springframework.context.ApplicationListener#onApplicationEvent(org.springframework.context.ApplicationEvent) - * @see org.springframework.context.event.ContextRefreshedEvent - */ - @Override - public final void onApplicationEvent(final ContextRefreshedEvent event) { - Assert.isTrue(event.getApplicationContext() instanceof ConfigurableApplicationContext, String.format( - "The Spring ApplicationContext (%1$s) must be an instance of ConfigurableApplicationContext", - ObjectUtils.nullSafeClassName(event.getApplicationContext()))); - - doInit(((ConfigurableApplicationContext) event.getApplicationContext()).getBeanFactory(), - nullSafeGetParameters()); - } - - /** - * When this bean gets destroyed by the Spring container, make sure this component gets unregistered from the - * SpringContextBootstrappingInitializer. - * - * @throws Exception if bean destruction is unsuccessful. - * @see org.springframework.data.gemfire.support.SpringContextBootstrappingInitializer - * #unregister(org.springframework.context.ApplicationListener) - */ - @Override - public void destroy() throws Exception { - SpringContextBootstrappingInitializer.unregister(this); - beanFactoryReference.release(); - parametersReference.set(null); - initialized = false; - } - -} diff --git a/src/main/java/org/springframework/data/gemfire/WiringDeclarableSupport.java b/src/main/java/org/springframework/data/gemfire/WiringDeclarableSupport.java deleted file mode 100644 index 4c515bed..00000000 --- a/src/main/java/org/springframework/data/gemfire/WiringDeclarableSupport.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * 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 java.util.Properties; - -import org.apache.geode.cache.Declarable; -import org.springframework.beans.factory.BeanFactory; -import org.springframework.beans.factory.wiring.BeanConfigurerSupport; -import org.springframework.beans.factory.wiring.BeanWiringInfo; -import org.springframework.beans.factory.wiring.BeanWiringInfoResolver; -import org.springframework.util.StringUtils; - -/** - * Dedicated {@link Declarable} support class for wiring the declaring instance through the Spring container. - * - *

This implementation first looks for a 'bean-name' property which will be used to locate a 'template' - * bean definition. Autowiring will be performed, based on the settings defined in the Spring container. - * - * @author Costin Leau - * @author John Blum - * @see org.springframework.beans.factory.BeanFactory - * @see org.springframework.beans.factory.wiring.BeanConfigurerSupport - * @see org.springframework.beans.factory.wiring.BeanWiringInfo - * @see org.springframework.data.gemfire.DeclarableSupport - * @see org.springframework.data.gemfire.LazyWiringDeclarableSupport - * @see org.apache.geode.cache.Declarable - * @deprecated please use LazyWiringDeclarableSupport instead. - */ -@Deprecated -public class WiringDeclarableSupport extends DeclarableSupport { - - private static final String BEAN_NAME_PROPERTY = "bean-name"; - - @Override - protected void initInstance(Properties parameters) { - BeanFactory beanFactory = getBeanFactory(); - - BeanConfigurerSupport beanConfigurer = new BeanConfigurerSupport(); - beanConfigurer.setBeanFactory(beanFactory); - - final String beanName = parameters.getProperty(BEAN_NAME_PROPERTY); - - if (StringUtils.hasText(beanName)) { - if (!beanFactory.containsBean(beanName)) { - throw new IllegalArgumentException(String.format("Cannot find bean named '%1$s'", beanName)); - } - - beanConfigurer.setBeanWiringInfoResolver(new BeanWiringInfoResolver() { - public BeanWiringInfo resolveWiringInfo(Object beanInstance) { - return new BeanWiringInfo(beanName); - } - }); - } - - beanConfigurer.afterPropertiesSet(); - beanConfigurer.configureBean(this); - beanConfigurer.destroy(); - } - -} diff --git a/src/main/java/org/springframework/data/gemfire/config/annotation/CacheServerApplication.java b/src/main/java/org/springframework/data/gemfire/config/annotation/CacheServerApplication.java index a1ac04ff..f8ebfa37 100644 --- a/src/main/java/org/springframework/data/gemfire/config/annotation/CacheServerApplication.java +++ b/src/main/java/org/springframework/data/gemfire/config/annotation/CacheServerApplication.java @@ -28,7 +28,6 @@ import org.apache.geode.cache.control.ResourceManager; import org.apache.geode.cache.server.CacheServer; import org.apache.geode.cache.server.ClientSubscriptionConfig; import org.springframework.beans.factory.BeanFactory; -import org.springframework.beans.factory.access.BeanFactoryLocator; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; import org.springframework.data.gemfire.server.SubscriptionEvictionPolicy; @@ -236,7 +235,7 @@ public @interface CacheServerApplication { SubscriptionEvictionPolicy subscriptionEvictionPolicy() default SubscriptionEvictionPolicy.NONE; /** - * Determines whether the Spring {@link BeanFactoryLocator} should be enabled to lookup + * Determines whether the Spring {@link BeanFactory} locator should be enabled to lookup * the Spring {@link BeanFactory} to auto-wire and configure/initialize GemFire components * created in a non-Spring managed, GemFire context. * diff --git a/src/main/java/org/springframework/data/gemfire/config/annotation/ClientCacheApplication.java b/src/main/java/org/springframework/data/gemfire/config/annotation/ClientCacheApplication.java index 2c3981fd..264554ae 100644 --- a/src/main/java/org/springframework/data/gemfire/config/annotation/ClientCacheApplication.java +++ b/src/main/java/org/springframework/data/gemfire/config/annotation/ClientCacheApplication.java @@ -27,10 +27,10 @@ import java.lang.annotation.Target; import org.apache.geode.cache.client.PoolFactory; import org.apache.geode.cache.control.ResourceManager; import org.springframework.beans.factory.BeanFactory; -import org.springframework.beans.factory.access.BeanFactoryLocator; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; import org.springframework.data.gemfire.GemfireUtils; +import org.springframework.data.gemfire.support.GemfireBeanFactoryLocator; /** * The {@link ClientCacheApplication} annotation enables a Spring Data GemFire based application to become @@ -259,7 +259,7 @@ public @interface ClientCacheApplication { boolean threadLocalConnections() default PoolFactory.DEFAULT_THREAD_LOCAL_CONNECTIONS; /** - * Determines whether the Spring {@link BeanFactoryLocator} should be enabled to lookup + * Determines whether the {@link GemfireBeanFactoryLocator} should be enabled to lookup * the Spring {@link BeanFactory} to auto-wire and configure/initialize GemFire components * created in a non-Spring managed, GemFire context. * diff --git a/src/main/java/org/springframework/data/gemfire/config/annotation/PeerCacheApplication.java b/src/main/java/org/springframework/data/gemfire/config/annotation/PeerCacheApplication.java index e107391d..97ecac58 100644 --- a/src/main/java/org/springframework/data/gemfire/config/annotation/PeerCacheApplication.java +++ b/src/main/java/org/springframework/data/gemfire/config/annotation/PeerCacheApplication.java @@ -26,9 +26,9 @@ import java.lang.annotation.Target; import org.apache.geode.cache.control.ResourceManager; import org.springframework.beans.factory.BeanFactory; -import org.springframework.beans.factory.access.BeanFactoryLocator; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; +import org.springframework.data.gemfire.support.GemfireBeanFactoryLocator; /** * The {@link PeerCacheApplication} annotation enables an embedded GemFire peer {@link org.apache.geode.cache.Cache} @@ -131,7 +131,7 @@ public @interface PeerCacheApplication { int searchTimeout() default 300; /** - * Determines whether the Spring {@link BeanFactoryLocator} should be enabled to lookup + * Determines whether the {@link GemfireBeanFactoryLocator} should be enabled to lookup * the Spring {@link BeanFactory} to auto-wire and configure/initialize GemFire components * created in a non-Spring managed, GemFire context. * diff --git a/src/main/java/org/springframework/data/gemfire/support/DeclarableSupport.java b/src/main/java/org/springframework/data/gemfire/support/DeclarableSupport.java new file mode 100644 index 00000000..2829c1a8 --- /dev/null +++ b/src/main/java/org/springframework/data/gemfire/support/DeclarableSupport.java @@ -0,0 +1,107 @@ +/* + * Copyright 2016 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.support; + +import static org.springframework.data.gemfire.support.GemfireBeanFactoryLocator.newBeanFactoryLocator; + +import org.apache.geode.cache.CacheCallback; +import org.apache.geode.cache.Declarable; +import org.springframework.beans.factory.BeanFactory; +import org.springframework.data.gemfire.RegionFactoryBean; + +/** + * Convenience class for Spring-aware GemFire {@link Declarable} components. Provides subclasses with a reference + * to the current Spring {@link BeanFactory} in orde to perform Spring bean lookups or resource loading. + * + * Note, in most cases, the developer should just declare the same components as Spring beans in the Spring container, + * through {@link RegionFactoryBean}, which gives access to the full Spring container capabilities and does not + * enforce the {@link Declarable} interface to be implemented. + * + * @author Costin Leau + * @author John Blum + * @see org.springframework.beans.factory.BeanFactory + * @see org.springframework.data.gemfire.support.GemfireBeanFactoryLocator + * @see org.apache.geode.cache.CacheCallback + * @see org.apache.geode.cache.Declarable + */ +@SuppressWarnings("unused") +public abstract class DeclarableSupport implements CacheCallback, Declarable { + + private String beanFactoryKey = null; + + /** + * Returns a reference to the Spring {@link BeanFactory}. + * + * @return a reference to the Spring {@link BeanFactory}. + * @see org.springframework.data.gemfire.support.GemfireBeanFactoryLocator#useBeanFactory(String) + * @see org.springframework.beans.factory.BeanFactory + * @see #locateBeanFactory() + */ + protected BeanFactory getBeanFactory() { + return locateBeanFactory(); + } + + /** + * Set the key used to lookup the Spring {@link BeanFactory}. + * + * @param beanFactoryKey {@link String} containing the key used to lookup the Spring {@link BeanFactory}. + */ + public void setBeanFactoryKey(String beanFactoryKey) { + this.beanFactoryKey = beanFactoryKey; + } + + /** + * Returns the key used to lookup the Spring {@link BeanFactory}. + * + * @return a {@link String} containing the key used to lookup the Spring {@link BeanFactory}. + */ + protected String getBeanFactoryKey() { + return this.beanFactoryKey; + } + + /** + * Returns a reference to the Spring {@link BeanFactory}. + * + * @return a reference to the Spring {@link BeanFactory}. + * @see org.springframework.beans.factory.BeanFactory + * @see #locateBeanFactory(String) + * @see #getBeanFactoryKey() + */ + protected BeanFactory locateBeanFactory() { + return locateBeanFactory(getBeanFactoryKey()); + } + + /** + * Returns a reference to the Spring {@link BeanFactory} for the given {@code beanFactoryKey}. + * + * @param beanFactoryKey {@link String} containing the key used to lookup the Spring {@link BeanFactory}. + * @return a reference to the Spring {@link BeanFactory} for the given {@code beanFactoryKey}. + * @see org.springframework.data.gemfire.support.GemfireBeanFactoryLocator#useBeanFactory(String) + * @see org.springframework.beans.factory.BeanFactory + */ + protected BeanFactory locateBeanFactory(String beanFactoryKey) { + return newBeanFactoryLocator().useBeanFactory(beanFactoryKey); + } + + /** + * @inheritDoc + */ + @Override + public void close() { + } +} diff --git a/src/main/java/org/springframework/data/gemfire/support/GemfireBeanFactoryLocator.java b/src/main/java/org/springframework/data/gemfire/support/GemfireBeanFactoryLocator.java new file mode 100644 index 00000000..31d752bd --- /dev/null +++ b/src/main/java/org/springframework/data/gemfire/support/GemfireBeanFactoryLocator.java @@ -0,0 +1,389 @@ +/* + * Copyright 2016 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.support; + +import static org.springframework.data.gemfire.support.GemfireBeanFactoryLocator.BeanFactoryReference.newBeanFactoryReference; +import static org.springframework.data.gemfire.util.CollectionUtils.nullSafeSet; +import static org.springframework.data.gemfire.util.SpringUtils.nullOrEquals; + +import java.util.Collections; +import java.util.Set; +import java.util.TreeSet; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.atomic.AtomicReference; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.BeanFactoryAware; +import org.springframework.beans.factory.BeanNameAware; +import org.springframework.beans.factory.DisposableBean; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.util.Assert; +import org.springframework.util.StringUtils; + +/** + * The {@link GemfireBeanFactoryLocator} class stores a reference to the Spring + * {@link org.springframework.context.ApplicationContext} / {@link BeanFactory} needed to auto-wire + * user application GemFire objects implementing the {@link org.apache.geode.cache.Declarable} interface + * and defined in GemFire's native configuration format (e.g. {@literal cache.xml}. + * + * In most cases, a developer does not need to use this class directly as it is registered by the + * {@link org.springframework.data.gemfire.CacheFactoryBean} when the {@literal useBeanFactoryLocator} property + * is set, and used internally by bothe the {@link WiringDeclarableSupport} and {@link LazyWiringDeclarableSupport} + * SDG classes. + * + * @author Costin Leau + * @author John Blum + * @see LazyWiringDeclarableSupport + * @see WiringDeclarableSupport + */ +@SuppressWarnings("all") +public class GemfireBeanFactoryLocator implements BeanFactoryAware, BeanNameAware, DisposableBean, InitializingBean { + + // bean alias/name <-> BeanFactory mapping + protected static final ConcurrentMap BEAN_FACTORIES = new ConcurrentHashMap<>(); + + private BeanFactory beanFactory; + + protected final Log logger = LogFactory.getLog(getClass()); + + private Set associatedBeanNameWithAliases = Collections.emptySet(); + + private String associatedBeanName; + + /** + * Factory method to construct a new, initialized instance of {@link GemfireBeanFactoryLocator}. + * + * @return a new, initialized instance of the {@link GemfireBeanFactoryLocator}. + * @see GemfireBeanFactoryLocator + * @see #GemfireBeanFactoryLocator() + * @see #afterPropertiesSet() + */ + public static GemfireBeanFactoryLocator newBeanFactoryLocator() { + GemfireBeanFactoryLocator beanFactoryLocator = new GemfireBeanFactoryLocator(); + beanFactoryLocator.afterPropertiesSet(); + return beanFactoryLocator; + } + + /** + * Factory method to construct a new, initialized instance of {@link GemfireBeanFactoryLocator} with the given + * default Spring {@link BeanFactory} and associated Spring bean name. + * + * @param beanFactory reference to the {@link BeanFactory} used to resolve Spring bean references. + * @param associatedBeanName {@link String} contain the name of the Spring bean associated with + * the Spring {@link BeanFactory}. + * @return a new, initialized instance of {@link GemfireBeanFactoryLocator} with the given default + * Spring {@link BeanFactory} and associated Spring bean name. + * @see org.springframework.beans.factory.BeanFactory + * @see GemfireBeanFactoryLocator + * @see #GemfireBeanFactoryLocator() + * @see #setBeanFactory(BeanFactory) + * @see #setBeanName(String) + * @see #afterPropertiesSet() + */ + public static GemfireBeanFactoryLocator newBeanFactoryLocator(BeanFactory beanFactory, String associatedBeanName) { + Assert.isTrue(beanFactory == null || StringUtils.hasText(associatedBeanName), + "associatedBeanName must be specified when BeanFactory is not null"); + + GemfireBeanFactoryLocator beanFactoryLocator = new GemfireBeanFactoryLocator(); + + beanFactoryLocator.setBeanFactory(beanFactory); + beanFactoryLocator.setBeanName(associatedBeanName); + beanFactoryLocator.afterPropertiesSet(); + + return beanFactoryLocator; + } + + /** + * Resolves the {@link BeanFactory} mapped to the given {@code beanFactoryKey}. + * + * @param beanFactoryKey {@link String} value containing the key used to lookup the {@link BeanFactory}. + * @return the {@link BeanFactory} mapped to the given key. + * @throws IllegalArgumentException if a Spring {@link BeanFactory} could not be found + * for the given {@code beanFactoryKey}. + * @see org.springframework.beans.factory.BeanFactory + */ + protected static BeanFactory resolveBeanFactory(String beanFactoryKey) { + BeanFactory beanFactory = BEAN_FACTORIES.get(beanFactoryKey); + + Assert.isTrue(BEAN_FACTORIES.isEmpty() || beanFactory != null, + String.format("BeanFactory for key [%s] was not found", beanFactoryKey)); + + return beanFactory; + } + + /** + * Resolves a single Spring {@link BeanFactory} from the mapping of registered bean factories. + * + * This class method is synchronized because it contains a "compound action", even though separate actions + * are performed on a {@link ConcurrentMap}, the actions are not independent and therefore must operate + * atomically. + * + * @return a single Spring {@link BeanFactory} from the registry. + * @throws IllegalStateException if the registry contains more than 1, or no + * Spring {@link BeanFactory bean factories}. + * @see org.springframework.beans.factory.BeanFactory + */ + protected static synchronized BeanFactory resolveSingleBeanFactory() { + if (!BEAN_FACTORIES.isEmpty()) { + boolean allTheSameBeanFactory = true; + + BeanFactory currentBeanFactory = null; + + for (BeanFactory beanFactory : BEAN_FACTORIES.values()) { + allTheSameBeanFactory &= nullOrEquals(currentBeanFactory, beanFactory); + currentBeanFactory = beanFactory; + + if (!allTheSameBeanFactory) { + break; + } + } + + Assert.state(allTheSameBeanFactory, String.format( + "BeanFactory key must be specified when more than one BeanFactory %s is registered", + new TreeSet(BEAN_FACTORIES.keySet()).toString())); + + return BEAN_FACTORIES.values().iterator().next(); + } + + return null; + } + + /** + * Registers all the provided names for given Spring {@link BeanFactory}. + * + * @param names {@link Set} of names and aliases to associate with the Spring {@link BeanFactory}. + * @param beanFactory reference to the Spring {@link BeanFactory}. + * @see org.springframework.beans.factory.BeanFactory + * @throws IllegalArgumentException if {@link BeanFactory} is {@literal null}. + * @throws IllegalStateException if one of the provided names is already associated with + * an existing, other than given, Spring {@link BeanFactory}. + * @see org.springframework.beans.factory.BeanFactory + */ + protected static synchronized void registerAliases(Set names, BeanFactory beanFactory) { + Assert.isTrue(nullSafeSet(names).isEmpty() || beanFactory != null, + "BeanFactory must not be null when aliases are specified"); + + for (String name : nullSafeSet(names)) { + BeanFactory existingBeanFactory = BEAN_FACTORIES.putIfAbsent(name, beanFactory); + + Assert.isTrue(nullOrEquals(existingBeanFactory, beanFactory), + String.format("BeanFactory reference already exists for key [%s]", name)); + } + } + + /** + * Removes all Spring {@link BeanFactory} associations/mappings for the given {@link Set} of names. + * + * @param names {@link Set} of names identifying the associations/mappings to remove. + * @return a boolean value indicating whether all associations/mappings were removed successfully. + */ + protected static synchronized boolean unregisterAliases(Set names) { + return BEAN_FACTORIES.keySet().removeAll(names); + } + + /** + * @inheritDoc + */ + @Override + public void afterPropertiesSet() { + BeanFactory beanFactory = getBeanFactory(); + + registerAliases(resolveAndInitializeBeanNamesWithAliases(beanFactory), beanFactory); + } + + /** + * Resolves all names (including aliases) from the given Spring {@link BeanFactory} + * assigned to the {@link #getAssociatedBeanName()}. + * + * @param beanFactory {@link BeanFactory} used to resolve the names assigned to the Spring bean + * identified by the {@link #getAssociatedBeanName()}. + * @return a {@link Set} of all the names assigned to the Spring bean identified by + * the {@link #getAssociatedBeanName()} using the provided Spring {@link BeanFactory}. + * @see org.springframework.beans.factory.BeanFactory + * @see #getAssociatedBeanName() + */ + Set resolveAndInitializeBeanNamesWithAliases(BeanFactory beanFactory) { + String associatedBeanName = getAssociatedBeanName(); + + if (beanFactory != null && StringUtils.hasText(associatedBeanName)) { + String[] beanAliases = beanFactory.getAliases(associatedBeanName); + + this.associatedBeanNameWithAliases = new TreeSet<>(); + this.associatedBeanNameWithAliases.add(associatedBeanName); + + Collections.addAll(this.associatedBeanNameWithAliases, beanAliases); + } + + return this.associatedBeanNameWithAliases; + } + + /** + * @inheritDoc + */ + @Override + public void destroy() { + unregisterAliases(getAssociatedBeanNameWithAliases()); + } + + /** + * Attempts to use a single, existing Spring {@link BeanFactory} from the registry based on + * the {@link #setBeanName(String)} beanName} property. + * + * @return the single Spring {@link BeanFactory} from the registry. + * @throws IllegalStateException if the {@link BeanFactory} with the associated + * {@link #setBeanName(String) beanName} is not found. + * @see org.springframework.beans.factory.BeanFactory + * @see #getAssociatedBeanName() + * @see #useBeanFactory(String) + */ + public BeanFactory useBeanFactory() { + return useBeanFactory(getAssociatedBeanName()); + } + + /** + * + * @param beanFactoryKey + * @return + */ + public BeanFactory useBeanFactory(String beanFactoryKey) { + return newBeanFactoryReference(StringUtils.hasText(beanFactoryKey) ? resolveBeanFactory(beanFactoryKey) + : resolveSingleBeanFactory()).get(); + } + + /** + * @inheritDoc + */ + @Override + public void setBeanFactory(BeanFactory beanFactory) { + this.beanFactory = beanFactory; + } + + /** + * Returns a reference to the {@link BeanFactory} managed by this {@link GemfireBeanFactoryLocator} instance; + * Might be {@literal null} if this {@link GemfireBeanFactoryLocator} is just used to lookup + * an existing {@link BeanFactory} reference. + * + * @return the managed {@link BeanFactory} reference. + * @see org.springframework.beans.factory.BeanFactory + */ + protected BeanFactory getBeanFactory() { + return this.beanFactory; + } + + /** + * @inheritDoc + */ + @Override + public void setBeanName(String name) { + this.associatedBeanName = name; + } + + /** + * Gets the name of the Spring bean associated with the Spring {@link BeanFactory} that possibly created the bean. + * + * @return a {@link String} containing the name of the Spring bean associated with the Spring {@link BeanFactory}. + * @see #setBeanFactory(BeanFactory) + */ + protected String getAssociatedBeanName() { + return this.associatedBeanName; + } + + /** + * Returns a {@link Set} of all names and aliases assigned to the Spring bean that is associated with + * the Spring {@link BeanFactory}. + * + * @return a {@link Set} containing all the names and aliases assigned to the Spring bean associated with + * the Spring {@link BeanFactory}. + * @see #setBeanName(String) + */ + protected Set getAssociatedBeanNameWithAliases() { + return Collections.unmodifiableSet(nullSafeSet(this.associatedBeanNameWithAliases)); + } + + /** + * Builder method to set the bean name used by this locator to lookup a Spring {@link BeanFactory}. + * + * @param beanName {@link String} containing the bean name to set on this locator. + * @return this {@link GemfireBeanFactoryLocator}. + * @see #setBeanName(String) + */ + public GemfireBeanFactoryLocator withBeanName(String beanName) { + setBeanName(beanName); + return this; + } + + /** + * Reference holder storing a reference to a Spring {@link BeanFactory}. + * + * @see org.springframework.beans.factory.BeanFactory + */ + protected static class BeanFactoryReference { + + protected static final String UNINITIALIZED_BEAN_FACTORY_REFERENCE_MESSAGE = + "A BeanFactory was not initialized; Please verify the useBeanFactoryLocator property was properly set"; + + private final AtomicReference beanFactory = new AtomicReference<>(null); + + /** + * Factory method to construct an instance of {@link BeanFactoryReference} initialized + * with the given {@link BeanFactory}. + * + * @param beanFactory {@link BeanFactory} reference to store. + * @return a new instance of {@link BeanFactoryReference} initialized with the given {@link BeanFactory}. + * @see org.springframework.beans.factory.BeanFactory + * @see #BeanFactoryReference(BeanFactory) + */ + public static BeanFactoryReference newBeanFactoryReference(BeanFactory beanFactory) { + return new BeanFactoryReference(beanFactory); + } + + /** + * Constructs an instance of {@link BeanFactoryReference} initialized with the given {@link BeanFactory}. + * + * @param beanFactory {@link BeanFactory} reference to store; may be {@literal null}. + * @see org.springframework.beans.factory.BeanFactory + */ + public BeanFactoryReference(BeanFactory beanFactory) { + this.beanFactory.set(beanFactory); + } + + /** + * Returns the reference to the Spring {@link BeanFactory}. + * + * @return a reference to the Spring {@link BeanFactory}. + * @see org.springframework.beans.factory.BeanFactory + */ + public BeanFactory get() { + BeanFactory beanFactory = this.beanFactory.get(); + + Assert.state(beanFactory != null, UNINITIALIZED_BEAN_FACTORY_REFERENCE_MESSAGE); + + return beanFactory; + } + + /** + * Releases the stored reference to the Spring {@link BeanFactory}. + */ + public void release() { + this.beanFactory.set(null); + } + } +} diff --git a/src/main/java/org/springframework/data/gemfire/support/LazyWiringDeclarableSupport.java b/src/main/java/org/springframework/data/gemfire/support/LazyWiringDeclarableSupport.java new file mode 100644 index 00000000..3a406926 --- /dev/null +++ b/src/main/java/org/springframework/data/gemfire/support/LazyWiringDeclarableSupport.java @@ -0,0 +1,261 @@ +/* + * Copyright 2016 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.support; + +import java.util.Properties; +import java.util.concurrent.atomic.AtomicReference; + +import org.apache.geode.cache.CacheCallback; +import org.apache.geode.cache.CacheLoader; +import org.apache.geode.cache.Declarable; +import org.apache.geode.cache.LoaderHelper; +import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.DisposableBean; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationListener; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.context.event.ContextRefreshedEvent; +import org.springframework.util.Assert; + +/** + * The {@link LazyWiringDeclarableSupport} class is an implementation of GemFire's {@link Declarable} interface + * that enables support for wiring GemFire components with Spring bean dependencies defined in + * a Spring {@link ApplicationContext}. + * + * @author John Blum + * @see org.springframework.beans.factory.BeanFactory + * @see org.springframework.beans.factory.DisposableBean + * @see org.springframework.context.ApplicationContext + * @see org.springframework.context.ApplicationListener + * @see org.springframework.context.event.ContextRefreshedEvent + * @see org.springframework.data.gemfire.support.SpringContextBootstrappingInitializer + * @see org.springframework.data.gemfire.support.WiringDeclarableSupport + * @see org.apache.geode.cache.Declarable + * @since 1.3.4 + */ +@SuppressWarnings("unused") +public abstract class LazyWiringDeclarableSupport extends WiringDeclarableSupport + implements ApplicationListener, DisposableBean { + + // atomic reference to the parameters passed by GemFire when this Declarable object + // was constructed, configured and its init method called + private final AtomicReference parametersReference = new AtomicReference<>(); + + // condition to determine the initialized state of this Declarable object + volatile boolean initialized = false; + + /** + * Constructs a new instance of the {@link LazyWiringDeclarableSupport} class registered with the + * {@link SpringContextBootstrappingInitializer} as a Spring {@link ApplicationListener}. + * + * This {@link Declarable} object will receive notifications from the {@link SpringContextBootstrappingInitializer} + * when the Spring context is created and initialized (refreshed). The notification is necessary in order for + * this {@link Declarable} object to be properly configured and initialized with any required, + * Spring-defined dependencies. + * + * @see org.springframework.data.gemfire.support.SpringContextBootstrappingInitializer + * #register(org.springframework.context.ApplicationListener) + */ + public LazyWiringDeclarableSupport() { + SpringContextBootstrappingInitializer.register(this); + } + + /** + * Asserts that this {@link Declarable} object has been properly configured and initialized by the Spring container + * after has GemFire constructed this {@link Declarable} object during startup. + * + * This method is recommended to be called before any of this {@link Declarable} object's {@link CacheCallback} + * methods (e.g. {@link CacheLoader#load(LoaderHelper)} are invoked in order to ensure that this {@link Declarable} + * object was properly constructed, configured and initialized by the Spring container before hand. + * + * @throws IllegalStateException if this {@link Declarable} object was not been properly constructed, configured + * and initialized by the Spring container. + * @see #init(java.util.Properties) + * @see #isInitialized() + */ + protected void assertInitialized() { + Assert.state(isInitialized(), String.format( + "This Declarable object [%s] has not been properly configured and initialized", getClass().getName())); + } + + /** + * Asserts that this {@link Declarable} object has not yet been used, or activated prior to being fully constructed, + * configured and initialized by the Spring container. + * + * It is possible, though rare, that the {@link #init(Properties)} method might be called multiple times by GemFire + * before the Spring container constructs, configures, initializes and generally puts this component to use. + * + * @throws java.lang.IllegalStateException if the Declarable object has already been configured and initialized + * by the Spring container. + * @see #init(java.util.Properties) + * @see #isNotInitialized() + */ + protected void assertUninitialized() { + Assert.state(isNotInitialized(), String.format( + "This Declarable object [%s] has already been configured and initialized", getClass().getName())); + } + + /** + * Determines whether this {@link Declarable} object has been properly configured and initialized + * by the Spring container. + * + * @return a boolean value indicating whether this {@link Declarable} object has been properly configured + * and initialized by the Spring container. + * @see #doInit(Properties) + * @see #assertInitialized() + */ + protected boolean isInitialized() { + return this.initialized; + } + + /** + * Determines whether this {@link Declarable} object has been properly configured and initialized + * by the Spring container. + * + * @return a boolean value indicating whether this {@link Declarable} object has been properly configured + * and initialized by the Spring container. + * @see #doInit(Properties) + * @see #isInitialized() + */ + protected boolean isNotInitialized() { + return !isInitialized(); + } + + /** + * Initialization method called by GemFire with the configured parameters once this {@link Declarable} object + * has been constructed by GemFire and the <initalizer> element is parsed + * in GemFire's configuration meta-data during startup. + * + * @param parameters {@link Properties} containing the configured parameters parsed from GemFire's + * configuration meta-data (e.g. {@literal cache.xml}) and passed to this {@link Declarable} object. + * @see #doInit(Properties) + * @see java.util.Properties + */ + @Override + public final void init(Properties parameters) { + setParameters(parameters); + + try { + doInit(locateBeanFactory(), nullSafeGetParameters()); + } + catch (IllegalStateException ignore) { + // BeanFactory does not exist, has been closed or the GemfireBeanFactoryLocator is not in use + } + } + + /** + * Performs the actual configuration and initialization of this {@link Declarable} object before use. + * + * This method is triggered by the Spring {@link org.springframework.context.ApplicationContext}, Spring application + * {@link ContextRefreshedEvent}) indicating that the Spring container (context) has been created and refreshed. + * + * @param parameters {@link Properties} containing the configured parameters parsed from GemFire's + * configuration meta-data (e.g. {@literal cache.xml}) and passed to this {@link Declarable} object. + * @throws IllegalArgumentException if the {@literal bean-name} parameter was specified in GemFire's + * configuration meta-data but no bean with the specified name could be found in the Spring context. + * @see #init(java.util.Properties) + * @see #configureThis(BeanFactory, String) + * @see #doPostInit(java.util.Properties) + * @see java.util.Properties + */ + synchronized void doInit(BeanFactory beanFactory, Properties parameters) { + this.initialized = (isInitialized() || configureThis(beanFactory, + parameters.getProperty(TEMPLATE_BEAN_NAME_PROPERTY))); + + doPostInit(parameters); + } + + /** + * Performs any post configuration and initialization activities required by the application. + * + * By default, this method does nothing. + * + * @param parameters {@link Properties} containing the configured parameters parsed from GemFire's + * configuration meta-data (e.g. {@literal cache.xml}) and passed to this {@link Declarable} object. + * @see #doInit(Properties) + * @see java.util.Properties + */ + protected void doPostInit(Properties parameters) { + } + + /** + * Null-safe operation to return the parameters passed to this {@link Declarable} object when created by GemFire + * from it's own configuration meta-data (e.g. {@literal cache.xml}). + * + * @return a {@link Properties} containing the configured parameters parsed from GemFire's configuration meta-data + * (e.g. {@literal cache.xml}) and passed to this {@link Declarable} object. + * @see java.util.Properties + */ + protected Properties nullSafeGetParameters() { + Properties parameters = parametersReference.get(); + return (parameters != null ? parameters : new Properties()); + } + + /** + * Stores a reference to the {@link Properties parameters} passed to the {@link Declarable#init(Properties)} method. + * + * @param parameters {@link Properties} containing the configured parameters parsed from GemFire's + * configuration meta-data (e.g. {@literal cache.xml}) and passed to this {@link Declarable} object. + * @see java.util.Properties + */ + protected void setParameters(Properties parameters) { + parametersReference.set(parameters); + } + + /** + * Event handler method called when GemFire has created and initialized (refreshed) + * the Spring {@link ApplicationContext} using the {@link SpringContextBootstrappingInitializer}. + * + * @param event {@link ContextRefreshedEvent} published by the Spring {@link ApplicationContext} after it is + * successfully created and initialized by GemFire. + * @see org.springframework.context.event.ContextRefreshedEvent + * @see #doInit(BeanFactory, Properties) + * @see #nullSafeGetParameters() + */ + @Override + @SuppressWarnings("all") + public final void onApplicationEvent(ContextRefreshedEvent event) { + ApplicationContext applicationContext = event.getApplicationContext(); + + Assert.isTrue(applicationContext instanceof ConfigurableApplicationContext, String.format( + "The Spring ApplicationContext [%s] must be an instance of ConfigurableApplicationContext", + applicationContext)); + + ConfigurableListableBeanFactory beanFactory = + ((ConfigurableApplicationContext) applicationContext).getBeanFactory(); + + doInit(beanFactory, nullSafeGetParameters()); + } + + /** + * When this {@link Declarable} object/bean gets destroyed by the Spring container, {@code destroy()} will + * make sure this component gets unregistered from the {@link SpringContextBootstrappingInitializer} properly. + * + * @throws Exception if bean destruction is unsuccessful. + * @see org.springframework.data.gemfire.support.SpringContextBootstrappingInitializer + * #unregister(org.springframework.context.ApplicationListener) + * @see #setParameters(Properties) + */ + @Override + public void destroy() throws Exception { + SpringContextBootstrappingInitializer.unregister(this); + setParameters(null); + this.initialized = false; + } +} diff --git a/src/main/java/org/springframework/data/gemfire/support/SpringContextBootstrappingInitializer.java b/src/main/java/org/springframework/data/gemfire/support/SpringContextBootstrappingInitializer.java index 7a544a44..0f75e4d9 100644 --- a/src/main/java/org/springframework/data/gemfire/support/SpringContextBootstrappingInitializer.java +++ b/src/main/java/org/springframework/data/gemfire/support/SpringContextBootstrappingInitializer.java @@ -25,6 +25,7 @@ import java.util.concurrent.atomic.AtomicReference; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.apache.geode.cache.Cache; import org.apache.geode.cache.Declarable; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextException; @@ -44,11 +45,11 @@ import org.springframework.util.ObjectUtils; import org.springframework.util.StringUtils; /** - * The SpringContextBootstrappingInitializer class is a GemFire configuration initializer used to bootstrap a Spring - * ApplicationContext inside a GemFire Server JVM-based process. This enables a GemFire Cache Server resources to be - * mostly configured with Spring Data GemFire's XML namespace. The Cache itself is the only resource that cannot be - * configured and initialized in a Spring context since the initializer is not invoked until after GemFire creates - * and initializes the Cache for use. + * The {@link SpringContextBootstrappingInitializer} class is a GemFire configuration initializer used to bootstrap + * a Spring {@link ApplicationContext} inside a GemFire Server JVM-based process. This enables a GemFire Server + * resource to be mostly configured with Spring Data GemFire's configuration meta-data. The GemFire {@link Cache} + * itself is the only resource that cannot be configured and initialized in a Spring context since the initializer + * is not invoked until after GemFire creates and initializes the GemFire {@link Cache} for use. * * @author John Blum * @see org.springframework.context.ApplicationContext @@ -58,6 +59,8 @@ import org.springframework.util.StringUtils; * @see org.springframework.context.event.ApplicationContextEvent * @see org.springframework.context.event.ApplicationEventMulticaster * @see org.springframework.context.support.ClassPathXmlApplicationContext + * @see org.springframework.core.io.DefaultResourceLoader + * @see org.apache.geode.cache.Cache * @see org.apache.geode.cache.Declarable * @link http://gemfire.docs.pivotal.io/latest/userguide/index.html#basic_config/the_cache/setting_cache_initializer.html * @link https://jira.springsource.org/browse/SGF-248 @@ -74,13 +77,13 @@ public class SpringContextBootstrappingInitializer implements Declarable, Applic private static final ApplicationEventMulticaster applicationEventNotifier = new SimpleApplicationEventMulticaster(); - private static final AtomicReference beanClassLoaderReference = new AtomicReference(null); + private static final AtomicReference beanClassLoaderReference = new AtomicReference<>(null); static volatile ConfigurableApplicationContext applicationContext; static volatile ContextRefreshedEvent contextRefreshedEvent; - private static final List> registeredAnnotatedClasses = new CopyOnWriteArrayList>(); + private static final List> registeredAnnotatedClasses = new CopyOnWriteArrayList<>(); protected final Log logger = initLogger(); @@ -92,7 +95,9 @@ public class SpringContextBootstrappingInitializer implements Declarable, Applic * @see org.springframework.context.ConfigurableApplicationContext */ public static synchronized ConfigurableApplicationContext getApplicationContext() { - Assert.state(applicationContext != null, "The Spring ApplicationContext was not configured and initialized properly!"); + Assert.state(applicationContext != null, + "A Spring ApplicationContext was not configured and initialized properly"); + return applicationContext; } @@ -110,7 +115,7 @@ public class SpringContextBootstrappingInitializer implements Declarable, Applic beanClassLoaderReference.set(beanClassLoader); } else { - throw new IllegalStateException("The Spring ApplicationContext has already been initialized!"); + throw new IllegalStateException("A Spring ApplicationContext has already been initialized"); } } @@ -254,8 +259,11 @@ public class SpringContextBootstrappingInitializer implements Declarable, Applic "'AnnotatedClasses', 'basePackages' or 'configLocations' must be specified in order to" + " construct and configure an instance of the ConfigurableApplicationContext"); + Class[] annotatedClasses = registeredAnnotatedClasses.toArray( + new Class[registeredAnnotatedClasses.size()]); + return scanBasePackages(registerAnnotatedClasses(createApplicationContext(configLocations), - registeredAnnotatedClasses.toArray(new Class[registeredAnnotatedClasses.size()])), basePackages); + annotatedClasses), basePackages); } /* (non-Javadoc) - used for testing purposes only */ @@ -276,9 +284,11 @@ public class SpringContextBootstrappingInitializer implements Declarable, Applic * @throws java.lang.IllegalArgumentException if the ApplicationContext reference is null! */ protected ConfigurableApplicationContext initApplicationContext(ConfigurableApplicationContext applicationContext) { - Assert.notNull(applicationContext, "The ConfigurableApplicationContext reference must not be null"); + Assert.notNull(applicationContext, "ConfigurableApplicationContext must not be null"); + applicationContext.addApplicationListener(this); applicationContext.registerShutdownHook(); + return setClassLoader(applicationContext); } @@ -292,8 +302,10 @@ public class SpringContextBootstrappingInitializer implements Declarable, Applic * @throws java.lang.IllegalArgumentException if the ApplicationContext reference is null! */ protected ConfigurableApplicationContext refreshApplicationContext(ConfigurableApplicationContext applicationContext) { - Assert.notNull(applicationContext, "The ConfigurableApplicationContext reference must not be null"); + Assert.notNull(applicationContext, "ConfigurableApplicationContext must not be null"); + applicationContext.refresh(); + return applicationContext; } @@ -310,7 +322,10 @@ public class SpringContextBootstrappingInitializer implements Declarable, Applic */ ConfigurableApplicationContext registerAnnotatedClasses(ConfigurableApplicationContext applicationContext, Class[] annotatedClasses) { - if (applicationContext instanceof AnnotationConfigApplicationContext && !ObjectUtils.isEmpty(annotatedClasses)) { + + if (applicationContext instanceof AnnotationConfigApplicationContext + && !ObjectUtils.isEmpty(annotatedClasses)) { + ((AnnotationConfigApplicationContext) applicationContext).register(annotatedClasses); } @@ -329,7 +344,10 @@ public class SpringContextBootstrappingInitializer implements Declarable, Applic */ ConfigurableApplicationContext scanBasePackages(ConfigurableApplicationContext applicationContext, String[] basePackages) { - if (applicationContext instanceof AnnotationConfigApplicationContext && !ObjectUtils.isEmpty(basePackages)) { + + if (applicationContext instanceof AnnotationConfigApplicationContext + && !ObjectUtils.isEmpty(basePackages)) { + ((AnnotationConfigApplicationContext) applicationContext).scan(basePackages); } @@ -354,17 +372,6 @@ public class SpringContextBootstrappingInitializer implements Declarable, Applic return applicationContext; } - /** - * Null-safe operation used to get the ID of the Spring ApplicationContext. - * - * @param applicationContext the Spring ApplicationContext from which to get the ID. - * @return the ID of the given Spring ApplicationContext or null if the ApplicationContext reference is null. - * @see org.springframework.context.ApplicationContext#getId() - */ - String nullSafeGetApplicationContextId(ApplicationContext applicationContext) { - return (applicationContext != null ? applicationContext.getId() : null); - } - /** * Initializes a Spring ApplicationContext with the given parameters specified with a GemFire <initializer> * block in cache.xml. @@ -380,7 +387,7 @@ public class SpringContextBootstrappingInitializer implements Declarable, Applic * @see java.util.Properties */ @Override - public void init(final Properties parameters) { + public void init(Properties parameters) { try { synchronized (SpringContextBootstrappingInitializer.class) { if (applicationContext == null || !applicationContext.isActive()) { @@ -412,6 +419,17 @@ public class SpringContextBootstrappingInitializer implements Declarable, Applic } } + /** + * Null-safe operation used to get the ID of the Spring ApplicationContext. + * + * @param applicationContext the Spring ApplicationContext from which to get the ID. + * @return the ID of the given Spring ApplicationContext or null if the ApplicationContext reference is null. + * @see org.springframework.context.ApplicationContext#getId() + */ + String nullSafeGetApplicationContextId(ApplicationContext applicationContext) { + return (applicationContext != null ? applicationContext.getId() : null); + } + /** * Gets notified when the Spring ApplicationContext gets created and refreshed by GemFire, once the * <initializer> block is processed and the SpringContextBootstrappingInitializer Declarable component @@ -429,7 +447,7 @@ public class SpringContextBootstrappingInitializer implements Declarable, Applic * #multicastEvent(org.springframework.context.ApplicationEvent) */ @Override - public void onApplicationEvent(final ApplicationContextEvent event) { + public void onApplicationEvent(ApplicationContextEvent event) { if (event instanceof ContextRefreshedEvent) { synchronized (applicationEventNotifier) { contextRefreshedEvent = (ContextRefreshedEvent) event; @@ -442,5 +460,4 @@ public class SpringContextBootstrappingInitializer implements Declarable, Applic } } } - } diff --git a/src/main/java/org/springframework/data/gemfire/support/WiringDeclarableSupport.java b/src/main/java/org/springframework/data/gemfire/support/WiringDeclarableSupport.java new file mode 100644 index 00000000..831d21d2 --- /dev/null +++ b/src/main/java/org/springframework/data/gemfire/support/WiringDeclarableSupport.java @@ -0,0 +1,140 @@ +/* + * Copyright 2016 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.support; + +import java.util.Properties; + +import org.apache.geode.cache.Declarable; +import org.apache.shiro.util.Assert; +import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.wiring.BeanConfigurerSupport; +import org.springframework.beans.factory.wiring.BeanWiringInfo; +import org.springframework.util.StringUtils; + +/** + * {@link Declarable} support class used to wire declaring, implementing instances through the Spring container. + * + * This implementation first looks for a {@literal 'bean-name'} property, which will be used to locate + * a Spring bean definition used as the 'template' for auto-wiring purposes. Auto-wiring will be performed + * based on the settings defined in the Spring container. + * + * @author Costin Leau + * @author John Blum + * @see org.springframework.beans.factory.BeanFactory + * @see org.springframework.beans.factory.wiring.BeanConfigurerSupport + * @see org.springframework.beans.factory.wiring.BeanWiringInfo + * @see DeclarableSupport + * @see LazyWiringDeclarableSupport + * @see org.apache.geode.cache.Declarable + */ +@SuppressWarnings("unused") +public abstract class WiringDeclarableSupport extends DeclarableSupport { + + protected static final String TEMPLATE_BEAN_NAME_PROPERTY = "bean-name"; + + /** + * @inheritDoc + */ + @Override + public void init(Properties parameters) { + configureThis(parameters.getProperty(TEMPLATE_BEAN_NAME_PROPERTY)); + } + + /** + * Configures this {@link Declarable} object using the bean defined and identified in the Spring {@link BeanFactory} + * with the given {@code name} used as a template for auto-wiring purposes. + * + * @param templateBeanName {@link String} containing the name of the Spring bean used as a template + * for auto-wiring purposes. + * @return a boolean value indicating whether this {@link Declarable} object was successfully configured + * and initialized by the Spring container. + * @see org.springframework.beans.factory.wiring.BeanConfigurerSupport + * @see #configureThis(BeanFactory, String) + * @see #locateBeanFactory() + */ + protected boolean configureThis(String templateBeanName) { + return configureThis(locateBeanFactory(), templateBeanName); + } + + /** + * Configures this {@link Declarable} object using the bean defined and identified in the given + * Spring {@link BeanFactory} with the given {@code name} used as a template for auto-wiring purposes. + * + * @param beanFactory Spring {@link BeanFactory} used to configure, auto-wire + * and initialize this {@link Declarable} object. + * @param templateBeanName {@link String} containing the name of the Spring bean used as a template + * for auto-wiring purposes. + * @return a boolean value indicating whether this {@link Declarable} object was successfully configured + * and initialized by the Spring container. + * @see org.springframework.beans.factory.wiring.BeanConfigurerSupport + * @see #newBeanConfigurer(BeanFactory, String) + */ + protected boolean configureThis(BeanFactory beanFactory, String templateBeanName) { + BeanConfigurerSupport beanConfigurer = newBeanConfigurer(beanFactory, templateBeanName); + + beanConfigurer.configureBean(this); + beanConfigurer.destroy(); + + return true; + } + + /** + * Constructs a new, initialized instance of {@link BeanConfigurerSupport} configured with + * the given Spring {@link BeanFactory}. + * + * @param beanFactory reference to the Spring {@link BeanFactory}. + * @return a new, initialized instance of {@link BeanConfigurerSupport} configured with + * the given Spring {@link BeanFactory}. + * @see org.springframework.beans.factory.wiring.BeanConfigurerSupport + * @see org.springframework.beans.factory.BeanFactory + * @see #newBeanConfigurer(BeanFactory, String) + */ + protected BeanConfigurerSupport newBeanConfigurer(BeanFactory beanFactory) { + return newBeanConfigurer(beanFactory, null); + } + + /** + * Constructs a new, initialized instance of {@link BeanConfigurerSupport} configured with + * the given Spring {@link BeanFactory} and name of a Spring bean defined in the Spring {@link BeanFactory} + * used as a template to wire this {@link Declarable} object. + * + * @param beanFactory reference to the Spring {@link BeanFactory}. + * @param templateBeanName {@link String} containing the name of a Spring bean in the Spring {@link BeanFactory} + * used as a template to wire this {@link Declarable} object. + * @return a new, initialized instance of {@link BeanConfigurerSupport} configured with + * the given Spring {@link BeanFactory}. + * @see org.springframework.beans.factory.wiring.BeanConfigurerSupport + * @see org.springframework.beans.factory.BeanFactory + */ + protected BeanConfigurerSupport newBeanConfigurer(BeanFactory beanFactory, String templateBeanName) { + BeanConfigurerSupport beanConfigurer = new BeanConfigurerSupport(); + + beanConfigurer.setBeanFactory(beanFactory); + + if (StringUtils.hasText(templateBeanName)) { + Assert.isTrue(beanFactory.containsBean(templateBeanName), + String.format("Cannot find bean with name [%s]", templateBeanName)); + + beanConfigurer.setBeanWiringInfoResolver(beanInstance -> new BeanWiringInfo(templateBeanName)); + } + + beanConfigurer.afterPropertiesSet(); + + return beanConfigurer; + } +} diff --git a/src/main/java/org/springframework/data/gemfire/util/SpringUtils.java b/src/main/java/org/springframework/data/gemfire/util/SpringUtils.java index 1de6f58d..429ac57a 100644 --- a/src/main/java/org/springframework/data/gemfire/util/SpringUtils.java +++ b/src/main/java/org/springframework/data/gemfire/util/SpringUtils.java @@ -63,6 +63,16 @@ public abstract class SpringUtils { return (obj1 == null ? obj2 == null : obj1.equals(obj2)); } + /* (non-Javadoc) */ + public static boolean nullOrEquals(Object obj1, Object obj2) { + return (obj1 == null || obj1.equals(obj2)); + } + + /* (non-Javadoc) */ + public static boolean nullSafeEquals(Object obj1, Object obj2) { + return (obj1 != null && obj1.equals(obj2)); + } + /* (non-Javadoc) */ public static String dereferenceBean(String beanName) { return String.format("%1$s%2$s", BeanFactory.FACTORY_BEAN_PREFIX, beanName); diff --git a/src/test/java/org/springframework/data/gemfire/CacheFactoryBeanTest.java b/src/test/java/org/springframework/data/gemfire/CacheFactoryBeanTest.java index 52f90e7b..20cc2340 100644 --- a/src/test/java/org/springframework/data/gemfire/CacheFactoryBeanTest.java +++ b/src/test/java/org/springframework/data/gemfire/CacheFactoryBeanTest.java @@ -32,6 +32,7 @@ import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import static org.junit.Assume.assumeTrue; import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.eq; import static org.mockito.Matchers.same; import static org.mockito.Mockito.mock; @@ -63,18 +64,16 @@ import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import org.springframework.beans.factory.BeanFactory; -import org.springframework.beans.factory.access.BeanFactoryReference; import org.springframework.core.io.Resource; +import org.springframework.data.gemfire.support.GemfireBeanFactoryLocator; import org.springframework.data.util.ReflectionUtils; /** - * The CacheFactoryBeanTest class is a test suite of test cases testing the contract and functionality - * of the CacheFactoryBean class. + * Unit tests for {@link CacheFactoryBean}. * * @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.CacheFactoryBean * @see org.apache.geode.cache.Cache @@ -219,6 +218,7 @@ public class CacheFactoryBeanTest { final CacheFactory mockCacheFactory = mock(CacheFactory.class); + when(mockBeanFactory.getAliases(anyString())).thenReturn(new String[0]); when(mockCacheFactory.create()).thenReturn(mockCache); when(mockCache.getCacheTransactionManager()).thenReturn(mockCacheTransactionManager); when(mockCache.getDistributedSystem()).thenReturn(mockDistributedSystem); @@ -269,6 +269,7 @@ public class CacheFactoryBeanTest { cacheFactoryBean.setTransactionWriter(mockTransactionWriter); cacheFactoryBean.setUseBeanFactoryLocator(true); + cacheFactoryBean.afterPropertiesSet(); cacheFactoryBean.init(); assertThat(Thread.currentThread().getContextClassLoader(), is(sameInstance(expectedThreadContextClassLoader))); @@ -277,11 +278,11 @@ public class CacheFactoryBeanTest { assertThat(beanFactoryLocator, is(notNullValue())); - BeanFactoryReference beanFactoryReference = beanFactoryLocator.useBeanFactory("TestGemFireCache"); + BeanFactory beanFactoryReference = beanFactoryLocator.useBeanFactory("TestGemFireCache"); - assertThat(beanFactoryReference, is(notNullValue())); - assertThat(beanFactoryReference.getFactory(), is(sameInstance(mockBeanFactory))); + assertThat(beanFactoryReference, is(sameInstance(mockBeanFactory))); + verify(mockBeanFactory, times(1)).getAliases(anyString()); verify(mockCacheFactory, times(1)).setPdxDiskStore(eq("TestPdxDiskStore")); verify(mockCacheFactory, times(1)).setPdxIgnoreUnreadFields(eq(false)); verify(mockCacheFactory, times(1)).setPdxPersistent(eq(true)); @@ -716,5 +717,4 @@ public class CacheFactoryBeanTest { assertSame(mockTransactionWriter, cacheFactoryBean.getTransactionWriter()); assertTrue(cacheFactoryBean.getUseClusterConfiguration()); } - } diff --git a/src/test/java/org/springframework/data/gemfire/DeclarableSupportTest.java b/src/test/java/org/springframework/data/gemfire/DeclarableSupportTest.java deleted file mode 100644 index f02fda8d..00000000 --- a/src/test/java/org/springframework/data/gemfire/DeclarableSupportTest.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * 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.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertSame; - -import org.apache.geode.cache.Cache; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.springframework.beans.factory.BeanFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; - - -/** - * Integration test for declarable support (and GEF bean factory locator). - * - * @author Costin Leau - */ -@RunWith(SpringJUnit4ClassRunner.class) -@ContextConfiguration(locations = { "cache-with-declarable-ctx.xml" }) -public class DeclarableSupportTest { - - @Autowired - private BeanFactory ctx; - - @Test - public void testUserObject() throws Exception { - ctx.getBean(Cache.class); - assertNotNull(UserObject.THIS); - UserObject obj = UserObject.THIS; - assertSame(ctx, obj.getBeanFactory()); - assertSame(ctx.getBean("bean"), obj.getProp2()); - assertEquals("Enescu", obj.getProp1()); - } -} diff --git a/src/test/java/org/springframework/data/gemfire/GemfireBeanFactoryLocatorTest.java b/src/test/java/org/springframework/data/gemfire/GemfireBeanFactoryLocatorTest.java deleted file mode 100644 index c1f198a5..00000000 --- a/src/test/java/org/springframework/data/gemfire/GemfireBeanFactoryLocatorTest.java +++ /dev/null @@ -1,149 +0,0 @@ -/* - * 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.hamcrest.CoreMatchers.is; -import static org.hamcrest.CoreMatchers.notNullValue; -import static org.hamcrest.CoreMatchers.nullValue; -import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.fail; - -import org.junit.After; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; -import org.junit.runner.RunWith; -import org.springframework.beans.factory.BeanFactory; -import org.springframework.beans.factory.access.BeanFactoryReference; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.ApplicationContext; -import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; - -/** - * @author Costin Leau - * @author John Blum - */ -@RunWith(SpringJUnit4ClassRunner.class) -@ContextConfiguration(locations = { "locatorContext.xml" }) -@SuppressWarnings("unused") -public class GemfireBeanFactoryLocatorTest { - - @Rule - public ExpectedException expectedException = ExpectedException.none(); - - @Autowired - private ApplicationContext applicationContext; - - private GemfireBeanFactoryLocator locator1, locator2; - - private String INSTANCE_1 = "instance1"; - private String INSTANCE_2 = "instance2"; - - @Before - public void init() { - locator1 = new GemfireBeanFactoryLocator(); - locator1.setBeanName(INSTANCE_1); - locator1.setBeanFactory(applicationContext); - locator1.afterPropertiesSet(); - - locator2 = new GemfireBeanFactoryLocator(); - locator2.setBeanName(INSTANCE_2); - locator2.setBeanFactory(applicationContext); - locator2.afterPropertiesSet(); - } - - @After - public void destroy() { - BeanFactoryReference ref1; - try { - ref1 = locator1.useBeanFactory(INSTANCE_1); - ref1.release(); - BeanFactoryReference ref2 = locator2.useBeanFactory(INSTANCE_2); - ref2.release(); - - } catch (IllegalArgumentException e) { - // it's okay - } - locator1.destroy(); - locator2.destroy(); - locator1 = null; - locator2 = null; - } - - @Test - public void testBeanFactoryRelease() throws Exception { - } - - @Test - public void testFactoryLocator() throws Exception { - BeanFactoryReference reference1 = locator1.useBeanFactory(INSTANCE_1); - BeanFactoryReference reference2 = locator2.useBeanFactory(INSTANCE_2); - BeanFactoryReference aliasRef1 = locator1.useBeanFactory("alias1"); - BeanFactoryReference aliasRef2 = locator1.useBeanFactory("alias2"); - - // verify the static map - BeanFactory factory1 = reference1.getFactory(); - BeanFactory factory2 = reference2.getFactory(); - BeanFactory factory3 = reference2.getFactory(); - // get the alias from different factories - BeanFactory alias1 = aliasRef1.getFactory(); - BeanFactory alias2 = aliasRef2.getFactory(); - - assertSame(factory1, factory2); - assertSame(factory1, factory3); - // verify it's the same bean factory as the application context - assertSame(factory1, applicationContext); - - // verify aliases - assertSame(alias1, alias2); - assertSame(factory1, alias1); - - aliasRef1.release(); - aliasRef2.release(); - reference1.release(); - reference2.release(); - } - - @Test - public void testDefaultFactoryLocator() throws Exception { - try { - locator1.useBeanFactory(null); - fail("there are more then one bean factories registered - should have thrown exception"); - } catch (IllegalArgumentException e) { - // it's okay - } - } - - @Test - public void factoryLocatorContract() throws Exception { - BeanFactoryReference factory1 = locator1.useBeanFactory(INSTANCE_1); - - assertThat(factory1.getFactory(), is(notNullValue())); - - factory1.release(); - - expectedException.expect(IllegalStateException.class); - expectedException.expectCause(is(nullValue(Throwable.class))); - expectedException.expectMessage("The BeanFactory has already been released or closed"); - - factory1.getFactory(); - } - -} diff --git a/src/test/java/org/springframework/data/gemfire/TestUtils.java b/src/test/java/org/springframework/data/gemfire/TestUtils.java index dddc5e14..83934446 100644 --- a/src/test/java/org/springframework/data/gemfire/TestUtils.java +++ b/src/test/java/org/springframework/data/gemfire/TestUtils.java @@ -19,41 +19,47 @@ package org.springframework.data.gemfire; import java.lang.reflect.Field; /** + * Utility class containing common functionality used when writing tests. + * * @author Costin Leau + * @author John Blum */ public abstract class TestUtils { @SuppressWarnings("unchecked") public static T readField(String name, Object target) throws Exception { - Field field = null; - Class clazz = target.getClass(); - do { - try { - field = clazz.getDeclaredField(name); - } catch (Exception ex) { - } + Field field = findField(name, target); - clazz = clazz.getSuperclass(); - } while (field == null && !clazz.equals(Object.class)); + if (field == null) { + throw new IllegalArgumentException(String.format("Cannot find field [%1$s] in class [%2$s]", + name, target.getClass().getName())); + } - if (field == null) - throw new IllegalArgumentException("Cannot find field '" + name + "' in the class hierarchy of " - + target.getClass()); field.setAccessible(true); + return (T) field.get(target); } - public static void cleanBeanFactoryStaticReference() { - try { - Field field = GemfireBeanFactoryLocator.class.getDeclaredField("canUseDefaultBeanFactory"); - field.setAccessible(true); - field.set(null, true); + /* (non-Javadoc) */ + private static Field findField(String fieldName, Object target) { + return findField(fieldName, target.getClass()); + } - field = GemfireBeanFactoryLocator.class.getDeclaredField("defaultFactory"); - field.setAccessible(true); - field.set(null, null); + /* (non-Javadoc) */ + private static Field findField(String fieldName, Class type) { + Field field = null; - } catch (Exception ex) { + while (field == null && !type.equals(Object.class)) { + try { + field = type.getDeclaredField(fieldName); + } + catch (Throwable ignore) { + } + finally { + type = type.getSuperclass(); + } } + + return field; } } diff --git a/src/test/java/org/springframework/data/gemfire/UserObject.java b/src/test/java/org/springframework/data/gemfire/UserObject.java deleted file mode 100644 index 9aea9a8f..00000000 --- a/src/test/java/org/springframework/data/gemfire/UserObject.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * 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 org.apache.geode.cache.CacheLoader; -import org.apache.geode.cache.CacheLoaderException; -import org.apache.geode.cache.LoaderHelper; - -/** - * User object used for testing Spring wiring. - * - * @author Costin Leau - */ -@SuppressWarnings("rawtypes") -public class UserObject extends WiringDeclarableSupport implements CacheLoader { - - public static UserObject THIS; - - private String prop1; - - private Object prop2; - - public UserObject() { - System.out.println("Initialized"); - THIS = this; - } - - @Override - public Object load(LoaderHelper helper) throws CacheLoaderException { - return new Object(); - } - - /** - * @return the prop1 - */ - public String getProp1() { - return prop1; - } - - /** - * @param prop1 the prop1 to set - */ - public void setProp1(String prop1) { - this.prop1 = prop1; - } - - /** - * @return the prop2 - */ - public Object getProp2() { - return prop2; - } - - /** - * @param prop2 the prop2 to set - */ - public void setProp2(Object prop2) { - this.prop2 = prop2; - } -} diff --git a/src/test/java/org/springframework/data/gemfire/config/xml/CacheNamespaceTest.java b/src/test/java/org/springframework/data/gemfire/config/xml/CacheNamespaceTest.java index b673739f..3fcf5ae1 100644 --- a/src/test/java/org/springframework/data/gemfire/config/xml/CacheNamespaceTest.java +++ b/src/test/java/org/springframework/data/gemfire/config/xml/CacheNamespaceTest.java @@ -24,6 +24,7 @@ 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 static org.springframework.data.gemfire.support.GemfireBeanFactoryLocator.newBeanFactoryLocator; import java.util.Properties; @@ -37,7 +38,6 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.core.io.Resource; import org.springframework.data.gemfire.CacheFactoryBean; -import org.springframework.data.gemfire.GemfireBeanFactoryLocator; import org.springframework.data.gemfire.TestUtils; import org.springframework.data.gemfire.client.ClientCacheFactoryBean; import org.springframework.test.context.ContextConfiguration; @@ -166,7 +166,7 @@ public class CacheNamespaceTest{ assertEquals(60.0f, evictionHeapPercentage, 0.0001); } - @Test(expected = IllegalArgumentException.class) + @Test(expected = IllegalStateException.class) public void testNoBeanFactoryLocator() throws Exception { assertTrue(context.containsBean("no-bean-factory-locator-cache")); @@ -174,15 +174,7 @@ public class CacheNamespaceTest{ assertThat(ReflectionTestUtils.getField(cacheFactoryBean, "beanFactoryLocator"), is(nullValue())); - GemfireBeanFactoryLocator beanFactoryLocator = new GemfireBeanFactoryLocator(); - - try { - assertNotNull(beanFactoryLocator.useBeanFactory("cache-with-name")); - beanFactoryLocator.useBeanFactory("no-bean-factory-locator-cache"); - } - finally { - beanFactoryLocator.destroy(); - } + newBeanFactoryLocator().useBeanFactory("no-bean-factory-locator-cache"); } @Test @@ -220,5 +212,4 @@ public class CacheNamespaceTest{ throw new UnsupportedOperationException("Not Implemented!"); } } - } diff --git a/src/test/java/org/springframework/data/gemfire/support/DeclarableSupportUnitTests.java b/src/test/java/org/springframework/data/gemfire/support/DeclarableSupportUnitTests.java new file mode 100644 index 00000000..7b3bf652 --- /dev/null +++ b/src/test/java/org/springframework/data/gemfire/support/DeclarableSupportUnitTests.java @@ -0,0 +1,182 @@ +/* + * Copyright 2016 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.support; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.nullValue; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import org.junit.After; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.Spy; +import org.mockito.runners.MockitoJUnitRunner; +import org.springframework.beans.factory.BeanFactory; + +/** + * Unit tests for {@link DeclarableSupport}. + * + * @author John Blum + * @see org.junit.Rule + * @see org.junit.Test + * @see org.mockito.Mock + * @see org.mockito.Mockito + * @see org.mockito.Spy + * @see org.mockito.runners.MockitoJUnitRunner + * @since 2.0.0 + */ +@RunWith(MockitoJUnitRunner.class) +public class DeclarableSupportUnitTests { + + @Rule + public ExpectedException exception = ExpectedException.none(); + + @Mock + private BeanFactory mockBeanFactoryOne; + + @Mock + private BeanFactory mockBeanFactoryTwo; + + @Spy + private DeclarableSupport testDeclarableSupport; + + @After + public void tearDown() { + testDeclarableSupport.setBeanFactoryKey(null); + GemfireBeanFactoryLocator.BEAN_FACTORIES.clear(); + } + + @Test + public void setAndGetBeanFactoryKey() { + assertThat(testDeclarableSupport.getBeanFactoryKey()).isNull(); + + testDeclarableSupport.setBeanFactoryKey("testKey"); + + assertThat(testDeclarableSupport.getBeanFactoryKey()).isEqualTo("testKey"); + + testDeclarableSupport.setBeanFactoryKey(null); + + assertThat(testDeclarableSupport.getBeanFactoryKey()).isNull(); + } + + @Test + public void locateBeanFactoryReturnsBeanFactory() { + GemfireBeanFactoryLocator.BEAN_FACTORIES.put("keyOne", mockBeanFactoryOne); + GemfireBeanFactoryLocator.BEAN_FACTORIES.put("keyTwo", mockBeanFactoryTwo); + + testDeclarableSupport.setBeanFactoryKey("keyOne"); + + assertThat(testDeclarableSupport.getBeanFactoryKey()).isEqualTo("keyOne"); + assertThat(testDeclarableSupport.locateBeanFactory()).isSameAs(mockBeanFactoryOne); + } + + @Test + public void locateBeanFactoryWithKeyReturnsBeanFactory() { + GemfireBeanFactoryLocator.BEAN_FACTORIES.put("keyOne", mockBeanFactoryOne); + GemfireBeanFactoryLocator.BEAN_FACTORIES.put("keyTwo", mockBeanFactoryTwo); + + assertThat(testDeclarableSupport.getBeanFactoryKey()).isNull(); + assertThat(testDeclarableSupport.locateBeanFactory("keyTwo")).isSameAs(mockBeanFactoryTwo); + } + + @Test + public void locateBeanFactoryWithoutKeyReturnsBeanFactory() { + GemfireBeanFactoryLocator.BEAN_FACTORIES.put("keyOne", mockBeanFactoryOne); + GemfireBeanFactoryLocator.BEAN_FACTORIES.put("refTwo", mockBeanFactoryOne); + + assertThat(testDeclarableSupport.getBeanFactoryKey()).isNull(); + assertThat(testDeclarableSupport.locateBeanFactory()).isSameAs(mockBeanFactoryOne); + } + + @Test + public void locateBeanFactoryWithUnknownKeyHavingMultipleBeanFactoriesRegisteredThrowsIllegalArgumentException() { + GemfireBeanFactoryLocator.BEAN_FACTORIES.put("keyOne", mockBeanFactoryOne); + GemfireBeanFactoryLocator.BEAN_FACTORIES.put("keyTwo", mockBeanFactoryTwo); + + testDeclarableSupport.setBeanFactoryKey("keyOne"); + + assertThat(testDeclarableSupport.getBeanFactoryKey()).isEqualTo("keyOne"); + + exception.expect(IllegalArgumentException.class); + exception.expectCause(is(nullValue(Throwable.class))); + exception.expectMessage("BeanFactory for key [UnknownKey] was not found"); + + testDeclarableSupport.locateBeanFactory("UnknownKey"); + } + + @Test + public void locateBeanFactoryWithoutKeyHavingMultipleBeanFactoriesRegisteredThrowsIllegalStateException() { + GemfireBeanFactoryLocator.BEAN_FACTORIES.put("keyOne", mockBeanFactoryOne); + GemfireBeanFactoryLocator.BEAN_FACTORIES.put("keyTwo", mockBeanFactoryTwo); + + assertThat(testDeclarableSupport.getBeanFactoryKey()).isNull(); + + exception.expect(IllegalStateException.class); + exception.expectCause(is(nullValue(Throwable.class))); + exception.expectMessage("BeanFactory key must be specified when more than one BeanFactory [keyOne, keyTwo]" + + " is registered"); + + testDeclarableSupport.locateBeanFactory(); + } + + @Test + public void locateBeanFactoryWithKeyWhenNoBeanFactoriesAreRegisteredThrowsIllegalStateException() { + assertThat(GemfireBeanFactoryLocator.BEAN_FACTORIES).isEmpty(); + + exception.expect(IllegalStateException.class); + exception.expectCause(is(nullValue(Throwable.class))); + exception.expectMessage("A BeanFactory was not initialized;" + + " Please verify the useBeanFactoryLocator property was properly set"); + + testDeclarableSupport.locateBeanFactory("testKey"); + } + + @Test + public void locateBeanFactoryWithoutKeyWhenNoBeanFactoriesAreRegisteredThrowsIllegalStateException() { + assertThat(GemfireBeanFactoryLocator.BEAN_FACTORIES).isEmpty(); + + exception.expect(IllegalStateException.class); + exception.expectCause(is(nullValue(Throwable.class))); + exception.expectMessage("A BeanFactory was not initialized;" + + " Please verify the useBeanFactoryLocator property was properly set"); + + testDeclarableSupport.locateBeanFactory(); + } + + @Test + public void getBeanFactoryReturnsBeanFactory() { + GemfireBeanFactoryLocator.BEAN_FACTORIES.put("keyOne", mockBeanFactoryOne); + GemfireBeanFactoryLocator.BEAN_FACTORIES.put("keyTwo", mockBeanFactoryTwo); + + testDeclarableSupport.setBeanFactoryKey("keyOne"); + + assertThat(testDeclarableSupport.getBeanFactoryKey()).isEqualTo("keyOne"); + assertThat(testDeclarableSupport.getBeanFactory()).isSameAs(mockBeanFactoryOne); + } + + @Test + public void closeIsSuccessful() { + testDeclarableSupport.close(); + verify(testDeclarableSupport, times(1)).close(); + } +} diff --git a/src/test/java/org/springframework/data/gemfire/support/GemfireBeanFactoryLocatorAnnotationConfigIntegrationTests.java b/src/test/java/org/springframework/data/gemfire/support/GemfireBeanFactoryLocatorAnnotationConfigIntegrationTests.java new file mode 100644 index 00000000..341a439f --- /dev/null +++ b/src/test/java/org/springframework/data/gemfire/support/GemfireBeanFactoryLocatorAnnotationConfigIntegrationTests.java @@ -0,0 +1,98 @@ +/* + * Copyright 2016 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.support; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.springframework.data.gemfire.util.CollectionUtils.asSet; + +import java.util.Set; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.data.gemfire.config.annotation.PeerCacheApplication; +import org.springframework.data.gemfire.test.GemfireTestBeanPostProcessor; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringRunner; + +/** + * Integration tests using Java-based configuration for {@link GemfireBeanFactoryLocator}. + * + * @author John Blum + * @see org.junit.Test + * @see org.springframework.beans.factory.BeanFactory + * @see org.springframework.data.gemfire.config.annotation.PeerCacheApplication + * @see org.springframework.data.gemfire.support.GemfireBeanFactoryLocator + * @see org.springframework.data.gemfire.test.GemfireTestBeanPostProcessor + * @see org.springframework.test.context.ContextConfiguration + * @see org.springframework.test.context.junit4.SpringRunner + * @since 2.0.0 + */ +@RunWith(SpringRunner.class) +@ContextConfiguration +public class GemfireBeanFactoryLocatorAnnotationConfigIntegrationTests { + + @Autowired + @SuppressWarnings("unused") + private BeanFactory beanFactory; + + @Test + public void beanFactoryContainsTestBeanFactoryLocatorBean() { + assertThat(beanFactory.containsBean("testBeanFactoryLocator")).isTrue(); + + GemfireBeanFactoryLocator testBeanFactoryLocator = beanFactory.getBean("testBeanFactoryLocator", + GemfireBeanFactoryLocator.class); + + assertThat(testBeanFactoryLocator).isNotNull(); + assertThat(testBeanFactoryLocator.getBeanFactory()).isSameAs(beanFactory); + assertThat(testBeanFactoryLocator.getAssociatedBeanName()).isEqualTo("testBeanFactoryLocator"); + assertThat(testBeanFactoryLocator.getAssociatedBeanNameWithAliases()).isNotNull(); + assertThat(testBeanFactoryLocator.getAssociatedBeanNameWithAliases()) + .containsAll(asSet("testBeanFactoryLocator", "aliasOne", "aliasTwo")); + assertThat(beanFactory.getAliases("testBeanFactoryLocator")).containsAll(asSet("aliasOne", "aliasTwo")); + } + + @Test + public void registeredBeanFactoriesIsCorrect() { + Set beanNames = asSet("gemfireCache", "testBeanFactoryLocator", "aliasOne", "aliasTwo"); + + assertThat(GemfireBeanFactoryLocator.BEAN_FACTORIES).hasSameSizeAs(beanNames); + assertThat(GemfireBeanFactoryLocator.BEAN_FACTORIES.keySet()).containsAll(beanNames); + + for (String beanName : beanNames) { + assertThat(GemfireBeanFactoryLocator.BEAN_FACTORIES.get(beanName)).isSameAs(beanFactory); + } + } + + @SuppressWarnings("unused") + @PeerCacheApplication(useBeanFactoryLocator = true) + static class TestConfiguration { + + @Bean + GemfireTestBeanPostProcessor gemfireTestBeanPostProcessor() { + return new GemfireTestBeanPostProcessor(); + } + + @Bean(name = { "testBeanFactoryLocator", "aliasOne", "aliasTwo" }) + GemfireBeanFactoryLocator testBeanFactoryLocator() { + return new GemfireBeanFactoryLocator(); + } + } +} diff --git a/src/test/java/org/springframework/data/gemfire/support/GemfireBeanFactoryLocatorIntegrationTests.java b/src/test/java/org/springframework/data/gemfire/support/GemfireBeanFactoryLocatorIntegrationTests.java new file mode 100644 index 00000000..dcd5c824 --- /dev/null +++ b/src/test/java/org/springframework/data/gemfire/support/GemfireBeanFactoryLocatorIntegrationTests.java @@ -0,0 +1,96 @@ +/* + * Copyright 2016 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.support; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.springframework.data.gemfire.util.CollectionUtils.asSet; + +import java.util.Set; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringRunner; + +/** + * Integration tests using XML for {@link GemfireBeanFactoryLocator}. + * + * @author John Blum + * @see org.junit.Test + * @see org.springframework.beans.factory.BeanFactory + * @see org.springframework.data.gemfire.support.GemfireBeanFactoryLocator + * @see org.springframework.test.context.ContextConfiguration + * @see org.springframework.test.context.junit4.SpringRunner + * @since 2.0.0 + */ +@RunWith(SpringRunner.class) +@ContextConfiguration +public class GemfireBeanFactoryLocatorIntegrationTests { + + @Autowired + @SuppressWarnings("unused") + private BeanFactory beanFactory; + + @Test + public void beanFactoryContainsGemfireBeanFactoryLocatorBean() { + assertThat(beanFactory.containsBean(GemfireBeanFactoryLocator.class.getName())).isTrue(); + + GemfireBeanFactoryLocator gemfireBeanFactoryLocator = + beanFactory.getBean(GemfireBeanFactoryLocator.class.getName(), GemfireBeanFactoryLocator.class); + + assertThat(gemfireBeanFactoryLocator).isNotNull(); + assertThat(gemfireBeanFactoryLocator.getBeanFactory()).isSameAs(beanFactory); + assertThat(gemfireBeanFactoryLocator.getAssociatedBeanName()) + .startsWith(GemfireBeanFactoryLocator.class.getName()); + assertThat(gemfireBeanFactoryLocator.getAssociatedBeanNameWithAliases()).isNotNull(); + assertThat(gemfireBeanFactoryLocator.getAssociatedBeanNameWithAliases()) + .containsAll(asSet(GemfireBeanFactoryLocator.class.getName())); + assertThat(beanFactory.getAliases(GemfireBeanFactoryLocator.class.getName())) + .containsAll(asSet(GemfireBeanFactoryLocator.class.getName().concat("#0"))); + } + + @Test + public void beanFactoryContainsTestBeanFactoryLocatorBean() { + assertThat(beanFactory.containsBean("testBeanFactoryLocator")).isTrue(); + + GemfireBeanFactoryLocator testBeanFactoryLocator = beanFactory.getBean("testBeanFactoryLocator", + GemfireBeanFactoryLocator.class); + + assertThat(testBeanFactoryLocator).isNotNull(); + assertThat(testBeanFactoryLocator.getBeanFactory()).isSameAs(beanFactory); + assertThat(testBeanFactoryLocator.getAssociatedBeanName()).isEqualTo("testBeanFactoryLocator"); + assertThat(testBeanFactoryLocator.getAssociatedBeanNameWithAliases()).isNotNull(); + assertThat(testBeanFactoryLocator.getAssociatedBeanNameWithAliases()) + .containsAll(asSet("testBeanFactoryLocator", "aliasOne", "aliasTwo")); + assertThat(beanFactory.getAliases("testBeanFactoryLocator")).containsAll(asSet("aliasOne", "aliasTwo")); + } + + @Test + public void registeredBeanFactoriesIsCorrect() { + Set beanNames = asSet("gemfire-cache", "gemfireCache", "testBeanFactoryLocator", "aliasOne", "aliasTwo", + GemfireBeanFactoryLocator.class.getName()); + + assertThat(GemfireBeanFactoryLocator.BEAN_FACTORIES.keySet()).containsAll(beanNames); + + for (String beanName : beanNames) { + assertThat(GemfireBeanFactoryLocator.BEAN_FACTORIES.get(beanName)).isSameAs(beanFactory); + } + } +} diff --git a/src/test/java/org/springframework/data/gemfire/support/GemfireBeanFactoryLocatorJavaConfigIntegrationTests.java b/src/test/java/org/springframework/data/gemfire/support/GemfireBeanFactoryLocatorJavaConfigIntegrationTests.java new file mode 100644 index 00000000..416d713c --- /dev/null +++ b/src/test/java/org/springframework/data/gemfire/support/GemfireBeanFactoryLocatorJavaConfigIntegrationTests.java @@ -0,0 +1,109 @@ +/* + * Copyright 2016 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.support; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.springframework.data.gemfire.util.CollectionUtils.asSet; + +import java.util.Set; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.gemfire.CacheFactoryBean; +import org.springframework.data.gemfire.test.GemfireTestBeanPostProcessor; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringRunner; + +/** + * Integration tests using Java-based configuration for {@link GemfireBeanFactoryLocator}. + * + * @author John Blum + * @see org.junit.Test + * @see org.springframework.beans.factory.BeanFactory + * @see org.springframework.data.gemfire.CacheFactoryBean + * @see org.springframework.data.gemfire.support.GemfireBeanFactoryLocator + * @see org.springframework.data.gemfire.test.GemfireTestBeanPostProcessor + * @see org.springframework.test.context.ContextConfiguration + * @see org.springframework.test.context.junit4.SpringRunner + * @since 2.0.0 + */ +@RunWith(SpringRunner.class) +@ContextConfiguration +public class GemfireBeanFactoryLocatorJavaConfigIntegrationTests { + + @Autowired + @SuppressWarnings("unused") + private BeanFactory beanFactory; + + @Test + public void beanFactoryContainsTestBeanFactoryLocatorBean() { + assertThat(beanFactory.containsBean("testBeanFactoryLocator")).isTrue(); + + GemfireBeanFactoryLocator testBeanFactoryLocator = beanFactory.getBean("testBeanFactoryLocator", + GemfireBeanFactoryLocator.class); + + assertThat(testBeanFactoryLocator).isNotNull(); + assertThat(testBeanFactoryLocator.getBeanFactory()).isSameAs(beanFactory); + assertThat(testBeanFactoryLocator.getAssociatedBeanName()).isEqualTo("testBeanFactoryLocator"); + assertThat(testBeanFactoryLocator.getAssociatedBeanNameWithAliases()).isNotNull(); + assertThat(testBeanFactoryLocator.getAssociatedBeanNameWithAliases()) + .containsAll(asSet("testBeanFactoryLocator", "aliasOne", "aliasTwo")); + assertThat(beanFactory.getAliases("testBeanFactoryLocator")).containsAll(asSet("aliasOne", "aliasTwo")); + } + + @Test + public void registeredBeanFactoriesIsCorrect() { + Set beanNames = asSet("gemfireCache", "testBeanFactoryLocator", "aliasOne", "aliasTwo"); + + assertThat(GemfireBeanFactoryLocator.BEAN_FACTORIES).hasSameSizeAs(beanNames); + assertThat(GemfireBeanFactoryLocator.BEAN_FACTORIES.keySet()).containsAll(beanNames); + + for (String beanName : beanNames) { + assertThat(GemfireBeanFactoryLocator.BEAN_FACTORIES.get(beanName)).isSameAs(beanFactory); + } + } + + @Configuration + @SuppressWarnings("unused") + static class TestConfiguration { + + @Bean + GemfireTestBeanPostProcessor gemfireTestBeanPostProcessor() { + return new GemfireTestBeanPostProcessor(); + } + + @Bean + CacheFactoryBean gemfireCache() { + CacheFactoryBean gemfireCache = new CacheFactoryBean(); + + gemfireCache.setClose(true); + gemfireCache.setUseBeanFactoryLocator(true); + + return gemfireCache; + } + + @Bean(name = { "testBeanFactoryLocator", "aliasOne", "aliasTwo" }) + GemfireBeanFactoryLocator testBeanFactoryLocator() { + return new GemfireBeanFactoryLocator(); + } + } +} diff --git a/src/test/java/org/springframework/data/gemfire/support/GemfireBeanFactoryLocatorUnitTests.java b/src/test/java/org/springframework/data/gemfire/support/GemfireBeanFactoryLocatorUnitTests.java new file mode 100644 index 00000000..f6204482 --- /dev/null +++ b/src/test/java/org/springframework/data/gemfire/support/GemfireBeanFactoryLocatorUnitTests.java @@ -0,0 +1,497 @@ +/* + * Copyright 2016 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.support; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.nullValue; +import static org.mockito.Matchers.anyString; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyZeroInteractions; +import static org.mockito.Mockito.when; +import static org.springframework.data.gemfire.support.GemfireBeanFactoryLocator.BeanFactoryReference.UNINITIALIZED_BEAN_FACTORY_REFERENCE_MESSAGE; +import static org.springframework.data.gemfire.support.GemfireBeanFactoryLocator.newBeanFactoryLocator; +import static org.springframework.data.gemfire.util.CollectionUtils.asSet; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; +import org.springframework.beans.factory.BeanFactory; + +/** + * Unit tests for {@link GemfireBeanFactoryLocator}. + * + * @author John Blum + * @see org.junit.Rule + * @see org.junit.Test + * @see org.mockito.Mock + * @see org.mockito.Mockito + * @see org.mockito.runners.MockitoJUnitRunner + * @see org.springframework.data.gemfire.support.GemfireBeanFactoryLocator + * @since 2.0.0 + */ +@RunWith(MockitoJUnitRunner.class) +public class GemfireBeanFactoryLocatorUnitTests { + + @Rule + public ExpectedException exception = ExpectedException.none(); + + @Mock + private BeanFactory mockBeanFactory; + + @Before + public void setup() { + assertThat(GemfireBeanFactoryLocator.BEAN_FACTORIES.isEmpty()).isTrue(); + } + + @After + public void tearDown() { + GemfireBeanFactoryLocator.BEAN_FACTORIES.clear(); + } + + @Test + public void newUninitializedBeanFactorLocator() { + GemfireBeanFactoryLocator beanFactoryLocator = newBeanFactoryLocator(); + + assertThat(beanFactoryLocator).isNotNull(); + assertThat(beanFactoryLocator.getBeanFactory()).isNull(); + assertThat(beanFactoryLocator.getAssociatedBeanName()).isNull(); + assertThat(beanFactoryLocator.getAssociatedBeanNameWithAliases()).isNotNull(); + assertThat(beanFactoryLocator.getAssociatedBeanNameWithAliases()).isEmpty(); + } + + @Test + public void newInitializedBeanFactoryLocator() { + when(mockBeanFactory.getAliases(anyString())).thenReturn(new String[0]); + + GemfireBeanFactoryLocator beanFactoryLocator = newBeanFactoryLocator(mockBeanFactory, "AssociatedBeanName"); + + assertThat(beanFactoryLocator).isNotNull(); + assertThat(beanFactoryLocator.getBeanFactory()).isSameAs(mockBeanFactory); + assertThat(beanFactoryLocator.getAssociatedBeanName()).isEqualTo("AssociatedBeanName"); + assertThat(beanFactoryLocator.getAssociatedBeanNameWithAliases()).isNotNull(); + assertThat(beanFactoryLocator.getAssociatedBeanNameWithAliases()).hasSize(1); + assertThat(beanFactoryLocator.getAssociatedBeanNameWithAliases()).containsAll(asSet("AssociatedBeanName")); + + verify(mockBeanFactory, times(1)).getAliases(eq("AssociatedBeanName")); + } + + @Test + public void newInitializedBeanFactoryLocatorWithNullBeanFactoryAndSpecifiedBeanName() { + GemfireBeanFactoryLocator beanFactoryLocator = newBeanFactoryLocator(null, "MyBeanName"); + + assertThat(beanFactoryLocator).isNotNull(); + assertThat(beanFactoryLocator.getBeanFactory()).isNull(); + assertThat(beanFactoryLocator.getAssociatedBeanName()).isEqualTo("MyBeanName"); + assertThat(beanFactoryLocator.getAssociatedBeanNameWithAliases()).isNotNull(); + assertThat(beanFactoryLocator.getAssociatedBeanNameWithAliases()).isEmpty(); + } + + @Test + public void newInitializedBeanFactoryLocatorWithNonNullBeanFactoryAndUnspecifiedBeanNameThrowsIllegalArgumentException() { + exception.expect(IllegalArgumentException.class); + exception.expectCause(is(nullValue(Throwable.class))); + exception.expectMessage("associatedBeanName must be specified when BeanFactory is not null"); + + newBeanFactoryLocator(mockBeanFactory, " "); + } + + @Test + public void resolveBeanFactoryReturnsResolvedBeanFactory() { + GemfireBeanFactoryLocator.BEAN_FACTORIES.put("MyBeanKey", mockBeanFactory); + + assertThat(GemfireBeanFactoryLocator.BEAN_FACTORIES).hasSize(1); + assertThat(GemfireBeanFactoryLocator.resolveBeanFactory("MyBeanKey")).isSameAs(mockBeanFactory); + } + + @Test + public void resolveBeanFactoryWithNoRegisteredBeanFactoriesAndAnyKeyReturnsNull() { + assertThat(GemfireBeanFactoryLocator.BEAN_FACTORIES).isEmpty(); + assertThat(GemfireBeanFactoryLocator.resolveBeanFactory("MyBeanKey")).isNull(); + assertThat(GemfireBeanFactoryLocator.resolveBeanFactory("AnotherBeanKey")).isNull(); + assertThat(GemfireBeanFactoryLocator.resolveBeanFactory("YetAnotherBeanKey")).isNull(); + } + + @Test + public void resolveBeanFactoryWithRegisteredBeanFactoriesAndUnknownKeyThrowsIllegalArgumentException() { + GemfireBeanFactoryLocator.BEAN_FACTORIES.put("MyBeanKey", mockBeanFactory); + + assertThat(GemfireBeanFactoryLocator.BEAN_FACTORIES).hasSize(1); + + exception.expect(IllegalArgumentException.class); + exception.expectCause(is(nullValue(Throwable.class))); + exception.expectMessage("BeanFactory for key [UnknownKey] was not found"); + + GemfireBeanFactoryLocator.resolveBeanFactory("UnknownKey"); + } + + @Test + public void resolveSingleBeanFactoryWithNoRegisteredBeanFactoriesReturnsNull() { + assertThat(GemfireBeanFactoryLocator.BEAN_FACTORIES.isEmpty()).isTrue(); + assertThat(GemfireBeanFactoryLocator.resolveSingleBeanFactory()).isNull(); + } + + @Test + public void resolveSingleBeanFactoryWhenSingleBeanFactoryIsRegisteredReturnsSingleBeanFactory() { + GemfireBeanFactoryLocator.BEAN_FACTORIES.put("MyBeanKey", mockBeanFactory); + + assertThat(GemfireBeanFactoryLocator.BEAN_FACTORIES.size()).isEqualTo(1); + assertThat(GemfireBeanFactoryLocator.resolveSingleBeanFactory()).isSameAs(mockBeanFactory); + } + + @Test + public void resolveSingleBeanFactoryWhenMultipleIdenticalBeanFactoriesAreRegisteredReturnsSingleBeanFactory() { + GemfireBeanFactoryLocator.BEAN_FACTORIES.put("refOne", mockBeanFactory); + GemfireBeanFactoryLocator.BEAN_FACTORIES.put("refTwo", mockBeanFactory); + + assertThat(GemfireBeanFactoryLocator.BEAN_FACTORIES.size()).isEqualTo(2); + assertThat(GemfireBeanFactoryLocator.resolveSingleBeanFactory()).isSameAs(mockBeanFactory); + } + + @Test + public void resolveSingeBeanFactoryWhenMultipleDifferentBeanFactoriesAreRegisteredThrowsIllegalStateException() { + GemfireBeanFactoryLocator.BEAN_FACTORIES.put("refOne", mockBeanFactory); + GemfireBeanFactoryLocator.BEAN_FACTORIES.put("refTwo", mock(BeanFactory.class)); + + assertThat(GemfireBeanFactoryLocator.BEAN_FACTORIES.size()).isEqualTo(2); + + exception.expect(IllegalStateException.class); + exception.expectCause(is(nullValue(Throwable.class))); + exception.expectMessage("BeanFactory key must be specified when more than one BeanFactory [refOne, refTwo]" + + " is registered"); + + GemfireBeanFactoryLocator.resolveSingleBeanFactory(); + } + + @Test + public void registerAliasesIsSuccessful() { + Set aliases = asSet("aliasOne", "aliasTwo", "aliasThree"); + + GemfireBeanFactoryLocator.registerAliases(aliases, mockBeanFactory); + + assertThat(GemfireBeanFactoryLocator.BEAN_FACTORIES.size()).isEqualTo(3); + assertThat(GemfireBeanFactoryLocator.BEAN_FACTORIES.keySet()).containsAll(aliases); + + Set beanFactories = new HashSet<>(GemfireBeanFactoryLocator.BEAN_FACTORIES.values()); + + assertThat(beanFactories).hasSize(1); + assertThat(beanFactories).containsAll(asSet(mockBeanFactory)); + } + + @Test + public void registerAliasesWithEmptyAliasesAndNonNullBeanFactoryDoesNothing() { + GemfireBeanFactoryLocator.registerAliases(Collections.emptySet(), mockBeanFactory); + + assertThat(GemfireBeanFactoryLocator.BEAN_FACTORIES.isEmpty()).isTrue(); + } + + @Test + public void registerAliasesWithEmptyAliasesAndNullBeanFactoryDoesNothing() { + GemfireBeanFactoryLocator.registerAliases(Collections.emptySet(), null); + + assertThat(GemfireBeanFactoryLocator.BEAN_FACTORIES.isEmpty()).isTrue(); + } + + @Test + public void registerAliasesWithNonEmptyAliasesAndNullBeanFactoryThrowsIllegalArgumentException() { + exception.expect(IllegalArgumentException.class); + exception.expectCause(is(nullValue(Throwable.class))); + exception.expectMessage("BeanFactory must not be null when aliases are specified"); + + GemfireBeanFactoryLocator.registerAliases(asSet("aliasOne", "aliasTwo"), null); + } + + @Test + public void registerAliasesWithNullAliasesHandlesNullAndDoesNothing() { + GemfireBeanFactoryLocator.registerAliases(null, null); + + assertThat(GemfireBeanFactoryLocator.BEAN_FACTORIES.isEmpty()).isTrue(); + } + + @Test + public void registerAliasesWhenIdenticalBeanFactoryReferencesAlreadyExistIsSuccessful() { + GemfireBeanFactoryLocator.BEAN_FACTORIES.put("aliasTwo", mockBeanFactory); + + assertThat(GemfireBeanFactoryLocator.BEAN_FACTORIES.size()).isEqualTo(1); + assertThat(GemfireBeanFactoryLocator.BEAN_FACTORIES.get("aliasTwo")).isSameAs(mockBeanFactory); + + GemfireBeanFactoryLocator.registerAliases(asSet("aliasOne", "aliasTwo"), mockBeanFactory); + + assertThat(GemfireBeanFactoryLocator.BEAN_FACTORIES.size()).isEqualTo(2); + assertThat(GemfireBeanFactoryLocator.BEAN_FACTORIES.get("aliasOne")).isSameAs(mockBeanFactory); + assertThat(GemfireBeanFactoryLocator.BEAN_FACTORIES.get("aliasTwo")).isSameAs(mockBeanFactory); + } + + @Test + public void registerAliasesWhenNonIdenticalBeanFactoryReferencesAlreadyExistThrowsIllegalArgumentException() { + GemfireBeanFactoryLocator.BEAN_FACTORIES.put("aliasTwo", mockBeanFactory); + + assertThat(GemfireBeanFactoryLocator.BEAN_FACTORIES.size()).isEqualTo(1); + assertThat(GemfireBeanFactoryLocator.BEAN_FACTORIES.get("aliasTwo")).isSameAs(mockBeanFactory); + + exception.expect(IllegalArgumentException.class); + exception.expectCause(is(nullValue(Throwable.class))); + exception.expectMessage("BeanFactory reference already exists for key [aliasTwo]"); + + GemfireBeanFactoryLocator.registerAliases(asSet("aliasOne", "aliasTwo"), mock(BeanFactory.class)); + } + + @Test + public void unregisterAliasesRemovesAll() { + GemfireBeanFactoryLocator.BEAN_FACTORIES.put("aliasOne", mockBeanFactory); + GemfireBeanFactoryLocator.BEAN_FACTORIES.put("aliasTwo", mockBeanFactory); + + assertThat(GemfireBeanFactoryLocator.BEAN_FACTORIES.size()).isEqualTo(2); + + GemfireBeanFactoryLocator.unregisterAliases(asSet("aliasOne", "aliasTwo")); + + assertThat(GemfireBeanFactoryLocator.BEAN_FACTORIES.isEmpty()).isTrue(); + } + + @Test + public void unregisterAliasesRemovesPartial() { + GemfireBeanFactoryLocator.BEAN_FACTORIES.put("aliasOne", mockBeanFactory); + GemfireBeanFactoryLocator.BEAN_FACTORIES.put("aliasTwo", mockBeanFactory); + + assertThat(GemfireBeanFactoryLocator.BEAN_FACTORIES.size()).isEqualTo(2); + + GemfireBeanFactoryLocator.unregisterAliases(asSet("aliasTwo")); + + assertThat(GemfireBeanFactoryLocator.BEAN_FACTORIES.size()).isEqualTo(1); + assertThat(GemfireBeanFactoryLocator.BEAN_FACTORIES.containsKey("aliasOne")).isTrue(); + assertThat(GemfireBeanFactoryLocator.BEAN_FACTORIES.containsKey("aliasTwo")).isFalse(); + } + + @Test + public void unregisterAliasesRemovesNone() { + GemfireBeanFactoryLocator.BEAN_FACTORIES.put("aliasOne", mockBeanFactory); + GemfireBeanFactoryLocator.BEAN_FACTORIES.put("aliasTwo", mockBeanFactory); + + assertThat(GemfireBeanFactoryLocator.BEAN_FACTORIES.size()).isEqualTo(2); + + GemfireBeanFactoryLocator.unregisterAliases(asSet("refOne", "refTwo")); + + assertThat(GemfireBeanFactoryLocator.BEAN_FACTORIES.size()).isEqualTo(2); + assertThat(GemfireBeanFactoryLocator.BEAN_FACTORIES.containsKey("aliasOne")).isTrue(); + assertThat(GemfireBeanFactoryLocator.BEAN_FACTORIES.containsKey("aliasTwo")).isTrue(); + } + + @Test + public void afterPropertiesSetResolvesAndInitializesBeanNamesWithAliasesThenRegisterAliases() { + when(mockBeanFactory.getAliases(eq("AssociatedBeanName"))).thenReturn(new String[] { "aliasOne", "aliasTwo" }); + + GemfireBeanFactoryLocator beanFactoryLocator = newBeanFactoryLocator(mockBeanFactory, "AssociatedBeanName"); + + assertThat(beanFactoryLocator).isNotNull(); + assertThat(beanFactoryLocator.getBeanFactory()).isSameAs(mockBeanFactory); + assertThat(beanFactoryLocator.getAssociatedBeanName()).isEqualTo("AssociatedBeanName"); + assertThat(beanFactoryLocator.getAssociatedBeanNameWithAliases()).isNotNull(); + assertThat(beanFactoryLocator.getAssociatedBeanNameWithAliases()).hasSize(3); + assertThat(beanFactoryLocator.getAssociatedBeanNameWithAliases()) + .containsAll(asSet("AssociatedBeanName", "aliasOne", "aliasTwo")); + + assertThat(GemfireBeanFactoryLocator.BEAN_FACTORIES).hasSize(3); + assertThat(GemfireBeanFactoryLocator.BEAN_FACTORIES.keySet()) + .containsAll(asSet("AssociatedBeanName", "aliasOne", "aliasTwo")); + assertThat(GemfireBeanFactoryLocator.BEAN_FACTORIES.get("AssociatedBeanName")).isSameAs(mockBeanFactory); + assertThat(GemfireBeanFactoryLocator.BEAN_FACTORIES.get("aliasOne")).isSameAs(mockBeanFactory); + assertThat(GemfireBeanFactoryLocator.BEAN_FACTORIES.get("aliasTwo")).isSameAs(mockBeanFactory); + + verify(mockBeanFactory, times(1)).getAliases(eq("AssociatedBeanName")); + } + + @Test + public void afterPropertiesSetUnableToResolveInitializeAndRegisterAliasesWithNullBeanFactory() { + GemfireBeanFactoryLocator beanFactoryLocator = newBeanFactoryLocator(null, "AssociatedBeanName"); + + assertThat(beanFactoryLocator).isNotNull(); + assertThat(beanFactoryLocator.getBeanFactory()).isNull(); + assertThat(beanFactoryLocator.getAssociatedBeanName()).isEqualTo("AssociatedBeanName"); + assertThat(beanFactoryLocator.getAssociatedBeanNameWithAliases()).isNotNull(); + assertThat(beanFactoryLocator.getAssociatedBeanNameWithAliases()).isEmpty(); + assertThat(GemfireBeanFactoryLocator.BEAN_FACTORIES).isEmpty(); + } + + @Test + public void destroyUnregistersOwningAliases() { + BeanFactory mockBeanFactoryTwo = mock(BeanFactory.class, "MockBeanFactoryTwo"); + + when(mockBeanFactory.getAliases(eq("AssociatedBeanName"))).thenReturn(new String[] { "aliasOne", "aliasTwo" }); + + GemfireBeanFactoryLocator.BEAN_FACTORIES.put("refOne", mockBeanFactoryTwo); + GemfireBeanFactoryLocator.BEAN_FACTORIES.put("refTwo", mockBeanFactoryTwo); + + assertThat(GemfireBeanFactoryLocator.BEAN_FACTORIES).hasSize(2); + assertThat(GemfireBeanFactoryLocator.BEAN_FACTORIES.keySet()).containsAll(asSet("refOne", "refTwo")); + + GemfireBeanFactoryLocator beanFactoryLocator = newBeanFactoryLocator(mockBeanFactory, "AssociatedBeanName"); + + assertThat(beanFactoryLocator).isNotNull(); + assertThat(beanFactoryLocator.getBeanFactory()).isSameAs(mockBeanFactory); + assertThat(beanFactoryLocator.getAssociatedBeanName()).isEqualTo("AssociatedBeanName"); + assertThat(beanFactoryLocator.getAssociatedBeanNameWithAliases()).isNotNull(); + assertThat(beanFactoryLocator.getAssociatedBeanNameWithAliases()).hasSize(3); + assertThat(beanFactoryLocator.getAssociatedBeanNameWithAliases()).containsAll( + asSet("AssociatedBeanName", "aliasOne", "aliasTwo")); + + assertThat(GemfireBeanFactoryLocator.BEAN_FACTORIES).hasSize(5); + assertThat(GemfireBeanFactoryLocator.BEAN_FACTORIES.keySet()) + .containsAll(asSet("refOne", "refTwo", "AssociatedBeanName", "aliasOne", "aliasTwo")); + + beanFactoryLocator.destroy(); + + assertThat(GemfireBeanFactoryLocator.BEAN_FACTORIES).hasSize(2); + assertThat(GemfireBeanFactoryLocator.BEAN_FACTORIES.keySet()).containsAll(asSet("refOne", "refTwo")); + + verify(mockBeanFactory, times(1)).getAliases(eq("AssociatedBeanName")); + verifyZeroInteractions(mockBeanFactoryTwo); + } + + @Test + public void useBeanFactoryWhenNoBeanFactoriesAreRegisteredThrowsIllegalStateException() { + exception.expect(IllegalStateException.class); + exception.expectCause(is(nullValue(Throwable.class))); + exception.expectMessage(UNINITIALIZED_BEAN_FACTORY_REFERENCE_MESSAGE); + + newBeanFactoryLocator().useBeanFactory(); + } + + @Test + public void useBeanFactoryWhenSingleBeanFactoryIsRegisteredReturnsSingleBeanFactory() { + GemfireBeanFactoryLocator.BEAN_FACTORIES.put("refOne", mockBeanFactory); + GemfireBeanFactoryLocator.BEAN_FACTORIES.put("refTwo", mockBeanFactory); + + assertThat(GemfireBeanFactoryLocator.BEAN_FACTORIES.size()).isEqualTo(2); + + assertThat(newBeanFactoryLocator().useBeanFactory()).isSameAs(mockBeanFactory); + } + + @Test + public void useBeanFactoryWhenMultipleBeanFactoriesAreRegisteredThrowsIllegalStateException() { + GemfireBeanFactoryLocator.BEAN_FACTORIES.put("refOne", mockBeanFactory); + GemfireBeanFactoryLocator.BEAN_FACTORIES.put("refTwo", mock(BeanFactory.class, "MockBeanFactoryTwo")); + + assertThat(GemfireBeanFactoryLocator.BEAN_FACTORIES).hasSize(2); + + exception.expect(IllegalStateException.class); + exception.expectCause(is(nullValue(Throwable.class))); + exception.expectMessage("BeanFactory key must be specified when more than one BeanFactory [refOne, refTwo]" + + " is registered"); + + newBeanFactoryLocator().useBeanFactory(); + } + + @Test + public void useBeanFactoryWhenMultipleBeanFactoriesAreRegisteredWithConfiguredKeyReturnsBeanFactory() { + BeanFactory mockBeanFactoryTwo = mock(BeanFactory.class, "MockBeanFactoryTwo"); + + GemfireBeanFactoryLocator.BEAN_FACTORIES.put("refOne", mockBeanFactory); + GemfireBeanFactoryLocator.BEAN_FACTORIES.put("refTwo", mockBeanFactoryTwo); + + assertThat(GemfireBeanFactoryLocator.BEAN_FACTORIES).hasSize(2); + assertThat(newBeanFactoryLocator(null, "refOne").useBeanFactory()).isSameAs(mockBeanFactory); + assertThat(newBeanFactoryLocator().withBeanName("refTwo").useBeanFactory()).isSameAs(mockBeanFactoryTwo); + } + + @Test + public void useBeanFactoryWithKeyReturnsSpecificBeanFactory() { + GemfireBeanFactoryLocator.BEAN_FACTORIES.put("keyOne", mockBeanFactory); + GemfireBeanFactoryLocator.BEAN_FACTORIES.put("keyTwo", mock(BeanFactory.class, "MockBeanFactoryTwo")); + + assertThat(GemfireBeanFactoryLocator.BEAN_FACTORIES).hasSize(2); + assertThat(newBeanFactoryLocator().useBeanFactory("keyOne")).isSameAs(mockBeanFactory); + } + + @Test + public void useBeanFactoryWithUnknownKeyThrowsIllegalArgumentException() { + GemfireBeanFactoryLocator.BEAN_FACTORIES.put("keyOne", mockBeanFactory); + GemfireBeanFactoryLocator.BEAN_FACTORIES.put("keyTwo", mock(BeanFactory.class, "MockBeanFactoryTwo")); + + assertThat(GemfireBeanFactoryLocator.BEAN_FACTORIES.size()).isEqualTo(2); + + exception.expect(IllegalArgumentException.class); + exception.expectCause(is(nullValue(Throwable.class))); + exception.expectMessage("BeanFactory for key [UnknownKey] was not found"); + + newBeanFactoryLocator().useBeanFactory("UnknownKey"); + } + + @Test + public void setAndGetBeanFactory() { + GemfireBeanFactoryLocator beanFactoryLocator = newBeanFactoryLocator(); + + assertThat(beanFactoryLocator).isNotNull(); + assertThat(beanFactoryLocator.getBeanFactory()).isNull(); + + beanFactoryLocator.setBeanFactory(mockBeanFactory); + + assertThat(beanFactoryLocator.getBeanFactory()).isSameAs(mockBeanFactory); + + beanFactoryLocator.setBeanFactory(null); + + assertThat(beanFactoryLocator.getBeanFactory()).isNull(); + + verifyZeroInteractions(mockBeanFactory); + } + + @Test + public void setAndGetAssociatedBeanName() { + GemfireBeanFactoryLocator beanFactoryLocator = newBeanFactoryLocator(null, "AssociatedBeanName"); + + assertThat(beanFactoryLocator).isNotNull(); + assertThat(beanFactoryLocator.getAssociatedBeanName()).isEqualTo("AssociatedBeanName"); + assertThat(beanFactoryLocator.getAssociatedBeanNameWithAliases()).isNotNull(); + assertThat(beanFactoryLocator.getAssociatedBeanNameWithAliases()).isEmpty(); + + beanFactoryLocator.setBeanName("TestBeanName"); + + assertThat(beanFactoryLocator.getAssociatedBeanName()).isEqualTo("TestBeanName"); + assertThat(beanFactoryLocator.getAssociatedBeanNameWithAliases()).isNotNull(); + assertThat(beanFactoryLocator.getAssociatedBeanNameWithAliases()).isEmpty(); + + beanFactoryLocator.setBeanName(null); + + assertThat(beanFactoryLocator.getAssociatedBeanName()).isNull(); + assertThat(beanFactoryLocator.getAssociatedBeanNameWithAliases()).isNotNull(); + assertThat(beanFactoryLocator.getAssociatedBeanNameWithAliases()).isEmpty(); + } + + @Test + public void withBeanNameIsSuccessful() { + GemfireBeanFactoryLocator beanFactoryLocator = newBeanFactoryLocator(); + + assertThat(beanFactoryLocator).isNotNull(); + assertThat(beanFactoryLocator.getAssociatedBeanName()).isNull(); + assertThat(beanFactoryLocator.withBeanName("MyBeanName")).isSameAs(beanFactoryLocator); + assertThat(beanFactoryLocator.getAssociatedBeanName()).isEqualTo("MyBeanName"); + assertThat(beanFactoryLocator.withBeanName(null)).isSameAs(beanFactoryLocator); + assertThat(beanFactoryLocator.getAssociatedBeanName()).isNull(); + } +} diff --git a/src/test/java/org/springframework/data/gemfire/LazyWiringDeclarableSupportFunctionBasedIntegrationTest.java b/src/test/java/org/springframework/data/gemfire/support/LazyWiringDeclarableSupportFunctionBasedIntegrationTests.java similarity index 80% rename from src/test/java/org/springframework/data/gemfire/LazyWiringDeclarableSupportFunctionBasedIntegrationTest.java rename to src/test/java/org/springframework/data/gemfire/support/LazyWiringDeclarableSupportFunctionBasedIntegrationTests.java index ac1892ac..7f319b0a 100644 --- a/src/test/java/org/springframework/data/gemfire/LazyWiringDeclarableSupportFunctionBasedIntegrationTest.java +++ b/src/test/java/org/springframework/data/gemfire/support/LazyWiringDeclarableSupportFunctionBasedIntegrationTests.java @@ -1,24 +1,23 @@ /* - * Copyright 2010-2013 the original author or authors. + * Copyright 2016 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 + * 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; +package org.springframework.data.gemfire.support; -import static org.hamcrest.CoreMatchers.equalTo; -import static org.hamcrest.CoreMatchers.is; -import static org.junit.Assert.assertThat; +import static org.assertj.core.api.Assertions.assertThat; import java.util.Properties; @@ -31,26 +30,25 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.data.gemfire.function.sample.HelloFunctionExecution; import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.test.context.junit4.SpringRunner; import org.springframework.util.Assert; import org.springframework.util.StringUtils; /** - * The LazyWiringDeclarableSupportFunctionBasedIntegrationTest class is a test suite of test cases testing the contract - * and functionality of a GemFire Function implementing LazyWiringDeclarableSupport, defined using native GemFire - * configuration metadata (cache.xml). + * Integration test to test the functionality of a GemFire Function implementing the Spring Data GemFire + * {@link LazyWiringDeclarableSupport} class, defined using native GemFire configuration meta-data + * (i.e {@literal cache.xml}). * * @author John Blum * @see org.junit.Test - * @see org.junit.runner.RunWith * @see org.springframework.test.context.ContextConfiguration - * @see org.springframework.test.context.junit4.SpringJUnit4ClassRunner + * @see org.springframework.test.context.junit4.SpringRunner * @since 1.7.0 */ -@RunWith(SpringJUnit4ClassRunner.class) +@RunWith(SpringRunner.class) @ContextConfiguration @SuppressWarnings("unused") -public class LazyWiringDeclarableSupportFunctionBasedIntegrationTest { +public class LazyWiringDeclarableSupportFunctionBasedIntegrationTests { @Autowired private Cache gemfireCache; @@ -62,7 +60,7 @@ public class LazyWiringDeclarableSupportFunctionBasedIntegrationTest { @BeforeClass public static void setupBeforeClass() { Cache gemfireCache = new CacheFactory() - .set("name", LazyWiringDeclarableSupportFunctionBasedIntegrationTest.class.getSimpleName()) + .set("name", LazyWiringDeclarableSupportFunctionBasedIntegrationTests.class.getSimpleName()) .set("mcast-port", "0") .set("log-level", "config") .set("cache-xml-file", null) @@ -80,15 +78,15 @@ public class LazyWiringDeclarableSupportFunctionBasedIntegrationTest { @Test public void helloGreeting() { - assertThat(helloFunctionExecution.hello(null), is(equalTo("Hello Everyone!"))); + assertThat(helloFunctionExecution.hello(null)).isEqualTo("Hello Everyone!"); } protected static abstract class FunctionAdaptor extends LazyWiringDeclarableSupport implements Function { private final String id; - public FunctionAdaptor(final String id) { - Assert.hasText(id, "The Function ID must be specified!"); + FunctionAdaptor(String id) { + Assert.hasText(id, "Function ID must be specified"); this.id = id; } @@ -113,6 +111,7 @@ public class LazyWiringDeclarableSupportFunctionBasedIntegrationTest { } } + @SuppressWarnings("all") public static class HelloGemFireFunction extends FunctionAdaptor { protected static final String ADDRESS_TO_PARAMETER = "hello.address.to"; @@ -167,5 +166,4 @@ public class LazyWiringDeclarableSupportFunctionBasedIntegrationTest { return String.format(HELLO_GREETING, addressTo); } } - } diff --git a/src/test/java/org/springframework/data/gemfire/LazyWiringDeclarableSupportIntegrationTest.java b/src/test/java/org/springframework/data/gemfire/support/LazyWiringDeclarableSupportIntegrationTests.java similarity index 52% rename from src/test/java/org/springframework/data/gemfire/LazyWiringDeclarableSupportIntegrationTest.java rename to src/test/java/org/springframework/data/gemfire/support/LazyWiringDeclarableSupportIntegrationTests.java index 9f504636..9ebf699a 100644 --- a/src/test/java/org/springframework/data/gemfire/LazyWiringDeclarableSupportIntegrationTest.java +++ b/src/test/java/org/springframework/data/gemfire/support/LazyWiringDeclarableSupportIntegrationTests.java @@ -1,31 +1,35 @@ /* - * Copyright 2010-2013 the original author or authors. + * Copyright 2016 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 + * 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; +package org.springframework.data.gemfire.support; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; +import static org.assertj.core.api.Assertions.assertThat; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.nullValue; +import static org.hamcrest.Matchers.startsWith; +import static org.springframework.data.gemfire.support.WiringDeclarableSupport.TEMPLATE_BEAN_NAME_PROPERTY; import java.util.Properties; import javax.sql.DataSource; +import org.junit.Rule; import org.junit.Test; +import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; @@ -33,75 +37,72 @@ import org.springframework.context.event.ContextRefreshedEvent; import org.springframework.data.gemfire.repository.sample.User; import org.springframework.data.gemfire.test.support.DataSourceAdapter; import org.springframework.test.context.ContextConfiguration; -import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.test.context.junit4.SpringRunner; import org.springframework.util.Assert; /** - * The LazyWiringDeclarableSupportIntegrationTest class is a test suite of integration test cases testing - * a LazyWiringDeclarableSupport object/component's wiring configuration and initialization in - * a Spring container context. + * Integration tests for {@link LazyWiringDeclarableSupport}. * * @author John Blum * @see org.junit.Test - * @see org.junit.runner.RunWith * @see org.springframework.test.context.ContextConfiguration - * @see org.springframework.test.context.junit4.SpringJUnit4ClassRunner + * @see org.springframework.test.context.junit4.SpringRunner * @since 1.3.4 */ -@RunWith(SpringJUnit4ClassRunner.class) +@RunWith(SpringRunner.class) @ContextConfiguration @SuppressWarnings("unused") -public class LazyWiringDeclarableSupportIntegrationTest { +public class LazyWiringDeclarableSupportIntegrationTests { + + @Rule + public ExpectedException exception = ExpectedException.none(); @Autowired private ApplicationContext applicationContext; - protected static Properties createParameters(final String parameter, final String value) { + private static Properties createParameters(String parameter, String value) { Properties parameters = new Properties(); parameters.setProperty(parameter, value); return parameters; } @Test - public void testWiring() { + public void autoWiringSuccessful() { TestDeclarable declarable = new TestDeclarable(); declarable.init(createParameters("testParam", "testValue")); declarable.onApplicationEvent(new ContextRefreshedEvent(applicationContext)); declarable.assertInitialized(); - assertNull(declarable.getDataSource()); - assertNotNull(declarable.getUser()); - assertEquals("supertool", declarable.getUser().getUsername()); + assertThat(declarable.getDataSource()).isNull(); + assertThat(declarable.getUser()).isNotNull(); + assertThat(declarable.getUser().getUsername()).isEqualTo("supertool"); } @Test - public void testWiringWithBeanTemplate() { + public void autoWiringWithBeanTemplateSuccessful() { TestDeclarable declarable = new TestDeclarable(); - declarable.init(createParameters(LazyWiringDeclarableSupport.BEAN_NAME_PARAMETER, "declarableTemplateBean")); + declarable.init(createParameters(TEMPLATE_BEAN_NAME_PROPERTY, "declarableTemplateBean")); declarable.onApplicationEvent(new ContextRefreshedEvent(applicationContext)); declarable.assertInitialized(); - assertNotNull(declarable.getDataSource()); - assertNotNull(declarable.getUser()); - assertEquals("supertool", declarable.getUser().getUsername()); + assertThat(declarable.getDataSource()).isNotNull(); + assertThat(declarable.getUser()).isNotNull(); + assertThat(declarable.getUser().getUsername()).isEqualTo("supertool"); } - @Test(expected = IllegalArgumentException.class) - public void testWiringWithNonExistingBeanTemplate() { + @Test + public void autoWiringWithNonExistingBeanTemplateThrowsIllegalArgumentException() { + exception.expect(IllegalArgumentException.class); + exception.expectCause(is(nullValue(Throwable.class))); + exception.expectMessage(startsWith( + "Cannot find bean with name [nonExistingBeanTemplate]")); + TestDeclarable declarable = new TestDeclarable(); - try { - declarable.init(createParameters(LazyWiringDeclarableSupport.BEAN_NAME_PARAMETER, - "nonExistingBeanTemplate")); - declarable.onApplicationEvent(new ContextRefreshedEvent(applicationContext)); - } - catch (IllegalArgumentException expected) { - assertTrue(expected.getMessage().startsWith( - "No bean with name 'nonExistingBeanTemplate' was found in the Spring context")); - throw expected; - } + declarable.init(createParameters(TEMPLATE_BEAN_NAME_PROPERTY, "nonExistingBeanTemplate")); + declarable.onApplicationEvent(new ContextRefreshedEvent(applicationContext)); } protected static final class TestDataSource extends DataSourceAdapter { @@ -114,18 +115,17 @@ public class LazyWiringDeclarableSupportIntegrationTest { @Autowired private User user; - public final void setDataSource(final DataSource dataSource) { + public final void setDataSource(DataSource dataSource) { this.dataSource = dataSource; } - protected DataSource getDataSource() { + DataSource getDataSource() { return dataSource; } protected User getUser() { - Assert.state(user != null, "A reference to the User was not properly configured!"); + Assert.state(user != null, "A reference to the User was not properly configured"); return user; } } - } diff --git a/src/test/java/org/springframework/data/gemfire/LazyWiringDeclarableSupportTest.java b/src/test/java/org/springframework/data/gemfire/support/LazyWiringDeclarableSupportUnitTests.java similarity index 71% rename from src/test/java/org/springframework/data/gemfire/LazyWiringDeclarableSupportTest.java rename to src/test/java/org/springframework/data/gemfire/support/LazyWiringDeclarableSupportUnitTests.java index 201d4c81..beb8a649 100644 --- a/src/test/java/org/springframework/data/gemfire/LazyWiringDeclarableSupportTest.java +++ b/src/test/java/org/springframework/data/gemfire/support/LazyWiringDeclarableSupportUnitTests.java @@ -1,32 +1,35 @@ /* - * Copyright 2010-2013 the original author or authors. + * Copyright 2016 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 + * 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; +package org.springframework.data.gemfire.support; -import static org.hamcrest.CoreMatchers.equalTo; -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.CoreMatchers.not; -import static org.hamcrest.CoreMatchers.notNullValue; -import static org.hamcrest.CoreMatchers.nullValue; -import static org.hamcrest.CoreMatchers.sameInstance; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.not; +import static org.hamcrest.Matchers.notNullValue; +import static org.hamcrest.Matchers.nullValue; +import static org.hamcrest.Matchers.sameInstance; import static org.junit.Assert.assertThat; +import static org.mockito.Matchers.anyString; 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 static org.springframework.data.gemfire.support.GemfireBeanFactoryLocator.newBeanFactoryLocator; import java.util.Properties; import java.util.concurrent.atomic.AtomicBoolean; @@ -40,33 +43,31 @@ import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.event.ContextClosedEvent; import org.springframework.context.event.ContextRefreshedEvent; -import org.springframework.data.gemfire.support.SpringContextBootstrappingInitializer; /** - * The LazyWiringDeclarableSupportTest class is a test suite of test cases testing the contract and functionality - * of the LazyWiringDeclarableSupport class. This test class focuses on testing isolated units of functionality - * in the Declarable class directly, mocking any dependencies as appropriate, in order for the class to uphold - * it's contract. + * Unit tests for {@link LazyWiringDeclarableSupport}. * * @author John Blum * @see org.junit.Rule * @see org.junit.Test * @see org.mockito.Mockito - * @see org.springframework.data.gemfire.LazyWiringDeclarableSupport + * @see org.springframework.beans.factory.BeanFactory + * @see org.springframework.data.gemfire.support.GemfireBeanFactoryLocator + * @see org.springframework.data.gemfire.support.LazyWiringDeclarableSupport * @since 1.3.4 */ -public class LazyWiringDeclarableSupportTest { +public class LazyWiringDeclarableSupportUnitTests { @Rule - public ExpectedException expectedException = ExpectedException.none(); + public ExpectedException exception = ExpectedException.none(); - protected static void assertParameters(Properties parameters, String expectedKey, String expectedValue) { + private static void assertParameters(Properties parameters, String expectedKey, String expectedValue) { assertThat(parameters, is(notNullValue())); assertThat(parameters.containsKey(expectedKey), is(true)); assertThat(parameters.getProperty(expectedKey), is(equalTo(expectedValue))); } - protected static Properties createParameters(final String parameter, final String value) { + private static Properties createParameters(String parameter, String value) { Properties parameters = new Properties(); parameters.setProperty(parameter, value); return parameters; @@ -97,10 +98,10 @@ public class LazyWiringDeclarableSupportTest { }; try { - expectedException.expect(IllegalStateException.class); - expectedException.expectCause(is(nullValue(Throwable.class))); - expectedException.expectMessage(String.format( - "This Declarable object (%1$s) has not been properly configured and initialized", + exception.expect(IllegalStateException.class); + exception.expectCause(is(nullValue(Throwable.class))); + exception.expectMessage(String.format( + "This Declarable object [%s] has not been properly configured and initialized", declarable.getClass().getName())); declarable.assertInitialized(); @@ -125,17 +126,18 @@ public class LazyWiringDeclarableSupportTest { @Test public void assertUninitializedWhenInitialized() { LazyWiringDeclarableSupport declarable = new TestLazyWiringDeclarableSupport() { - @Override protected boolean isInitialized() { + @Override + protected boolean isInitialized() { return true; } }; try { - expectedException.expect(IllegalStateException.class); - expectedException.expectCause(is(nullValue(Throwable.class))); - expectedException.expectMessage(String.format( - "This Declarable object (%1$s) has already been configured and initialized", - declarable.getClass().getName())); + exception.expect(IllegalStateException.class); + exception.expectCause(is(nullValue(Throwable.class))); + exception.expectMessage(String.format( + "This Declarable object [%s] has already been configured and initialized", + declarable.getClass().getName())); declarable.assertUninitialized(); } @@ -189,25 +191,6 @@ public class LazyWiringDeclarableSupportTest { assertThat(declarable.isNotInitialized(), is(true)); } - @Test - public void locateBeanFactory() { - BeanFactory mockBeanFactory = mock(BeanFactory.class, "MockBeanFactory"); - - GemfireBeanFactoryLocator locator = new GemfireBeanFactoryLocator(); - - locator.setBeanName("MockBeanFactory"); - locator.setBeanFactory(mockBeanFactory); - - try { - locator.afterPropertiesSet(); - - assertThat(new TestLazyWiringDeclarableSupport().locateBeanFactory(null), is(sameInstance(mockBeanFactory))); - } - finally { - locator.destroy(); - } - } - @Test public void nullSafeGetParametersWithNullReference() { LazyWiringDeclarableSupport declarable = new TestLazyWiringDeclarableSupport(); @@ -227,11 +210,8 @@ public class LazyWiringDeclarableSupportTest { @Test public void onApplicationEvent() { - ConfigurableApplicationContext mockApplicationContext = mock(ConfigurableApplicationContext.class, - "MockConfigurableApplicationContext"); - - ConfigurableListableBeanFactory mockBeanFactory = mock(ConfigurableListableBeanFactory.class, - "MockConfigurableListableBeanFactory"); + ConfigurableApplicationContext mockApplicationContext = mock(ConfigurableApplicationContext.class); + ConfigurableListableBeanFactory mockBeanFactory = mock(ConfigurableListableBeanFactory.class); when(mockApplicationContext.getBeanFactory()).thenReturn(mockBeanFactory); @@ -241,7 +221,7 @@ public class LazyWiringDeclarableSupportTest { @Override protected void doPostInit(final Properties parameters) { super.doPostInit(parameters); assertInitialized(); - LazyWiringDeclarableSupportTest.assertParameters(parameters, "param", "value"); + LazyWiringDeclarableSupportUnitTests.assertParameters(parameters, "param", "value"); doPostInitCalled.set(true); } }; @@ -269,13 +249,13 @@ public class LazyWiringDeclarableSupportTest { LazyWiringDeclarableSupport declarable = new TestLazyWiringDeclarableSupport(); try { - ContextRefreshedEvent mockContextRefreshedEvent = mock(ContextRefreshedEvent.class, "MockContextRefreshedEvent"); + ContextRefreshedEvent mockContextRefreshedEvent = mock(ContextRefreshedEvent.class); when(mockContextRefreshedEvent.getApplicationContext()).thenReturn(null); - expectedException.expect(IllegalArgumentException.class); - expectedException.expectCause(is(nullValue(Throwable.class))); - expectedException.expectMessage("The Spring ApplicationContext (null) must be an instance of ConfigurableApplicationContext"); + exception.expect(IllegalArgumentException.class); + exception.expectCause(is(nullValue(Throwable.class))); + exception.expectMessage("The Spring ApplicationContext [null] must be an instance of ConfigurableApplicationContext"); declarable.onApplicationEvent(mockContextRefreshedEvent); } @@ -290,11 +270,8 @@ public class LazyWiringDeclarableSupportTest { @Test public void fullLifecycleOnApplicationEventToDestroy() throws Exception { - ConfigurableApplicationContext mockApplicationContext = mock(ConfigurableApplicationContext.class, - "MockConfigurableApplicationContext"); - - ConfigurableListableBeanFactory mockBeanFactory = mock(ConfigurableListableBeanFactory.class, - "MockConfigurableListableBeanFactory"); + ConfigurableApplicationContext mockApplicationContext = mock(ConfigurableApplicationContext.class); + ConfigurableListableBeanFactory mockBeanFactory = mock(ConfigurableListableBeanFactory.class); when(mockApplicationContext.getBeanFactory()).thenReturn(mockBeanFactory); @@ -304,7 +281,7 @@ public class LazyWiringDeclarableSupportTest { @Override protected void doPostInit(final Properties parameters) { super.doPostInit(parameters); assertInitialized(); - LazyWiringDeclarableSupportTest.assertParameters(parameters, "param", "value"); + LazyWiringDeclarableSupportUnitTests.assertParameters(parameters, "param", "value"); doPostInitCalled.set(true); } }; @@ -349,28 +326,27 @@ public class LazyWiringDeclarableSupportTest { @Test public void initThenOnApplicationEventThenInitWhenInitialized() { - BeanFactory mockBeanFactory = mock(BeanFactory.class, "MockBeanFactory"); + BeanFactory mockBeanFactory = mock(BeanFactory.class); - ConfigurableApplicationContext mockApplicationContext = mock(ConfigurableApplicationContext.class, "MockApplicationContext"); + ConfigurableApplicationContext mockApplicationContext = mock(ConfigurableApplicationContext.class); - ConfigurableListableBeanFactory mockConfigurableListableBeanFactory = mock(ConfigurableListableBeanFactory.class, - "MockConfigurableListableBeanFactory"); + ConfigurableListableBeanFactory mockConfigurableListableBeanFactory = + mock(ConfigurableListableBeanFactory.class); when(mockApplicationContext.getBeanFactory()).thenReturn(mockConfigurableListableBeanFactory); + when(mockBeanFactory.getAliases(anyString())).thenReturn(new String[0]); - GemfireBeanFactoryLocator locator = new GemfireBeanFactoryLocator(); - locator.setBeanName("MockBeanFactory"); - locator.setBeanFactory(mockBeanFactory); + GemfireBeanFactoryLocator locator = newBeanFactoryLocator(mockBeanFactory, "MockBeanFactory"); final AtomicBoolean doPostInitCalled = new AtomicBoolean(false); - final AtomicReference expectedKey = new AtomicReference("testParam"); - final AtomicReference expectedValue = new AtomicReference("testValue"); + final AtomicReference expectedKey = new AtomicReference<>("testParam"); + final AtomicReference expectedValue = new AtomicReference<>("testValue"); TestLazyWiringDeclarableSupport declarable = new TestLazyWiringDeclarableSupport() { @Override protected void doPostInit(final Properties parameters) { super.doPostInit(parameters); assertInitialized(); - LazyWiringDeclarableSupportTest.assertParameters(parameters, expectedKey.get(), expectedValue.get()); + LazyWiringDeclarableSupportUnitTests.assertParameters(parameters, expectedKey.get(), expectedValue.get()); doPostInitCalled.set(true); } }; @@ -394,7 +370,7 @@ public class LazyWiringDeclarableSupportTest { doPostInitCalled.set(false); declarable.onApplicationEvent(new ContextRefreshedEvent(mockApplicationContext)); - declarable.assertBeanFactory(mockBeanFactory); + declarable.assertBeanFactory(mockConfigurableListableBeanFactory); declarable.assertParameters(parameters); assertThat(declarable.isInitialized(), is(true)); @@ -421,29 +397,26 @@ public class LazyWiringDeclarableSupportTest { } } - protected static class TestLazyWiringDeclarableSupport extends LazyWiringDeclarableSupport { + private static class TestLazyWiringDeclarableSupport extends LazyWiringDeclarableSupport { private BeanFactory actualBeanFactory; private Properties actualParameters; - protected void assertBeanFactory(final BeanFactory expectedBeanFactory) { - assertThat(actualBeanFactory, is(sameInstance(expectedBeanFactory))); + private void assertBeanFactory(final BeanFactory expectedBeanFactory) { + assertThat(this.actualBeanFactory, is(sameInstance(expectedBeanFactory))); } - protected void assertParameters(final Properties expectedParameters) { - assertThat(actualParameters, is(equalTo(expectedParameters))); + private void assertParameters(final Properties expectedParameters) { + assertThat(this.actualParameters, is(equalTo(expectedParameters))); } @Override - void doInit(final BeanFactory beanFactory, final Properties parameters) { - if (!isInitialized()) { - this.actualBeanFactory = beanFactory; - initialized = true; - } - + void doInit(BeanFactory beanFactory, Properties parameters) { + this.actualBeanFactory = beanFactory; this.actualParameters = parameters; + this.initialized = true; + doPostInit(parameters); } } - } diff --git a/src/test/java/org/springframework/data/gemfire/support/SpringContextBootstrappingInitializerIntegrationTest.java b/src/test/java/org/springframework/data/gemfire/support/SpringContextBootstrappingInitializerIntegrationTest.java index cdae3322..427256fe 100644 --- a/src/test/java/org/springframework/data/gemfire/support/SpringContextBootstrappingInitializerIntegrationTest.java +++ b/src/test/java/org/springframework/data/gemfire/support/SpringContextBootstrappingInitializerIntegrationTest.java @@ -47,7 +47,6 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.data.gemfire.LazyWiringDeclarableSupport; import org.springframework.data.gemfire.config.xml.GemfireConstants; import org.springframework.data.gemfire.repository.sample.User; import org.springframework.data.gemfire.support.sample.TestUserDao; @@ -62,7 +61,7 @@ import org.springframework.util.Assert; * @author John Blum * @see org.junit.Test * @see org.springframework.context.ConfigurableApplicationContext - * @see org.springframework.data.gemfire.LazyWiringDeclarableSupport + * @see LazyWiringDeclarableSupport * @see org.springframework.data.gemfire.support.SpringContextBootstrappingInitializer * @see org.apache.geode.cache.Cache * @see org.apache.geode.cache.CacheFactory diff --git a/src/test/java/org/springframework/data/gemfire/support/SpringContextBootstrappingInitializerTest.java b/src/test/java/org/springframework/data/gemfire/support/SpringContextBootstrappingInitializerTest.java index 3934eeb3..66475317 100644 --- a/src/test/java/org/springframework/data/gemfire/support/SpringContextBootstrappingInitializerTest.java +++ b/src/test/java/org/springframework/data/gemfire/support/SpringContextBootstrappingInitializerTest.java @@ -118,7 +118,7 @@ public class SpringContextBootstrappingInitializerTest { @Test public void getUninitializedApplicationContext() { expectedException.expect(IllegalStateException.class); - expectedException.expectMessage("The Spring ApplicationContext was not configured and initialized properly!"); + expectedException.expectMessage("A Spring ApplicationContext was not configured and initialized properly"); expectedException.expectCause(is(nullValue(Throwable.class))); SpringContextBootstrappingInitializer.getApplicationContext(); @@ -152,7 +152,7 @@ public class SpringContextBootstrappingInitializerTest { expectedException.expect(IllegalStateException.class); expectedException.expectCause(is(nullValue(Throwable.class))); - expectedException.expectMessage("The Spring ApplicationContext has already been initialized!"); + expectedException.expectMessage("A Spring ApplicationContext has already been initialized"); try { SpringContextBootstrappingInitializer.applicationContext = mockApplicationContext; @@ -267,7 +267,7 @@ public class SpringContextBootstrappingInitializerTest { public void initApplicationContextWithNull() { expectedException.expect(IllegalArgumentException.class); expectedException.expectCause(is(nullValue(Throwable.class))); - expectedException.expectMessage("The ConfigurableApplicationContext reference must not be null"); + expectedException.expectMessage("ConfigurableApplicationContext must not be null"); new SpringContextBootstrappingInitializer().initApplicationContext(null); } @@ -287,7 +287,7 @@ public class SpringContextBootstrappingInitializerTest { public void refreshApplicationContextWithNull() { expectedException.expect(IllegalArgumentException.class); expectedException.expectCause(is(nullValue(Throwable.class))); - expectedException.expectMessage("The ConfigurableApplicationContext reference must not be null"); + expectedException.expectMessage("ConfigurableApplicationContext must not be null"); new SpringContextBootstrappingInitializer().refreshApplicationContext(null); } @@ -301,7 +301,7 @@ public class SpringContextBootstrappingInitializerTest { assertThat(new SpringContextBootstrappingInitializer() .registerAnnotatedClasses(mockApplicationContext, annotatedClasses), - is(sameInstance((ConfigurableApplicationContext) mockApplicationContext))); + is(sameInstance(mockApplicationContext))); verify(mockApplicationContext, times(1)).register(annotatedClasses); } @@ -313,7 +313,7 @@ public class SpringContextBootstrappingInitializerTest { assertThat(new SpringContextBootstrappingInitializer().registerAnnotatedClasses(mockApplicationContext, new Class[0]), - is(sameInstance((ConfigurableApplicationContext) mockApplicationContext))); + is(sameInstance(mockApplicationContext))); verify(mockApplicationContext, never()).register(any(Class[].class)); } @@ -335,7 +335,7 @@ public class SpringContextBootstrappingInitializerTest { String[] basePackages = { "org.example.app", "org.example.plugins" }; assertThat(new SpringContextBootstrappingInitializer().scanBasePackages(mockApplicationContext, basePackages), - is(sameInstance((ConfigurableApplicationContext) mockApplicationContext))); + is(sameInstance(mockApplicationContext))); verify(mockApplicationContext, times(1)).scan(basePackages); } @@ -346,7 +346,7 @@ public class SpringContextBootstrappingInitializerTest { "MockApplicationContext"); assertThat(new SpringContextBootstrappingInitializer().scanBasePackages(mockApplicationContext, null), - is(sameInstance((ConfigurableApplicationContext) mockApplicationContext))); + is(sameInstance(mockApplicationContext))); verify(mockApplicationContext, never()).scan(any(String[].class)); } @@ -368,7 +368,7 @@ public class SpringContextBootstrappingInitializerTest { SpringContextBootstrappingInitializer.setBeanClassLoader(Thread.currentThread().getContextClassLoader()); assertThat(new SpringContextBootstrappingInitializer().setClassLoader(mockApplicationContext), - is(sameInstance((ConfigurableApplicationContext) mockApplicationContext))); + is(sameInstance(mockApplicationContext))); verify(mockApplicationContext, times(1)).setClassLoader(eq(Thread.currentThread().getContextClassLoader())); } @@ -392,7 +392,7 @@ public class SpringContextBootstrappingInitializerTest { SpringContextBootstrappingInitializer.setBeanClassLoader(null); assertThat(new SpringContextBootstrappingInitializer().setClassLoader(mockApplicationContext), - is(sameInstance((ConfigurableApplicationContext) mockApplicationContext))); + is(sameInstance(mockApplicationContext))); verify(mockApplicationContext, never()).setClassLoader(any(ClassLoader.class)); } @@ -606,8 +606,9 @@ public class SpringContextBootstrappingInitializerTest { return mockLog; } - @Override protected ConfigurableApplicationContext createApplicationContext(final String[] basePackages, - final String[] configLocations) { + @Override protected ConfigurableApplicationContext createApplicationContext(String[] basePackages, + String[] configLocations) { + throw new IllegalStateException("TEST"); } }; @@ -949,5 +950,4 @@ public class SpringContextBootstrappingInitializerTest { return this.name; } } - } diff --git a/src/test/java/org/springframework/data/gemfire/support/WiringDeclarableSupportIntegrationTests.java b/src/test/java/org/springframework/data/gemfire/support/WiringDeclarableSupportIntegrationTests.java new file mode 100644 index 00000000..ce52b8ee --- /dev/null +++ b/src/test/java/org/springframework/data/gemfire/support/WiringDeclarableSupportIntegrationTests.java @@ -0,0 +1,108 @@ +/* + * Copyright 2016 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.support; + + +import static org.assertj.core.api.Assertions.assertThat; + +import javax.annotation.Resource; + +import org.apache.geode.cache.CacheLoader; +import org.apache.geode.cache.CacheLoaderException; +import org.apache.geode.cache.DataPolicy; +import org.apache.geode.cache.LoaderHelper; +import org.apache.geode.cache.Region; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringRunner; + +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * Integration test for {@link WiringDeclarableSupport} and {@link GemfireBeanFactoryLocator}. + * + * @author Costin Leau + * @author John Blum + * @see org.junit.Test + * @see lombok + * @see org.apache.geode.cache.CacheLoader + * @see org.springframework.beans.factory.BeanFactory + * @see org.springframework.data.gemfire.support.GemfireBeanFactoryLocator + * @see org.springframework.data.gemfire.support.WiringDeclarableSupport + * @see org.springframework.test.context.ContextConfiguration + * @see org.springframework.test.context.junit4.SpringRunner + */ +@RunWith(SpringRunner.class) +@ContextConfiguration +public class WiringDeclarableSupportIntegrationTests { + + @Autowired + @SuppressWarnings("unused") + private BeanFactory beanFactory; + + @Resource(name = "Example") + @SuppressWarnings("unused") + private Region example; + + private void assertRegion(Region region, String name, DataPolicy dataPolicy) { + assertThat(region).isNotNull(); + assertThat(region.getName()).isEqualTo(name); + assertThat(region.getFullPath()).isEqualTo(String.format("%1$s%2$s", Region.SEPARATOR, name)); + assertThat(region.getAttributes()).isNotNull(); + assertThat(region.getAttributes().getDataPolicy()).isEqualTo(dataPolicy); + } + + @Test + public void declarableObjectAutoWiredSuccessfully() throws Exception { + assertThat(beanFactory.containsBean("testBean")).isTrue(); + assertRegion(example, "Example", DataPolicy.NORMAL); + + CacheLoader testCacheLoader = example.getAttributes().getCacheLoader(); + + assertThat(testCacheLoader).isInstanceOf(TestCacheLoader.class); + assertThat(((TestCacheLoader) testCacheLoader).getBeanFactory()).isSameAs(beanFactory); + assertThat(((TestCacheLoader) testCacheLoader).getPropertyOne()).isEqualTo(beanFactory.getBean("testBean")); + assertThat(((TestCacheLoader) testCacheLoader).getPropertyTwo()).isEqualTo("GoodBye"); + } + + @Data + @NoArgsConstructor + public static class TestBean { + private String name; + } + + @Data + @NoArgsConstructor + public static class TestCacheLoader extends WiringDeclarableSupport implements CacheLoader { + + private Object propertyOne; + private String propertyTwo; + + /** + * @inheritDoc + */ + @Override + public String load(LoaderHelper helper) throws CacheLoaderException { + return helper.getKey(); + } + } +} 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 22dbade2..277475be 100644 --- a/src/test/java/org/springframework/data/gemfire/test/MockCacheFactoryBean.java +++ b/src/test/java/org/springframework/data/gemfire/test/MockCacheFactoryBean.java @@ -30,7 +30,6 @@ public class MockCacheFactoryBean extends CacheFactoryBean { setUseBeanFactoryLocator(false); if (cacheFactoryBean != null) { - this.beanFactoryLocator = cacheFactoryBean.getBeanFactoryLocator(); setBeanClassLoader(cacheFactoryBean.getBeanClassLoader()); setBeanFactory(cacheFactoryBean.getBeanFactory()); setBeanName(cacheFactoryBean.getBeanName()); @@ -56,6 +55,7 @@ public class MockCacheFactoryBean extends CacheFactoryBean { setSearchTimeout(cacheFactoryBean.getSearchTimeout()); setTransactionListeners(cacheFactoryBean.getTransactionListeners()); setTransactionWriter(cacheFactoryBean.getTransactionWriter()); + setUseBeanFactoryLocator(cacheFactoryBean.isUseBeanFactoryLocator()); } } diff --git a/src/test/java/org/springframework/data/gemfire/util/SpringUtilsUnitTests.java b/src/test/java/org/springframework/data/gemfire/util/SpringUtilsUnitTests.java index 2c53a4d4..73d3742f 100644 --- a/src/test/java/org/springframework/data/gemfire/util/SpringUtilsUnitTests.java +++ b/src/test/java/org/springframework/data/gemfire/util/SpringUtilsUnitTests.java @@ -122,6 +122,37 @@ public class SpringUtilsUnitTests { assertThat(SpringUtils.equalsIgnoreNull("nil", "null")).isFalse(); } + @Test + public void nullOrEqualsWithNullIsTrue() { + assertThat(SpringUtils.nullOrEquals(null, "test")).isTrue(); + } + + @Test + public void nullOrEqualsWithEqualObjectsIsTrue() { + assertThat(SpringUtils.nullOrEquals("test", "test")).isTrue(); + } + + @Test + public void nullOrEqualsWithUnequalObjectsIsFalse() { + assertThat(SpringUtils.nullOrEquals("test", "mock")).isFalse(); + } + + @Test + public void nullSafeEqualsWithEqualObjectsIsTrue() { + assertThat(SpringUtils.nullSafeEquals("test", "test")).isTrue(); + } + + @Test + public void nullSafeEqualsWithUnequalObjectsIsFalse() { + assertThat(SpringUtils.nullSafeEquals("test", "mock")).isFalse(); + } + + @Test + public void nullSafeEqualsWithNullObjectsIsFalse() { + assertThat(SpringUtils.nullSafeEquals(null, "test")).isFalse(); + assertThat(SpringUtils.nullSafeEquals("test", null)).isFalse(); + } + @Test public void dereferenceBean() { assertThat(SpringUtils.dereferenceBean("example")).isEqualTo("&example"); diff --git a/src/test/resources/cache-with-declarable.xml b/src/test/resources/cache-with-declarable.xml index eecd69a3..be7daa16 100644 --- a/src/test/resources/cache-with-declarable.xml +++ b/src/test/resources/cache-with-declarable.xml @@ -1,32 +1,11 @@ - - - java.lang.String - - org.springframework.data.gemfire.UserObject - - - - - - - - - - - - - - - - - + + + + + org.springframework.data.gemfire.support.WiringDeclarableSupportIntegrationTests$TestCacheLoader + - - Application Version - 1.0 - - diff --git a/src/test/resources/lazy-wiring-declarable-support-function-cache.xml b/src/test/resources/lazy-wiring-declarable-support-function-cache.xml index 203bcde7..372e922c 100644 --- a/src/test/resources/lazy-wiring-declarable-support-function-cache.xml +++ b/src/test/resources/lazy-wiring-declarable-support-function-cache.xml @@ -4,7 +4,7 @@ - org.springframework.data.gemfire.LazyWiringDeclarableSupportFunctionBasedIntegrationTest$HelloGemFireFunction + org.springframework.data.gemfire.support.LazyWiringDeclarableSupportFunctionBasedIntegrationTests$HelloGemFireFunction Everyone diff --git a/src/test/resources/org/springframework/data/gemfire/support/GemfireBeanFactoryLocatorIntegrationTests-context.xml b/src/test/resources/org/springframework/data/gemfire/support/GemfireBeanFactoryLocatorIntegrationTests-context.xml new file mode 100644 index 00000000..f468ad2f --- /dev/null +++ b/src/test/resources/org/springframework/data/gemfire/support/GemfireBeanFactoryLocatorIntegrationTests-context.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + diff --git a/src/test/resources/org/springframework/data/gemfire/LazyWiringDeclarableSupportFunctionBasedIntegrationTest-context.xml b/src/test/resources/org/springframework/data/gemfire/support/LazyWiringDeclarableSupportFunctionBasedIntegrationTests-context.xml similarity index 100% rename from src/test/resources/org/springframework/data/gemfire/LazyWiringDeclarableSupportFunctionBasedIntegrationTest-context.xml rename to src/test/resources/org/springframework/data/gemfire/support/LazyWiringDeclarableSupportFunctionBasedIntegrationTests-context.xml diff --git a/src/test/resources/org/springframework/data/gemfire/LazyWiringDeclarableSupportIntegrationTest-context.xml b/src/test/resources/org/springframework/data/gemfire/support/LazyWiringDeclarableSupportIntegrationTests-context.xml similarity index 74% rename from src/test/resources/org/springframework/data/gemfire/LazyWiringDeclarableSupportIntegrationTest-context.xml rename to src/test/resources/org/springframework/data/gemfire/support/LazyWiringDeclarableSupportIntegrationTests-context.xml index db89d809..7f53d596 100644 --- a/src/test/resources/org/springframework/data/gemfire/LazyWiringDeclarableSupportIntegrationTest-context.xml +++ b/src/test/resources/org/springframework/data/gemfire/support/LazyWiringDeclarableSupportIntegrationTests-context.xml @@ -2,10 +2,10 @@ - + diff --git a/src/test/resources/org/springframework/data/gemfire/cache-with-declarable-ctx.xml b/src/test/resources/org/springframework/data/gemfire/support/WiringDeclarableSupportIntegrationTests-context.xml similarity index 68% rename from src/test/resources/org/springframework/data/gemfire/cache-with-declarable-ctx.xml rename to src/test/resources/org/springframework/data/gemfire/support/WiringDeclarableSupportIntegrationTests-context.xml index 13c605a0..24e09f17 100644 --- a/src/test/resources/org/springframework/data/gemfire/cache-with-declarable-ctx.xml +++ b/src/test/resources/org/springframework/data/gemfire/support/WiringDeclarableSupportIntegrationTests-context.xml @@ -11,16 +11,18 @@ "> - CacheWithDeclarableContextConfig - 0 + WiringDeclarableSupportIntegrationTests warning - + - + + +