diff --git a/src/main/java/org/springframework/data/gemfire/DeclarableSupport.java b/src/main/java/org/springframework/data/gemfire/DeclarableSupport.java index f5fb7baf..4c8a1688 100644 --- a/src/main/java/org/springframework/data/gemfire/DeclarableSupport.java +++ b/src/main/java/org/springframework/data/gemfire/DeclarableSupport.java @@ -25,69 +25,82 @@ import com.gemstone.gemfire.cache.CacheCallback; import com.gemstone.gemfire.cache.Declarable; /** - * Convenience class for Spring-aware GemFire Declarable components. Provides a - * reference to the current Spring application context, e.g. for bean lookup or - * resource loading. + * 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 - * container capabilities and does not enforce the {@link Declarable} interface + * 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 com.gemstone.gemfire.cache.CacheCallback + * @see com.gemstone.gemfire.cache.Declarable */ +@SuppressWarnings("unused") public abstract class DeclarableSupport implements CacheCallback, Declarable { - private String factoryKey = null; + private String beanFactoryKey = null; - private BeanFactoryReference bfReference = null; + private BeanFactoryReference beanFactoryReference = null; public DeclarableSupport() { } /** - * This implementation uses this method as a lifecycle hook to initialize - * the bean factory locator. - * - * {@inheritDoc} - * - * @see #setFactoryKey(String) + * Gets a reference to the configured Spring BeanFactory. + * + * @return a Spring BeanFactory reference. + * @see org.springframework.beans.factory.BeanFactory */ - @Override - public final void init(Properties props) { - bfReference = new GemfireBeanFactoryLocator().useBeanFactory(factoryKey); - initInstance(props); - } - - /** - * Initialize the current instance based on the given properties. - * - * @param props the Properties used to initialize this Declarable. - * @see com.gemstone.gemfire.cache.Declarable#init(java.util.Properties) - * @see java.util.Properties - */ - protected void initInstance(Properties props) { - } - protected BeanFactory getBeanFactory() { - return bfReference.getFactory(); - } - - @Override - public void close() { - bfReference.release(); - bfReference = null; + 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. - * - * @see GemfireBeanFactoryLocator - * @param key a String specifying the key used to lookup the "enclosing" BeanFactory in the presenence of - * multiple BeanFactories. + * + * @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.factoryKey = 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 com.gemstone.gemfire.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 index 9205a9df..f9b8bf1f 100644 --- a/src/main/java/org/springframework/data/gemfire/GemfireBeanFactoryLocator.java +++ b/src/main/java/org/springframework/data/gemfire/GemfireBeanFactoryLocator.java @@ -47,6 +47,7 @@ import org.springframework.util.StringUtils; * by {@link com.gemstone.gemfire.cache.CacheFactory}. * * @author Costin Leau + * @author John Blum */ public class GemfireBeanFactoryLocator implements BeanFactoryLocator, BeanFactoryAware, BeanNameAware, DisposableBean, InitializingBean { @@ -62,19 +63,19 @@ public class GemfireBeanFactoryLocator implements BeanFactoryLocator, BeanFactor private static class SimpleBeanFactoryReference implements BeanFactoryReference { - private BeanFactory bf; + private BeanFactory beanFactory; - SimpleBeanFactoryReference(BeanFactory bf) { - this.bf = bf; + SimpleBeanFactoryReference(BeanFactory beanFactory) { + this.beanFactory = beanFactory; } public BeanFactory getFactory() { - Assert.notNull(bf, "beanFactory already released or closed"); - return bf; + Assert.state(beanFactory != null, "The BeanFactory has already been released or closed"); + return beanFactory; } public void release() throws FatalBeanException { - bf = null; + beanFactory = null; } } @@ -106,7 +107,7 @@ public class GemfireBeanFactoryLocator implements BeanFactoryLocator, BeanFactor // add aliases if (StringUtils.hasText(factoryName)) { String[] aliases = beanFactory.getAliases(factoryName); - names = (String[]) ObjectUtils.addObjectToArray(aliases, factoryName); + names = ObjectUtils.addObjectToArray(aliases, factoryName); for (String name : names) { if (log.isDebugEnabled()) @@ -161,4 +162,5 @@ public class GemfireBeanFactoryLocator implements BeanFactoryLocator, BeanFactor 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 index 210a340a..7f3f0c50 100644 --- a/src/main/java/org/springframework/data/gemfire/LazyWiringDeclarableSupport.java +++ b/src/main/java/org/springframework/data/gemfire/LazyWiringDeclarableSupport.java @@ -19,17 +19,15 @@ package org.springframework.data.gemfire; import java.util.Properties; import java.util.concurrent.atomic.AtomicReference; +import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.DisposableBean; -import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; 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; import com.gemstone.gemfire.cache.Declarable; @@ -41,10 +39,13 @@ import com.gemstone.gemfire.cache.Declarable; * @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.context.ApplicationListener * @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 com.gemstone.gemfire.cache.Declarable * @since 1.3.4 */ @@ -52,15 +53,18 @@ import com.gemstone.gemfire.cache.Declarable; public abstract class LazyWiringDeclarableSupport implements ApplicationListener, Declarable, DisposableBean { - // The name of the template bean defined in the Spring context for wiring this Declarable instance. + // 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 Declared was constructed + // 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 String factoryKey = null; + /** * Constructs an instance of the LazyWiringDeclarableSupport class registered with the * SpringContextBootstrappingInitializer. This Declarable will receive notifications from the @@ -75,6 +79,30 @@ public abstract class LazyWiringDeclarableSupport implements ApplicationListener 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 @@ -88,7 +116,7 @@ public abstract class LazyWiringDeclarableSupport implements ApplicationListener */ protected void assertInitialized() { Assert.state(isInitialized(), String.format( - "This Declarable object (%1$s) has not been properly configured and initialized!", + "This Declarable object (%1$s) has not been properly configured and initialized", getClass().getName())); } @@ -104,7 +132,7 @@ public abstract class LazyWiringDeclarableSupport implements ApplicationListener */ protected void assertUninitialized() { Assert.state(!isInitialized(), String.format( - "This Declarable object (%1$s) has already been configured and initialized, and is currently active!", + "This Declarable object (%1$s) has already been configured and initialized", getClass().getName())); } @@ -125,33 +153,37 @@ public abstract class LazyWiringDeclarableSupport implements ApplicationListener * @see org.springframework.beans.factory.wiring.BeanWiringInfo * @see org.springframework.beans.factory.wiring.BeanWiringInfoResolver */ - /* package-private */ void doInit(final ConfigurableListableBeanFactory beanFactory, final Properties parameters) { - BeanConfigurerSupport beanConfigurer = new BeanConfigurerSupport(); + void doInit(final BeanFactory beanFactory, final Properties parameters) { + synchronized (this) { + if (isNotInitialized()) { + BeanConfigurerSupport beanConfigurer = new BeanConfigurerSupport(); - beanConfigurer.setBeanFactory(beanFactory); + beanConfigurer.setBeanFactory(beanFactory); - final String templateBeanName = parameters.getProperty(BEAN_NAME_PARAMETER); + 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); + 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)); + 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; } } - beanConfigurer.afterPropertiesSet(); - beanConfigurer.configureBean(this); - beanConfigurer.destroy(); - - initialized = true; - doPostInit(parameters); } @@ -161,7 +193,7 @@ public abstract class LazyWiringDeclarableSupport implements ApplicationListener * * @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(org.springframework.beans.factory.config.ConfigurableListableBeanFactory, java.util.Properties) + * @see #doInit(BeanFactory, Properties) */ protected void doPostInit(final Properties parameters) { } @@ -174,28 +206,60 @@ public abstract class LazyWiringDeclarableSupport implements ApplicationListener * 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(org.springframework.beans.factory.config.ConfigurableListableBeanFactory, java.util.Properties) + * @see #doInit(BeanFactory, Properties) * @see java.util.Properties */ @Override public final void init(final Properties parameters) { - assertUninitialized(); 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. + * @return a boolean value indicating whether this Declarable object has been configured and initialized + * by the Spring container. * @see #assertInitialized() - * @see #doInit(org.springframework.beans.factory.config.ConfigurableListableBeanFactory, java.util.Properties) + * @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) { + return new GemfireBeanFactoryLocator().useBeanFactory(factoryKey).getFactory(); + } + /** * Null-safe operation to return the parameters passed to this Declarable object when created by GemFire from it's * configuration meta-data. @@ -216,19 +280,15 @@ public abstract class LazyWiringDeclarableSupport implements ApplicationListener * @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(org.springframework.beans.factory.config.ConfigurableListableBeanFactory, java.util.Properties) + * @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()); + Assert.notNull(event.getApplicationContext(), "The Spring ApplicationContext must not be null"); + doInit(event.getApplicationContext(), nullSafeGetParameters()); } /** diff --git a/src/main/java/org/springframework/data/gemfire/WiringDeclarableSupport.java b/src/main/java/org/springframework/data/gemfire/WiringDeclarableSupport.java index a44b5a47..17f0f6b0 100644 --- a/src/main/java/org/springframework/data/gemfire/WiringDeclarableSupport.java +++ b/src/main/java/org/springframework/data/gemfire/WiringDeclarableSupport.java @@ -24,43 +24,50 @@ import org.springframework.beans.factory.wiring.BeanWiringInfo; import org.springframework.beans.factory.wiring.BeanWiringInfoResolver; import com.gemstone.gemfire.cache.Declarable; +import com.gemstone.gemfire.management.internal.cli.util.spring.StringUtils; /** - * Dedicated {@link Declarable} support class for wiring the declaring instance through - * the Spring container. - * This implementation will first look for a 'bean-name' property which will be used to - * locate a 'template' bean definition. In case the property is not given, a bean named - * after the class will be searched and if none is found, autowiring will be performed, - * based on the settings defined in the Spring container. + * 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 com.gemstone.gemfire.cache.Declarable */ public class WiringDeclarableSupport extends DeclarableSupport { - private static final String BEAN_NAME_PROP = "bean-name"; + private static final String BEAN_NAME_PROPERTY = "bean-name"; @Override - protected void initInstance(Properties props) { - BeanFactory bf = getBeanFactory(); - BeanConfigurerSupport configurer = new BeanConfigurerSupport(); - configurer.setBeanFactory(bf); + protected void initInstance(Properties parameters) { + BeanFactory beanFactory = getBeanFactory(); - final String beanName = props.getProperty(BEAN_NAME_PROP); - // key specified, search for a bean - if (beanName != null) { - if (!bf.containsBean(beanName)) { - throw new IllegalArgumentException("Cannot find bean named '" + beanName + "'"); + 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)); } - configurer.setBeanWiringInfoResolver(new BeanWiringInfoResolver() { + beanConfigurer.setBeanWiringInfoResolver(new BeanWiringInfoResolver() { public BeanWiringInfo resolveWiringInfo(Object beanInstance) { return new BeanWiringInfo(beanName); } }); } - configurer.afterPropertiesSet(); - configurer.configureBean(this); - configurer.destroy(); + beanConfigurer.afterPropertiesSet(); + beanConfigurer.configureBean(this); + beanConfigurer.destroy(); } + } 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 5650567e..a3b9b52f 100644 --- a/src/main/java/org/springframework/data/gemfire/support/SpringContextBootstrappingInitializer.java +++ b/src/main/java/org/springframework/data/gemfire/support/SpringContextBootstrappingInitializer.java @@ -56,10 +56,12 @@ import com.gemstone.gemfire.cache.Declarable; * @see org.springframework.context.ApplicationListener * @see org.springframework.context.ConfigurableApplicationContext * @see org.springframework.context.annotation.AnnotationConfigApplicationContext + * @see org.springframework.context.event.ApplicationContextEvent + * @see org.springframework.context.event.ApplicationEventMulticaster * @see org.springframework.context.support.ClassPathXmlApplicationContext * @see com.gemstone.gemfire.cache.Declarable - * @see Setting Cache Initializer - * @see SGF-248 + * @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 * @since 1.4.0 */ @SuppressWarnings("unused") @@ -73,11 +75,11 @@ public class SpringContextBootstrappingInitializer implements Declarable, Applic private static final ApplicationEventMulticaster applicationEventNotifier = new SimpleApplicationEventMulticaster(); - private static final AtomicReference beanClassLoaderRef = new AtomicReference(null); + private static final AtomicReference beanClassLoaderReference = new AtomicReference(null); - /* package-private */ static volatile ConfigurableApplicationContext applicationContext; + static volatile ConfigurableApplicationContext applicationContext; - /* package-private */ static volatile ContextRefreshedEvent contextRefreshedEvent; + static volatile ContextRefreshedEvent contextRefreshedEvent; private static final List> registeredAnnotatedClasses = new CopyOnWriteArrayList>(); @@ -96,8 +98,8 @@ public class SpringContextBootstrappingInitializer implements Declarable, Applic } /** - * Sets the ClassLoader used by Spring ApplicationContext, created by this GemFire ("Bootstrapping") Initializer, - * when creating bean definition classes. + * Sets the ClassLoader used by the Spring ApplicationContext, created by this GemFire Initializer, when creating + * bean definition classes. * * @param beanClassLoader the ClassLoader used by the Spring ApplicationContext to load bean definition classes. * @throws java.lang.IllegalStateException if the Spring ApplicationContext has already been created @@ -106,7 +108,7 @@ public class SpringContextBootstrappingInitializer implements Declarable, Applic */ public static void setBeanClassLoader(ClassLoader beanClassLoader) { if (applicationContext == null || !applicationContext.isActive()) { - beanClassLoaderRef.set(beanClassLoader); + beanClassLoaderReference.set(beanClassLoader); } else { throw new IllegalStateException("The Spring ApplicationContext has already been initialized!"); @@ -167,7 +169,7 @@ public class SpringContextBootstrappingInitializer implements Declarable, Applic * @see #unregister(Class) */ public static boolean register(Class annotatedClass) { - Assert.notNull(annotatedClass, "the Spring annotated class to register must not be null"); + Assert.notNull(annotatedClass, "The Spring annotated class to register must not be null"); return registeredAnnotatedClasses.add(annotatedClass); } @@ -216,6 +218,14 @@ public class SpringContextBootstrappingInitializer implements Declarable, Applic return LogFactory.getLog(getClass()); } + /* (non-Javadoc) */ + private boolean isConfigurable(Collection> annotatedClasses, String[] basePackages, + String[] contextConfigLocations) { + + return !(CollectionUtils.isEmpty(annotatedClasses) && ObjectUtils.isEmpty(basePackages) + && ObjectUtils.isEmpty(contextConfigLocations)); + } + /** * Creates (constructs and configures) an instance of the ConfigurableApplicationContext based on either the * specified base packages containing @Configuration, @Component or JSR 330 annotated classes to scan, or the @@ -241,17 +251,12 @@ public class SpringContextBootstrappingInitializer implements Declarable, Applic * @see org.springframework.context.support.ClassPathXmlApplicationContext */ protected ConfigurableApplicationContext createApplicationContext(String[] basePackages, String[] configLocations) { - if (!ObjectUtils.isEmpty(configLocations)) { - return createApplicationContext(configLocations); - } - else { - Assert.isTrue(isConfigurable(basePackages, configLocations, registeredAnnotatedClasses), - "'basePackages', 'configLocations' or 'AnnotatedClasses' must be specified in order to" - + " construct and configure an instance of the ConfigurableApplicationContext"); + Assert.isTrue(isConfigurable(registeredAnnotatedClasses, basePackages, configLocations), + "'AnnotatedClasses', 'basePackages' or 'configLocations' must be specified in order to" + + " construct and configure an instance of the ConfigurableApplicationContext"); - return scanBasePackages(registerAnnotatedClasses((AnnotationConfigApplicationContext) createApplicationContext(null), - registeredAnnotatedClasses.toArray(new Class[registeredAnnotatedClasses.size()])), basePackages); - } + return scanBasePackages(registerAnnotatedClasses(createApplicationContext(configLocations), + registeredAnnotatedClasses.toArray(new Class[registeredAnnotatedClasses.size()])), basePackages); } /* (non-Javadoc) - used for testing purposes only */ @@ -272,7 +277,7 @@ 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, "The ConfigurableApplicationContext reference must not be null"); applicationContext.addApplicationListener(this); applicationContext.registerShutdownHook(); return setClassLoader(applicationContext); @@ -288,29 +293,11 @@ 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, "The ConfigurableApplicationContext reference must not be null"); applicationContext.refresh(); return applicationContext; } - /* (non-Javadoc) */ - private boolean isConfigurable(String[] basePackages, String[] contextConfigLocations, - Collection> annotatedClasses) { - return !(ObjectUtils.isEmpty(basePackages) && ObjectUtils.isEmpty(contextConfigLocations) - && CollectionUtils.isEmpty(annotatedClasses)); - } - - /** - * 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); - } - /** * Registers the given Spring annotated (@Configuration) POJO classes with the specified * AnnotationConfigApplicationContext. @@ -322,10 +309,10 @@ public class SpringContextBootstrappingInitializer implements Declarable, Applic * @return the given AnnotationConfigApplicationContext. * @see org.springframework.context.annotation.AnnotationConfigApplicationContext#register(Class[]) */ - AnnotationConfigApplicationContext registerAnnotatedClasses(AnnotationConfigApplicationContext applicationContext, + ConfigurableApplicationContext registerAnnotatedClasses(ConfigurableApplicationContext applicationContext, Class[] annotatedClasses) { - if (!ObjectUtils.isEmpty(annotatedClasses)) { - applicationContext.register(annotatedClasses); + if (applicationContext instanceof AnnotationConfigApplicationContext && !ObjectUtils.isEmpty(annotatedClasses)) { + ((AnnotationConfigApplicationContext) applicationContext).register(annotatedClasses); } return applicationContext; @@ -341,10 +328,10 @@ public class SpringContextBootstrappingInitializer implements Declarable, Applic * @return the given AnnotationConfigApplicationContext. * @see org.springframework.context.annotation.AnnotationConfigApplicationContext#scan(String...) */ - AnnotationConfigApplicationContext scanBasePackages(AnnotationConfigApplicationContext applicationContext, + ConfigurableApplicationContext scanBasePackages(ConfigurableApplicationContext applicationContext, String[] basePackages) { - if (!ObjectUtils.isEmpty(basePackages)) { - applicationContext.scan(basePackages); + if (applicationContext instanceof AnnotationConfigApplicationContext && !ObjectUtils.isEmpty(basePackages)) { + ((AnnotationConfigApplicationContext) applicationContext).scan(basePackages); } return applicationContext; @@ -359,7 +346,7 @@ public class SpringContextBootstrappingInitializer implements Declarable, Applic * @see java.lang.ClassLoader */ ConfigurableApplicationContext setClassLoader(ConfigurableApplicationContext applicationContext) { - ClassLoader beanClassLoader = beanClassLoaderRef.get(); + ClassLoader beanClassLoader = beanClassLoaderReference.get(); if (applicationContext instanceof DefaultResourceLoader && beanClassLoader != null) { ((DefaultResourceLoader) applicationContext).setClassLoader(beanClassLoader); @@ -368,6 +355,17 @@ 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. @@ -409,7 +407,7 @@ public class SpringContextBootstrappingInitializer implements Declarable, Applic } } catch (Throwable cause) { - String message = "Failed to bootstrap the Spring ApplicationContext!"; + String message = "Failed to bootstrap the Spring ApplicationContext"; logger.error(message, cause); throw new ApplicationContextException(message, cause); } diff --git a/src/test/java/org/springframework/data/gemfire/LazyWiringDeclarableSupportFunctionBasedIntegrationTest.java b/src/test/java/org/springframework/data/gemfire/LazyWiringDeclarableSupportFunctionBasedIntegrationTest.java new file mode 100644 index 00000000..d9a5dee1 --- /dev/null +++ b/src/test/java/org/springframework/data/gemfire/LazyWiringDeclarableSupportFunctionBasedIntegrationTest.java @@ -0,0 +1,168 @@ +/* + * 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.equalTo; +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertThat; + +import java.util.Properties; + +import org.junit.Test; +import org.junit.runner.RunWith; +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.util.Assert; + +import com.gemstone.gemfire.cache.execute.Function; +import com.gemstone.gemfire.cache.execute.FunctionContext; +import com.gemstone.gemfire.management.internal.cli.util.spring.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). + * + * @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 + * @since 1.7.0 + */ +@RunWith(SpringJUnit4ClassRunner.class) +@ContextConfiguration +@SuppressWarnings("unused") +public class LazyWiringDeclarableSupportFunctionBasedIntegrationTest { + + @Autowired + private HelloFunctionExecution helloFunctionExecution; + +/* + @BeforeClass + public static void setupBeforeClass() { + Cache gemfireCache = new CacheFactory() + .set("name", LazyWiringDeclarableSupportFunctionBasedIntegrationTest.class.getSimpleName()) + .set("mcast-port", "0") + .set("log-level", "config") + .set("cache-xml-file", null) + .create(); + + assertThat(gemfireCache, is(notNullValue())); + assertThat(SpringContextBootstrappingInitializer.getApplicationContext(), is(notNullValue())); + } + + @AfterClass + public static void tearDownAfterClass() { + CacheFactory.getAnyInstance().close(); + } +*/ + + @Test + public void helloGreeting() { + assertThat(helloFunctionExecution.hello(null), is(equalTo("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!"); + this.id = id; + } + + @Override + public String getId() { + return id; + } + + @Override + public boolean hasResult() { + return true; + } + + @Override + public boolean isHA() { + return false; + } + + @Override + public boolean optimizeForWrite() { + return false; + } + } + + public static class HelloGemFireFunction extends FunctionAdaptor { + + protected static final String ADDRESS_TO_PARAMETER = "hello.address.to"; + protected static final String DEFAULT_ADDRESS_TO = "World"; + protected static final String HELLO_GREETING = "Hello %1$s!"; + protected static final String ID = "hello"; + + @Value("${hello.default.address.to}") + private String defaultAddressTo; + + private String addressTo; + + public HelloGemFireFunction() { + super(ID); + } + + protected String getAddressTo() { + return addressTo; + } + + protected String getDefaultAddressTo() { + return (StringUtils.hasText(defaultAddressTo) ? defaultAddressTo : DEFAULT_ADDRESS_TO); + } + + @Override + protected void doPostInit(final Properties parameters) { + addressTo = parameters.getProperty(ADDRESS_TO_PARAMETER, getDefaultAddressTo()); + } + + @Override + public void execute(final FunctionContext context) { + context.getResultSender().lastResult(formatHelloGreeting(addressTo(context))); + } + + // precedence is... 1. Caller 2. GemFire 3. Spring + protected String addressTo(FunctionContext context) { + Object arguments = context.getArguments(); + String addressTo = null; + + if (arguments instanceof Object[]) { + Object[] args = (Object[]) arguments; + addressTo = (args.length > 0 && args[0] != null ? String.valueOf(args[0]) : null); + } + else if (arguments != null) { + addressTo = String.valueOf(arguments); + } + + return (StringUtils.hasText(addressTo) ? addressTo : getAddressTo()); + } + + protected String formatHelloGreeting(String addressTo) { + return String.format(HELLO_GREETING, addressTo); + } + } + +} diff --git a/src/test/java/org/springframework/data/gemfire/LazyWiringDeclarableSupportTest.java b/src/test/java/org/springframework/data/gemfire/LazyWiringDeclarableSupportTest.java index 745ac22f..16bfb72e 100644 --- a/src/test/java/org/springframework/data/gemfire/LazyWiringDeclarableSupportTest.java +++ b/src/test/java/org/springframework/data/gemfire/LazyWiringDeclarableSupportTest.java @@ -16,25 +16,25 @@ package org.springframework.data.gemfire; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNotSame; -import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertTrue; +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.junit.Assert.assertThat; import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import java.util.Properties; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicReference; -import org.junit.Assert; +import org.junit.Rule; import org.junit.Test; -import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.junit.rules.ExpectedException; +import org.springframework.beans.factory.BeanFactory; import org.springframework.context.ApplicationContext; -import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.event.ContextClosedEvent; import org.springframework.context.event.ContextRefreshedEvent; import org.springframework.data.gemfire.support.SpringContextBootstrappingInitializer; @@ -46,6 +46,7 @@ import org.springframework.data.gemfire.support.SpringContextBootstrappingInitia * it's contract. * * @author John Blum + * @see org.junit.Rule * @see org.junit.Test * @see org.mockito.Mockito * @see org.springframework.data.gemfire.LazyWiringDeclarableSupport @@ -53,6 +54,15 @@ import org.springframework.data.gemfire.support.SpringContextBootstrappingInitia */ public class LazyWiringDeclarableSupportTest { + @Rule + public ExpectedException expectedException = ExpectedException.none(); + + protected 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) { Properties parameters = new Properties(); parameters.setProperty(parameter, value); @@ -60,7 +70,7 @@ public class LazyWiringDeclarableSupportTest { } @Test - public void testAssertInitialized() { + public void assertInitialized() { LazyWiringDeclarableSupport declarable = new TestLazyWiringDeclarableSupport() { @Override protected boolean isInitialized() { return true; @@ -75,25 +85,30 @@ public class LazyWiringDeclarableSupportTest { } } - @Test(expected = IllegalStateException.class) - public void testAssertInitializedWhenUninitialized() { - LazyWiringDeclarableSupport declarable = new TestLazyWiringDeclarableSupport(); + @Test + public void assertInitializedWhenUninitialized() { + LazyWiringDeclarableSupport declarable = new TestLazyWiringDeclarableSupport() { + @Override protected boolean isInitialized() { + return false; + } + }; 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", + declarable.getClass().getName())); + declarable.assertInitialized(); } - catch (IllegalStateException expected) { - assertEquals(String.format("This Declarable object (%1$s) has not been properly configured and initialized!", - TestLazyWiringDeclarableSupport.class.getName()), expected.getMessage()); - throw expected; - } finally { SpringContextBootstrappingInitializer.unregister(declarable); } } @Test - public void testAssertUninitialized() { + public void assertUninitialized() { LazyWiringDeclarableSupport declarable = new TestLazyWiringDeclarableSupport(); try { @@ -104,8 +119,8 @@ public class LazyWiringDeclarableSupportTest { } } - @Test(expected = IllegalStateException.class) - public void testAssertUninitializedWhenInitialized() { + @Test + public void assertUninitializedWhenInitialized() { LazyWiringDeclarableSupport declarable = new TestLazyWiringDeclarableSupport() { @Override protected boolean isInitialized() { return true; @@ -113,13 +128,34 @@ public class LazyWiringDeclarableSupportTest { }; 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())); + declarable.assertUninitialized(); } - catch (IllegalStateException expected) { - assertEquals(String.format( - "This Declarable object (%1$s) has already been configured and initialized, and is currently active!", - declarable.getClass().getName()), expected.getMessage()); - throw expected; + finally { + SpringContextBootstrappingInitializer.unregister(declarable); + } + } + + @Test + public void init() { + LazyWiringDeclarableSupport declarable = new TestLazyWiringDeclarableSupport(); + + try { + assertThat(declarable.isInitialized(), is(false)); + + declarable.init(createParameters("param", "value")); + + assertParameters(declarable.nullSafeGetParameters(), "param", "value"); + + declarable.init(createParameters("newParam", "newValue")); + + assertParameters(declarable.nullSafeGetParameters(), "newParam", "newValue"); + assertThat(declarable.isInitialized(), is(false)); } finally { SpringContextBootstrappingInitializer.unregister(declarable); @@ -127,63 +163,59 @@ public class LazyWiringDeclarableSupportTest { } @Test - public void testInit() { - LazyWiringDeclarableSupport declarable = new TestLazyWiringDeclarableSupport(); - - try { - assertFalse(declarable.isInitialized()); - declarable.init(createParameters("param", "value")); - declarable.init(createParameters("newParam", "newValue")); - } - finally { - SpringContextBootstrappingInitializer.unregister(declarable); - } - } - - @Test(expected = IllegalStateException.class) - public void testInitWhenInitialized() { + public void isInitialized() { LazyWiringDeclarableSupport declarable = new TestLazyWiringDeclarableSupport() { @Override protected boolean isInitialized() { return true; } }; + assertThat(declarable.isInitialized(), is(true)); + assertThat(declarable.isNotInitialized(), is(false)); + } + + @Test + public void isUninitialized() { + LazyWiringDeclarableSupport declarable = new TestLazyWiringDeclarableSupport() { + @Override protected boolean isInitialized() { + return false; + } + }; + + assertThat(declarable.isInitialized(), is(false)); + 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 { - declarable.init(createParameters("param", "value")); - } - catch (IllegalStateException expected) { - assertEquals(String.format( - "This Declarable object (%1$s) has already been configured and initialized, and is currently active!", - declarable.getClass().getName()), expected.getMessage()); - throw expected; + locator.afterPropertiesSet(); + + assertThat(new TestLazyWiringDeclarableSupport().locateBeanFactory(null), is(sameInstance(mockBeanFactory))); } finally { - SpringContextBootstrappingInitializer.unregister(declarable); + locator.destroy(); } } @Test - public void testNullSafeGetParameters() { + public void nullSafeGetParametersWithNullReference() { LazyWiringDeclarableSupport declarable = new TestLazyWiringDeclarableSupport(); try { - declarable.init(createParameters("param", "value")); + declarable.init(null); Properties parameters = declarable.nullSafeGetParameters(); - assertNotNull(parameters); - assertFalse(parameters.isEmpty()); - assertEquals(1, parameters.size()); - assertEquals("value", parameters.getProperty("param")); - - declarable.init(createParameters("newParam", "newValue")); - parameters = declarable.nullSafeGetParameters(); - - assertNotNull(parameters); - assertFalse(parameters.isEmpty()); - assertEquals(1, parameters.size()); - assertFalse(parameters.containsKey("param")); - assertEquals("newValue", parameters.getProperty("newParam")); + assertThat(parameters, is(notNullValue())); + assertThat(parameters.isEmpty(), is(true)); } finally { SpringContextBootstrappingInitializer.unregister(declarable); @@ -191,49 +223,8 @@ public class LazyWiringDeclarableSupportTest { } @Test - public void testNullSafeGetParametersWithNullReference() { - LazyWiringDeclarableSupport declarable = new TestLazyWiringDeclarableSupport(); - - try { - Properties parameters = declarable.nullSafeGetParameters(); - - assertNotNull(parameters); - assertTrue(parameters.isEmpty()); - } - finally { - SpringContextBootstrappingInitializer.unregister(declarable); - } - } - - @Test(expected = IllegalArgumentException.class) - public void testOnApplicationEventWithNonConfigurableApplicationContext() { - ApplicationContext mockApplicationContext = mock(ApplicationContext.class, - "testOnApplicationEventWithNonConfigurableApplicationContext"); - - LazyWiringDeclarableSupport declarable = new TestLazyWiringDeclarableSupport(); - - try { - declarable.onApplicationEvent(new ContextRefreshedEvent(mockApplicationContext)); - } - catch (IllegalArgumentException expected) { - assertEquals(String.format("The Spring ApplicationContext (%1$s) must be an instance of ConfigurableApplicationContext.", - mockApplicationContext.getClass().getName()), expected.getMessage()); - throw expected; - } - finally { - SpringContextBootstrappingInitializer.unregister(declarable); - } - } - - @Test - public void testOnApplicationEventAndDoPostInit() { - ConfigurableApplicationContext mockApplicationContext = mock(ConfigurableApplicationContext.class, - "testOnApplicationEventAndDoPostInit.ApplicationContext"); - - ConfigurableListableBeanFactory mockBeanFactory = mock(ConfigurableListableBeanFactory.class, - "testOnApplicationEventAndDoPostInit.BeanFactory"); - - when(mockApplicationContext.getBeanFactory()).thenReturn(mockBeanFactory); + public void onApplicationEvent() { + ApplicationContext mockApplicationContext = mock(ApplicationContext.class, "MockApplicationContext"); final AtomicBoolean doPostInitCalled = new AtomicBoolean(false); @@ -241,6 +232,7 @@ public class LazyWiringDeclarableSupportTest { @Override protected void doPostInit(final Properties parameters) { super.doPostInit(parameters); assertInitialized(); + LazyWiringDeclarableSupportTest.assertParameters(parameters, "param", "value"); doPostInitCalled.set(true); } }; @@ -250,12 +242,11 @@ public class LazyWiringDeclarableSupportTest { try { declarable.init(parameters); declarable.onApplicationEvent(new ContextRefreshedEvent(mockApplicationContext)); - declarable.assertEquals(parameters); - declarable.assertSame(mockBeanFactory); + declarable.assertBeanFactory(mockApplicationContext); + declarable.assertParameters(parameters); - assertTrue(doPostInitCalled.get()); - - verify(mockApplicationContext, times(1)).getBeanFactory(); + assertThat(declarable.isInitialized(), is(true)); + assertThat(doPostInitCalled.get(), is(true)); } finally { SpringContextBootstrappingInitializer.unregister(declarable); @@ -263,14 +254,32 @@ public class LazyWiringDeclarableSupportTest { } @Test - public void testFullLifecycleIntegrationWithDestroy() throws Exception { - ConfigurableApplicationContext mockApplicationContext = mock(ConfigurableApplicationContext.class, - "testFullLifecycleIntegrationWithDestroy.ApplicationContext"); + public void onApplicationEventWithNullApplicationContext() throws Throwable { + LazyWiringDeclarableSupport declarable = new TestLazyWiringDeclarableSupport(); - ConfigurableListableBeanFactory mockBeanFactory = mock(ConfigurableListableBeanFactory.class, - "testFullLifecycleIntegrationWithDestroy.BeanFactory"); + try { + ContextRefreshedEvent mockContextRefreshedEvent = mock(ContextRefreshedEvent.class, "MockContextRefreshedEvent"); - when(mockApplicationContext.getBeanFactory()).thenReturn(mockBeanFactory); + when(mockContextRefreshedEvent.getApplicationContext()).thenReturn(null); + + expectedException.expect(IllegalArgumentException.class); + expectedException.expectCause(is(nullValue(Throwable.class))); + expectedException.expectMessage("The Spring ApplicationContext must not be null"); + + declarable.onApplicationEvent(mockContextRefreshedEvent); + } + catch (Throwable t) { + assertThat(declarable.isInitialized(), is(false)); + throw t; + } + finally { + SpringContextBootstrappingInitializer.unregister(declarable); + } + } + + @Test + public void fullLifecycleOnApplicationEventToDestroy() throws Exception { + ApplicationContext mockApplicationContext = mock(ApplicationContext.class, "MockApplicationContext"); final AtomicBoolean doPostInitCalled = new AtomicBoolean(false); @@ -278,6 +287,7 @@ public class LazyWiringDeclarableSupportTest { @Override protected void doPostInit(final Properties parameters) { super.doPostInit(parameters); assertInitialized(); + LazyWiringDeclarableSupportTest.assertParameters(parameters, "param", "value"); doPostInitCalled.set(true); } }; @@ -289,52 +299,123 @@ public class LazyWiringDeclarableSupportTest { try { declarable.init(parameters); - assertFalse(declarable.isInitialized()); - assertFalse(doPostInitCalled.get()); - assertSame(parameters, declarable.nullSafeGetParameters()); + assertThat(declarable.isInitialized(), is(false)); + assertThat(declarable.nullSafeGetParameters(), is(sameInstance(parameters))); + assertThat(doPostInitCalled.get(), is(false)); initializer.onApplicationEvent(new ContextRefreshedEvent(mockApplicationContext)); - assertTrue(declarable.isInitialized()); - assertTrue(doPostInitCalled.get()); - declarable.assertEquals(parameters); - declarable.assertSame(mockBeanFactory); + assertThat(declarable.isInitialized(), is(true)); + assertThat(doPostInitCalled.get(), is(true)); + declarable.assertBeanFactory(mockApplicationContext); + declarable.assertParameters(parameters); - declarable.destroy(); doPostInitCalled.set(false); + declarable.destroy(); - assertFalse(declarable.isInitialized()); - assertFalse(doPostInitCalled.get()); - assertNotSame(parameters, declarable.nullSafeGetParameters()); + assertThat(declarable.isInitialized(), is(false)); + assertThat(declarable.nullSafeGetParameters(), is(not(sameInstance(parameters)))); + assertThat(doPostInitCalled.get(), is(false)); initializer.onApplicationEvent(new ContextRefreshedEvent(mockApplicationContext)); - assertFalse(declarable.isInitialized()); - assertFalse(doPostInitCalled.get()); + assertThat(declarable.isInitialized(), is(false)); + assertThat(declarable.nullSafeGetParameters(), is(not(sameInstance(parameters)))); + assertThat(doPostInitCalled.get(), is(false)); } finally { initializer.onApplicationEvent(new ContextClosedEvent(mockApplicationContext)); } } + @Test + public void initThenOnApplicationEventThenInitWhenInitialized() { + ApplicationContext mockApplicationContext = mock(ApplicationContext.class, "MockApplicationContext"); + + BeanFactory mockBeanFactory = mock(BeanFactory.class, "MockBeanFactory"); + + GemfireBeanFactoryLocator locator = new GemfireBeanFactoryLocator(); + locator.setBeanName("MockBeanFactory"); + locator.setBeanFactory(mockBeanFactory); + + final AtomicBoolean doPostInitCalled = new AtomicBoolean(false); + 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()); + doPostInitCalled.set(true); + } + }; + + Properties parameters = createParameters("testParam", "testValue"); + + try { + locator.afterPropertiesSet(); + + assertThat(declarable.isInitialized(), is(false)); + assertThat(declarable.nullSafeGetParameters(), is(not(sameInstance(parameters)))); + assertThat(doPostInitCalled.get(), is(false)); + + declarable.init(parameters); + declarable.assertBeanFactory(mockBeanFactory); + declarable.assertParameters(parameters); + + assertThat(declarable.isInitialized(), is(true)); + assertThat(declarable.nullSafeGetParameters(), is(sameInstance(parameters))); + assertThat(doPostInitCalled.get(), is(true)); + + doPostInitCalled.set(false); + declarable.onApplicationEvent(new ContextRefreshedEvent(mockApplicationContext)); + declarable.assertBeanFactory(mockBeanFactory); + declarable.assertParameters(parameters); + + assertThat(declarable.isInitialized(), is(true)); + assertThat(declarable.nullSafeGetParameters(), is(sameInstance(parameters))); + assertThat(doPostInitCalled.get(), is(true)); + + doPostInitCalled.set(false); + expectedKey.set("mockKey"); + expectedValue.set("mockValue"); + parameters = createParameters("mockKey", "mockValue"); + + declarable.init(parameters); + declarable.assertBeanFactory(mockBeanFactory); + declarable.assertParameters(parameters); + + assertThat(declarable.isInitialized(), is(true)); + assertThat(declarable.nullSafeGetParameters(), is(sameInstance(parameters))); + assertThat(doPostInitCalled.get(), is(true)); + } + finally { + locator.destroy(); + } + } + protected static class TestLazyWiringDeclarableSupport extends LazyWiringDeclarableSupport { - private ConfigurableListableBeanFactory actualBeanFactory; + private BeanFactory actualBeanFactory; private Properties actualParameters; - protected void assertEquals(final Properties expectedParameters) { - Assert.assertEquals(expectedParameters, actualParameters); + protected void assertBeanFactory(final BeanFactory expectedBeanFactory) { + assertThat(actualBeanFactory, is(sameInstance(expectedBeanFactory))); } - protected void assertSame(final ConfigurableListableBeanFactory expectedBeanFactory) { - Assert.assertSame(expectedBeanFactory, actualBeanFactory); + protected void assertParameters(final Properties expectedParameters) { + assertThat(actualParameters, is(equalTo(expectedParameters))); } @Override - void doInit(final ConfigurableListableBeanFactory beanFactory, final Properties parameters) { - this.actualBeanFactory = beanFactory; + void doInit(final BeanFactory beanFactory, final Properties parameters) { + if (!isInitialized()) { + this.actualBeanFactory = beanFactory; + initialized = true; + } + this.actualParameters = parameters; - initialized = true; doPostInit(parameters); } } diff --git a/src/test/java/org/springframework/data/gemfire/function/sample/HelloFunctionExecution.java b/src/test/java/org/springframework/data/gemfire/function/sample/HelloFunctionExecution.java new file mode 100644 index 00000000..7dfd5aa2 --- /dev/null +++ b/src/test/java/org/springframework/data/gemfire/function/sample/HelloFunctionExecution.java @@ -0,0 +1,35 @@ +/* + * 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.function.sample; + +import org.springframework.data.gemfire.function.annotation.OnMember; + +/** + * The HelloFunctionExecution interface is a Spring Data GemFire Function Execution interface + * for the 'hello' GemFire Function and hello greetings. + * + * @author John Blum + * @see org.springframework.data.gemfire.function.annotation.OnMember + * @since 1.7.0 + */ +@OnMember(groups = "HelloGroup") +@SuppressWarnings("unused") +public interface HelloFunctionExecution { + + String hello(String addressTo); + +} 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 af86f627..3934eeb3 100644 --- a/src/test/java/org/springframework/data/gemfire/support/SpringContextBootstrappingInitializerTest.java +++ b/src/test/java/org/springframework/data/gemfire/support/SpringContextBootstrappingInitializerTest.java @@ -16,10 +16,17 @@ package org.springframework.data.gemfire.support; +import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.isA; +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.hamcrest.CoreMatchers.nullValue; +import static org.hamcrest.CoreMatchers.sameInstance; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.any; import static org.mockito.Matchers.argThat; @@ -37,8 +44,9 @@ import java.util.Properties; import org.apache.commons.logging.Log; import org.junit.After; -import org.junit.Assert; +import org.junit.Rule; import org.junit.Test; +import org.junit.rules.ExpectedException; import org.mockito.ArgumentMatcher; import org.mockito.Matchers; import org.springframework.context.ApplicationContext; @@ -47,6 +55,7 @@ import org.springframework.context.ApplicationListener; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.Configuration; +import org.springframework.context.event.ApplicationContextEvent; import org.springframework.context.event.ContextClosedEvent; import org.springframework.context.event.ContextRefreshedEvent; import org.springframework.context.event.ContextStartedEvent; @@ -72,6 +81,9 @@ import org.springframework.util.ObjectUtils; @SuppressWarnings("unused") public class SpringContextBootstrappingInitializerTest { + @Rule + public ExpectedException expectedException = ExpectedException.none(); + @After public void tearDown() { SpringContextBootstrappingInitializer.applicationContext = null; @@ -93,37 +105,35 @@ public class SpringContextBootstrappingInitializerTest { } @Test - public void testGetApplicationContext() { + public void getInitializedApplicationContext() { ConfigurableApplicationContext mockApplicationContext = mock(ConfigurableApplicationContext.class, "testGetApplicationContext"); SpringContextBootstrappingInitializer.applicationContext = mockApplicationContext; - assertSame(mockApplicationContext, SpringContextBootstrappingInitializer.getApplicationContext()); - } - - @Test(expected = IllegalStateException.class) - public void testGetApplicationContextUninitialized() { - try { - SpringContextBootstrappingInitializer.getApplicationContext(); - } - catch (IllegalStateException expected) { - assertEquals("The Spring ApplicationContext was not configured and initialized properly!", - expected.getMessage()); - throw expected; - } + assertThat(SpringContextBootstrappingInitializer.getApplicationContext(), + is(sameInstance(mockApplicationContext))); } @Test - public void testSetBeanClassLoader() { - assertNull(SpringContextBootstrappingInitializer.applicationContext); + public void getUninitializedApplicationContext() { + expectedException.expect(IllegalStateException.class); + expectedException.expectMessage("The Spring ApplicationContext was not configured and initialized properly!"); + expectedException.expectCause(is(nullValue(Throwable.class))); + + SpringContextBootstrappingInitializer.getApplicationContext(); + } + + @Test + public void setBeanClassLoaderWithCurrentThreadContextClassLoader() { + assertThat(SpringContextBootstrappingInitializer.applicationContext, is(nullValue())); SpringContextBootstrappingInitializer.setBeanClassLoader(Thread.currentThread().getContextClassLoader()); } @Test - public void testSetBeanClassLoaderWhenApplicationContextIsInactive() { + public void setBeanClassLoaderWithCurrentThreadContextClassLoaderWhenApplicationContextIsInactive() { ConfigurableApplicationContext mockApplicationContext = mock(ConfigurableApplicationContext.class, - "testSetBeanClassLoaderWhenApplicationContextIsInactive.MockApplicationContext"); + "MockApplicationContext"); when(mockApplicationContext.isActive()).thenReturn(false); @@ -133,42 +143,71 @@ public class SpringContextBootstrappingInitializerTest { verify(mockApplicationContext, times(1)).isActive(); } - @Test(expected = IllegalStateException.class) - public void testSetBeanClassLoaderWhenApplicationContextIsActive() { + @Test + public void setBeanClassLoaderWithCurrentThreadContextClassLoaderWhenApplicationContextIsActive() { ConfigurableApplicationContext mockApplicationContext = mock(ConfigurableApplicationContext.class, - "testSetBeanClassLoaderWhenApplicationContextIsActive.MockApplicationContext"); + "MockApplicationContext"); when(mockApplicationContext.isActive()).thenReturn(true); + expectedException.expect(IllegalStateException.class); + expectedException.expectCause(is(nullValue(Throwable.class))); + expectedException.expectMessage("The Spring ApplicationContext has already been initialized!"); + try { SpringContextBootstrappingInitializer.applicationContext = mockApplicationContext; SpringContextBootstrappingInitializer.setBeanClassLoader(Thread.currentThread().getContextClassLoader()); } - catch (IllegalStateException expected) { - assertEquals("The Spring ApplicationContext has already been initialized!", expected.getMessage()); - throw expected; - } - } - - @Test(expected = IllegalArgumentException.class) - public void testCreateApplicationContextWhenBasePackagesAndConfigLocationsAreUnspecified() { - try { - new SpringContextBootstrappingInitializer().createApplicationContext(null, null); - } - catch (IllegalArgumentException expected) { - assertEquals("'basePackages', 'configLocations' or 'AnnotatedClasses' must be specified in order to" - + " construct and configure an instance of the ConfigurableApplicationContext", expected.getMessage()); - throw expected; + finally { + verify(mockApplicationContext, times(1)).isActive(); } } @Test - public void testCreateAnnotationApplicationContext() { - final ConfigurableApplicationContext mockXmlApplicationContext = mock(ConfigurableApplicationContext.class, - "testCreateAnnotationApplicationContext.MockXmlApplicationContext"); + public void createApplicationContextWhenAnnotatedClassesBasePackagesAndConfigLocationsAreUnspecified() { + expectedException.expect(IllegalArgumentException.class); + expectedException.expectCause(is(nullValue(Throwable.class))); + expectedException.expectMessage("'AnnotatedClasses', 'basePackages' or 'configLocations' must be specified" + + " in order to construct and configure an instance of the ConfigurableApplicationContext"); + new SpringContextBootstrappingInitializer().createApplicationContext(null, null); + } + + @Test + public void createAnnotationApplicationContextWithAnnotatedClasses() { final AnnotationConfigApplicationContext mockAnnotationApplicationContext = mock(AnnotationConfigApplicationContext.class, - "testCreateAnnotationApplicationContext.MockAnnotationApplicationContext"); + "MockAnnotationApplicationContext"); + + final ConfigurableApplicationContext mockXmlApplicationContext = mock(ConfigurableApplicationContext.class, + "MockXmlApplicationContext"); + + Class[] annotatedClasses = { TestAppConfigOne.class, TestAppConfigTwo.class }; + + SpringContextBootstrappingInitializer.register(annotatedClasses[0]); + SpringContextBootstrappingInitializer.register(annotatedClasses[1]); + + SpringContextBootstrappingInitializer initializer = new SpringContextBootstrappingInitializer() { + @Override ConfigurableApplicationContext createApplicationContext(final String[] configLocations) { + return (ObjectUtils.isEmpty(configLocations) ? mockAnnotationApplicationContext + : mockXmlApplicationContext); + } + }; + + ConfigurableApplicationContext actualApplicationContext = initializer.createApplicationContext(null, null); + + assertThat(actualApplicationContext, + is(sameInstance((ConfigurableApplicationContext) mockAnnotationApplicationContext))); + + verify(mockAnnotationApplicationContext, times(1)).register(annotatedClasses[0], annotatedClasses[1]); + } + + @Test + public void createAnnotationApplicationContextWithBasePackages() { + final AnnotationConfigApplicationContext mockAnnotationApplicationContext = mock(AnnotationConfigApplicationContext.class, + "MockAnnotationApplicationContext"); + + final ConfigurableApplicationContext mockXmlApplicationContext = mock(ConfigurableApplicationContext.class, + "MockXmlApplicationContext"); String[] basePackages = { "org.example.app" }; @@ -181,18 +220,19 @@ public class SpringContextBootstrappingInitializerTest { ConfigurableApplicationContext actualApplicationContext = initializer.createApplicationContext(basePackages, null); - assertSame(mockAnnotationApplicationContext, actualApplicationContext); + assertThat(actualApplicationContext, + is(sameInstance((ConfigurableApplicationContext) mockAnnotationApplicationContext))); - verify(mockAnnotationApplicationContext, times(1)).scan(eq("org.example.app")); + verify(mockAnnotationApplicationContext, times(1)).scan(eq(basePackages[0])); } @Test - public void testCreateXmlApplicationContext() { - final ConfigurableApplicationContext mockXmlApplicationContext = mock(ConfigurableApplicationContext.class, - "testCreateXmlApplicationContext.MockXmlApplicationContext"); - + public void createXmlApplicationContext() { final ConfigurableApplicationContext mockAnnotationApplicationContext = mock(ConfigurableApplicationContext.class, - "testCreateXmlApplicationContext.MockAnnotationApplicationContext"); + "MockAnnotationApplicationContext"); + + final ConfigurableApplicationContext mockXmlApplicationContext = mock(ConfigurableApplicationContext.class, + "MockXmlApplicationContext"); SpringContextBootstrappingInitializer initializer = new SpringContextBootstrappingInitializer() { @Override ConfigurableApplicationContext createApplicationContext(final String[] configLocations) { @@ -204,137 +244,155 @@ public class SpringContextBootstrappingInitializerTest { ConfigurableApplicationContext actualApplicationContext = initializer.createApplicationContext(null, new String[] { "/path/to/application/context.xml" }); - assertSame(mockXmlApplicationContext, actualApplicationContext); + assertThat(actualApplicationContext, is(sameInstance(mockXmlApplicationContext))); } @Test - public void testInitApplicationContext() { + public void initApplicationContext() { AbstractApplicationContext mockApplicationContext = mock(AbstractApplicationContext.class, - "testInitApplicationContext.MockApplicationContext"); + "MockApplicationContext"); SpringContextBootstrappingInitializer.setBeanClassLoader(Thread.currentThread().getContextClassLoader()); SpringContextBootstrappingInitializer initializer = new SpringContextBootstrappingInitializer(); - initializer.initApplicationContext(mockApplicationContext); + assertSame(mockApplicationContext, initializer.initApplicationContext(mockApplicationContext)); verify(mockApplicationContext, times(1)).addApplicationListener(same(initializer)); verify(mockApplicationContext, times(1)).registerShutdownHook(); verify(mockApplicationContext, times(1)).setClassLoader(eq(Thread.currentThread().getContextClassLoader())); } - @Test(expected = IllegalArgumentException.class) - public void testInitApplicationContextWithNull() { - try { - new SpringContextBootstrappingInitializer().initApplicationContext(null); - } - catch (IllegalArgumentException expected) { - assertEquals("The ConfigurableApplicationContext reference must not be null!", expected.getMessage()); - throw expected; - } + @Test + public void initApplicationContextWithNull() { + expectedException.expect(IllegalArgumentException.class); + expectedException.expectCause(is(nullValue(Throwable.class))); + expectedException.expectMessage("The ConfigurableApplicationContext reference must not be null"); + + new SpringContextBootstrappingInitializer().initApplicationContext(null); } @Test - public void testRefreshApplicationContext() { + public void refreshApplicationContext() { ConfigurableApplicationContext mockApplicationContext = mock(ConfigurableApplicationContext.class, - "testRefreshApplicationContext"); + "MockApplicationContext"); - new SpringContextBootstrappingInitializer().refreshApplicationContext(mockApplicationContext); + assertThat(new SpringContextBootstrappingInitializer().refreshApplicationContext(mockApplicationContext), + is(sameInstance(mockApplicationContext))); verify(mockApplicationContext, times(1)).refresh(); } - @Test(expected = IllegalArgumentException.class) - public void testRefreshApplicationContextWithNull() { - try { - new SpringContextBootstrappingInitializer().refreshApplicationContext(null); - } - catch (IllegalArgumentException expected) { - assertEquals("The ConfigurableApplicationContext reference must not be null!", expected.getMessage()); - throw expected; - } + @Test + public void refreshApplicationContextWithNull() { + expectedException.expect(IllegalArgumentException.class); + expectedException.expectCause(is(nullValue(Throwable.class))); + expectedException.expectMessage("The ConfigurableApplicationContext reference must not be null"); + + new SpringContextBootstrappingInitializer().refreshApplicationContext(null); } @Test - public void testNullSafeGetApplicationContextIdWithNullReference() { - assertNull(new SpringContextBootstrappingInitializer().nullSafeGetApplicationContextId(null)); - } - - @Test - public void testNullSafeGetApplicationContextIdWithNonNullReference() { - ApplicationContext mockApplicationContext = mock(ApplicationContext.class, - "testNullSafeGetApplicationContextIdWithNonNullReference"); - - when(mockApplicationContext.getId()).thenReturn("testNullSafeGetApplicationContextIdWithNonNullReference"); - - assertEquals("testNullSafeGetApplicationContextIdWithNonNullReference", - new SpringContextBootstrappingInitializer().nullSafeGetApplicationContextId(mockApplicationContext)); - } - - @Test - public void testRegisterAnnotatedClasses() { + public void registerAnnotatedClasses() { AnnotationConfigApplicationContext mockApplicationContext = mock(AnnotationConfigApplicationContext.class, - "testRegisterAnnotatedClasses"); + "MockApplicationContext"); Class[] annotatedClasses = { TestAppConfigOne.class, TestAppConfigTwo.class }; - new SpringContextBootstrappingInitializer().registerAnnotatedClasses(mockApplicationContext, annotatedClasses); + assertThat(new SpringContextBootstrappingInitializer() + .registerAnnotatedClasses(mockApplicationContext, annotatedClasses), + is(sameInstance((ConfigurableApplicationContext) mockApplicationContext))); verify(mockApplicationContext, times(1)).register(annotatedClasses); } @Test - public void testRegisterAnnotatedClassesWithEmptyAnnotatedClassesArray() { + public void registerAnnotatedClassesWithEmptyAnnotatedClassesArray() { AnnotationConfigApplicationContext mockApplicationContext = mock(AnnotationConfigApplicationContext.class, - "testRegisterAnnotatedClassesWithEmptyAnnotatedClassesArray"); + "MockApplicationContext"); - new SpringContextBootstrappingInitializer().registerAnnotatedClasses(mockApplicationContext, new Class[0]); + assertThat(new SpringContextBootstrappingInitializer().registerAnnotatedClasses(mockApplicationContext, + new Class[0]), + is(sameInstance((ConfigurableApplicationContext) mockApplicationContext))); - verify(mockApplicationContext, never()).register(any(Class.class)); + verify(mockApplicationContext, never()).register(any(Class[].class)); } @Test - public void testScanBasePackages() { + public void registerAnnotatedClassesWithNonAnnotationBasedApplicationContext() { + ConfigurableApplicationContext mockApplicationContext = mock(ConfigurableApplicationContext.class, + "MockApplicationContext"); + + assertThat(new SpringContextBootstrappingInitializer().registerAnnotatedClasses(mockApplicationContext, + new Class[] { TestAppConfigOne.class }), is(sameInstance(mockApplicationContext))); + } + + @Test + public void scanBasePackages() { AnnotationConfigApplicationContext mockApplicationContext = mock(AnnotationConfigApplicationContext.class, - "testScanBasePackages"); + "MockApplicationContext"); String[] basePackages = { "org.example.app", "org.example.plugins" }; - new SpringContextBootstrappingInitializer().scanBasePackages(mockApplicationContext, basePackages); + assertThat(new SpringContextBootstrappingInitializer().scanBasePackages(mockApplicationContext, basePackages), + is(sameInstance((ConfigurableApplicationContext) mockApplicationContext))); verify(mockApplicationContext, times(1)).scan(basePackages); } @Test - public void testScanBasePackagesWithEmptyBasePackagesArray() { + public void scanBasePackagesWithEmptyBasePackagesArray() { AnnotationConfigApplicationContext mockApplicationContext = mock(AnnotationConfigApplicationContext.class, - "testScanBasePackages"); + "MockApplicationContext"); - new SpringContextBootstrappingInitializer().scanBasePackages(mockApplicationContext, null); + assertThat(new SpringContextBootstrappingInitializer().scanBasePackages(mockApplicationContext, null), + is(sameInstance((ConfigurableApplicationContext) mockApplicationContext))); verify(mockApplicationContext, never()).scan(any(String[].class)); } @Test - public void testSetClassLoader() { + public void scanBasePackagesWithNonAnnotationBasedApplicationContext() { + ConfigurableApplicationContext mockApplicationContext = mock(ConfigurableApplicationContext.class, + "MockApplicationContext"); + + assertThat(new SpringContextBootstrappingInitializer().scanBasePackages(mockApplicationContext, + new String[] { "org.example.app" }), is(sameInstance(mockApplicationContext))); + } + + @Test + public void setClassLoader() { AbstractApplicationContext mockApplicationContext = mock(AbstractApplicationContext.class, - "testSetClassLoader.MockApplicationContext"); + "MockApplicationContext"); SpringContextBootstrappingInitializer.setBeanClassLoader(Thread.currentThread().getContextClassLoader()); - new SpringContextBootstrappingInitializer().setClassLoader(mockApplicationContext); + assertThat(new SpringContextBootstrappingInitializer().setClassLoader(mockApplicationContext), + is(sameInstance((ConfigurableApplicationContext) mockApplicationContext))); verify(mockApplicationContext, times(1)).setClassLoader(eq(Thread.currentThread().getContextClassLoader())); } @Test - public void testSetClassLoaderWhenClassLoaderIsNull() { + public void setClassLoaderWithNonSettableClassLoaderApplicationContext() { + ConfigurableApplicationContext mockApplicationContext = mock(ConfigurableApplicationContext.class, + "MockApplicationContext"); + + SpringContextBootstrappingInitializer.setBeanClassLoader(Thread.currentThread().getContextClassLoader()); + + assertThat(new SpringContextBootstrappingInitializer().setClassLoader(mockApplicationContext), + is(sameInstance(mockApplicationContext))); + } + + @Test + public void setClassLoaderWithNullClassLoader() { AbstractApplicationContext mockApplicationContext = mock(AbstractApplicationContext.class, - "testSetClassLoaderWhenClassLoaderIsNull.MockApplicationContext"); + "MockApplicationContext"); SpringContextBootstrappingInitializer.setBeanClassLoader(null); - new SpringContextBootstrappingInitializer().setClassLoader(mockApplicationContext); + assertThat(new SpringContextBootstrappingInitializer().setClassLoader(mockApplicationContext), + is(sameInstance((ConfigurableApplicationContext) mockApplicationContext))); verify(mockApplicationContext, never()).setClassLoader(any(ClassLoader.class)); } @@ -342,12 +400,27 @@ public class SpringContextBootstrappingInitializerTest { private Class[] annotatedClasses(final Class... annotatedClasses) { return argThat(new ArgumentMatcher[]>() { @Override public boolean matches(final Object argument) { - assertTrue(argument instanceof Class[]); + assertThat(argument instanceof Class[], is(true)); return Arrays.equals(annotatedClasses, (Class[]) argument); } }); } + @Test + public void nullSafeGetApplicationContextIdWithNullReference() { + assertThat(new SpringContextBootstrappingInitializer().nullSafeGetApplicationContextId(null), is(nullValue())); + } + + @Test + public void nullSafeGetApplicationContextIdWithNonNullReference() { + ApplicationContext mockApplicationContext = mock(ApplicationContext.class, "MockApplicationContext"); + + when(mockApplicationContext.getId()).thenReturn("123"); + + assertThat(new SpringContextBootstrappingInitializer().nullSafeGetApplicationContextId(mockApplicationContext), + is(equalTo("123"))); + } + @Test public void testInitWithAnnotatedClasses() { final AnnotationConfigApplicationContext mockApplicationContext = mock(AnnotationConfigApplicationContext.class, @@ -471,23 +544,17 @@ public class SpringContextBootstrappingInitializerTest { assertSame(mockNewApplicationContext, SpringContextBootstrappingInitializer.getApplicationContext()); } - @Test(expected = IllegalArgumentException.class) + @Test public void testInitWhenBasePackagesAndContextConfigLocationsParametersAreUnspecified() throws Throwable { - assertNull(SpringContextBootstrappingInitializer.applicationContext); + assertThat(SpringContextBootstrappingInitializer.applicationContext, is(nullValue())); - try { - new SpringContextBootstrappingInitializer().init(createParameters(createParameters( + expectedException.expect(ApplicationContextException.class); + expectedException.expectCause(isA(IllegalArgumentException.class)); + expectedException.expectMessage(containsString("Failed to bootstrap the Spring ApplicationContext")); + + new SpringContextBootstrappingInitializer().init(createParameters(createParameters( SpringContextBootstrappingInitializer.CONTEXT_CONFIG_LOCATIONS_PARAMETER, ""), - SpringContextBootstrappingInitializer.BASE_PACKAGES_PARAMETER, " ")); - } - catch (ApplicationContextException expected) { - assertTrue(expected.getMessage().contains("Failed to bootstrap the Spring ApplicationContext!")); - assertTrue(expected.getCause() instanceof IllegalArgumentException); - assertEquals("'basePackages', 'configLocations' or 'AnnotatedClasses' must be specified" - + " in order to construct and configure an instance of the ConfigurableApplicationContext", - expected.getCause().getMessage()); - throw expected.getCause(); - } + SpringContextBootstrappingInitializer.BASE_PACKAGES_PARAMETER, " ")); } @Test(expected = IllegalStateException.class) @@ -515,7 +582,7 @@ public class SpringContextBootstrappingInitializerTest { SpringContextBootstrappingInitializer.getApplicationContext(); } catch (ApplicationContextException expected) { - assertTrue(expected.getMessage().contains("Failed to bootstrap the Spring ApplicationContext!")); + assertTrue(expected.getMessage().contains("Failed to bootstrap the Spring ApplicationContext")); assertTrue(expected.getCause() instanceof IllegalStateException); assertEquals("The Spring ApplicationContext (testInitWhenApplicationContextIsNotRunning) failed to be properly initialized with the context config files ([]) or base packages ([org.example.app, org.example.plugins])!", expected.getCause().getMessage()); @@ -550,63 +617,48 @@ public class SpringContextBootstrappingInitializerTest { "classpath/to/spring/application/context.xml")); } catch (ApplicationContextException expected) { - assertTrue(expected.getMessage().contains("Failed to bootstrap the Spring ApplicationContext!")); + assertTrue(expected.getMessage().contains("Failed to bootstrap the Spring ApplicationContext")); assertTrue(expected.getCause() instanceof IllegalStateException); assertEquals("TEST", expected.getCause().getMessage()); throw expected.getCause(); } finally { - verify(mockLog, times(1)).error(eq("Failed to bootstrap the Spring ApplicationContext!"), + verify(mockLog, times(1)).error(eq("Failed to bootstrap the Spring ApplicationContext"), any(RuntimeException.class)); } } - protected static void assertNotified(TestApplicationListener listener, ContextRefreshedEvent expectedEvent) { - assertTrue(listener.isNotified()); - Assert.assertSame(expectedEvent, listener.getActualEvent()); + protected static void assertNotified(TestApplicationListener listener, ApplicationContextEvent expectedEvent) { + assertThat(listener, is(notNullValue())); + assertThat(listener.isNotified(), is(true)); + assertThat(listener.getActualEvent(), is(sameInstance(expectedEvent))); } protected static void assertUnnotified(TestApplicationListener listener) { - assertFalse(listener.isNotified()); - assertNull(listener.getActualEvent()); + assertThat(listener, is(notNullValue())); + assertThat(listener.isNotified(), is(false)); + assertThat(listener.getActualEvent(), is(nullValue())); } @Test - public void testOnApplicationEvent() { - TestApplicationListener testApplicationListener = new TestApplicationListener("testOnApplicationEvent"); - - try { - testApplicationListener = SpringContextBootstrappingInitializer.register(testApplicationListener); - - assertUnnotified(testApplicationListener); - - ContextRefreshedEvent testContextRefreshedEvent = new ContextRefreshedEvent(mock(ApplicationContext.class, - "testOnApplicationEvent")); - - new SpringContextBootstrappingInitializer().onApplicationEvent(testContextRefreshedEvent); - - assertNotified(testApplicationListener, testContextRefreshedEvent); - } - finally { - SpringContextBootstrappingInitializer.unregister(testApplicationListener); - } - } - - @Test - public void testOnApplicationEventWithContextStartedEvent() { + public void onContextClosedApplicationEvent() { TestApplicationListener testApplicationListener = new TestApplicationListener( - "testOnApplicationEventWithContextStartedEvent"); + "testOnContextClosedApplicationEvent"); try { testApplicationListener = SpringContextBootstrappingInitializer.register(testApplicationListener); assertUnnotified(testApplicationListener); - ContextStartedEvent testContextStartedEvent = mock(ContextStartedEvent.class, - "testOnApplicationEventWithContextStartedEvent"); + SpringContextBootstrappingInitializer.contextRefreshedEvent = mock(ContextRefreshedEvent.class, + "MockContextRefreshedEvent"); - new SpringContextBootstrappingInitializer().onApplicationEvent(testContextStartedEvent); + assertThat(SpringContextBootstrappingInitializer.contextRefreshedEvent, isA(ContextRefreshedEvent.class)); + new SpringContextBootstrappingInitializer().onApplicationEvent(mock(ContextClosedEvent.class, + "MockContextClosedEvent")); + + assertThat(SpringContextBootstrappingInitializer.contextRefreshedEvent, is(nullValue())); assertUnnotified(testApplicationListener); } finally { @@ -615,33 +667,108 @@ public class SpringContextBootstrappingInitializerTest { } @Test - public void testOnApplicationEventWithMultipleRegisteredApplicationListeners() { - TestApplicationListener testApplicationListenerOne = new TestApplicationListener( - "testOnApplicationEventWithMultipleRegisteredApplicationListeners.1"); + public void onContextRefreshedApplicationEvent() { + TestApplicationListener testApplicationListener = new TestApplicationListener( + "testOnContextRefreshedApplicationEvent"); - TestApplicationListener testApplicationListenerTwo = new TestApplicationListener( - "testOnApplicationEventWithMultipleRegisteredApplicationListeners.2"); + try { + testApplicationListener = SpringContextBootstrappingInitializer.register(testApplicationListener); - TestApplicationListener testApplicationListenerThree = new TestApplicationListener( - "testOnApplicationEventWithMultipleRegisteredApplicationListeners.3"); + assertThat(SpringContextBootstrappingInitializer.contextRefreshedEvent, is(nullValue())); + assertUnnotified(testApplicationListener); + + ContextRefreshedEvent mockContextRefreshedEvent = mock(ContextRefreshedEvent.class, + "MockContextRefreshedEvent"); + + new SpringContextBootstrappingInitializer().onApplicationEvent(mockContextRefreshedEvent); + + assertThat(SpringContextBootstrappingInitializer.contextRefreshedEvent, is(sameInstance(mockContextRefreshedEvent))); + assertNotified(testApplicationListener, mockContextRefreshedEvent); + } + finally { + SpringContextBootstrappingInitializer.unregister(testApplicationListener); + } + } + + @Test + public void onContextStartedApplicationEvent() { + TestApplicationListener testApplicationListener = new TestApplicationListener( + "testOnContextStartedApplicationEvent"); + + try { + testApplicationListener = SpringContextBootstrappingInitializer.register(testApplicationListener); + + assertThat(SpringContextBootstrappingInitializer.contextRefreshedEvent, is(nullValue())); + assertUnnotified(testApplicationListener); + + new SpringContextBootstrappingInitializer().onApplicationEvent(mock(ContextStartedEvent.class, + "MockContextStartedEvent")); + + assertThat(SpringContextBootstrappingInitializer.contextRefreshedEvent, is(nullValue())); + assertUnnotified(testApplicationListener); + } + finally { + SpringContextBootstrappingInitializer.unregister(testApplicationListener); + } + } + + @Test + public void onContextStoppedApplicationEvent() { + TestApplicationListener testApplicationListener = new TestApplicationListener( + "testOnContextStartedApplicationEvent"); + + try { + testApplicationListener = SpringContextBootstrappingInitializer.register(testApplicationListener); + + assertUnnotified(testApplicationListener); + + ContextRefreshedEvent mockContextRefreshedEvent = mock(ContextRefreshedEvent.class, + "MockContextRefreshedEvent"); + + SpringContextBootstrappingInitializer.contextRefreshedEvent = mockContextRefreshedEvent; + + assertThat(SpringContextBootstrappingInitializer.contextRefreshedEvent, is(sameInstance( + mockContextRefreshedEvent))); + + new SpringContextBootstrappingInitializer().onApplicationEvent(mock(ContextStoppedEvent.class, + "MockContextStoppedEvent")); + + assertThat(SpringContextBootstrappingInitializer.contextRefreshedEvent, is(sameInstance(mockContextRefreshedEvent))); + assertUnnotified(testApplicationListener); + } + finally { + SpringContextBootstrappingInitializer.unregister(testApplicationListener); + } + } + + @Test + public void onApplicationEventWithMultipleRegisteredApplicationListeners() { + TestApplicationListener testApplicationListenerOne = new TestApplicationListener("TestApplicationListener.1"); + + TestApplicationListener testApplicationListenerTwo = new TestApplicationListener("TestApplicationListener.2"); + + TestApplicationListener testApplicationListenerThree = new TestApplicationListener("TestApplicationListener.3"); try { testApplicationListenerOne = SpringContextBootstrappingInitializer.register(testApplicationListenerOne); testApplicationListenerTwo = SpringContextBootstrappingInitializer.register(testApplicationListenerTwo); testApplicationListenerThree = SpringContextBootstrappingInitializer.register(testApplicationListenerThree); + assertThat(SpringContextBootstrappingInitializer.contextRefreshedEvent, is(nullValue())); assertUnnotified(testApplicationListenerOne); assertUnnotified(testApplicationListenerTwo); assertUnnotified(testApplicationListenerThree); - ContextRefreshedEvent testContextRefreshedEvent = new ContextRefreshedEvent(mock(ApplicationContext.class, - "testOnApplicationEventWithMultipleRegisteredApplicationListeners")); + ContextRefreshedEvent mockContextRefreshedEvent = mock(ContextRefreshedEvent.class, + "MockContextRefreshedEvent"); - new SpringContextBootstrappingInitializer().onApplicationEvent(testContextRefreshedEvent); + new SpringContextBootstrappingInitializer().onApplicationEvent(mockContextRefreshedEvent); - assertNotified(testApplicationListenerOne, testContextRefreshedEvent); - assertNotified(testApplicationListenerTwo, testContextRefreshedEvent); - assertNotified(testApplicationListenerThree, testContextRefreshedEvent); + assertThat(SpringContextBootstrappingInitializer.contextRefreshedEvent, + is(sameInstance(mockContextRefreshedEvent))); + assertNotified(testApplicationListenerOne, mockContextRefreshedEvent); + assertNotified(testApplicationListenerTwo, mockContextRefreshedEvent); + assertNotified(testApplicationListenerThree, mockContextRefreshedEvent); } finally { SpringContextBootstrappingInitializer.unregister(testApplicationListenerOne); @@ -651,9 +778,8 @@ public class SpringContextBootstrappingInitializerTest { } @Test - public void testOnApplicationEventWithUnregisteredApplicationListener() { - TestApplicationListener testApplicationListener = new TestApplicationListener( - "testOnApplicationEventWithUnregisteredApplicationListener"); + public void onApplicationEventWithNoRegisteredApplicationListener() { + TestApplicationListener testApplicationListener = new TestApplicationListener("TestApplicationListener"); try { testApplicationListener = SpringContextBootstrappingInitializer.unregister( @@ -661,10 +787,8 @@ public class SpringContextBootstrappingInitializerTest { assertUnnotified(testApplicationListener); - ContextRefreshedEvent testContextRefreshedEvent = new ContextRefreshedEvent(mock(ApplicationContext.class, - "testRegisterThenUnregisterWithOnApplicationEvent")); - - new SpringContextBootstrappingInitializer().onApplicationEvent(testContextRefreshedEvent); + new SpringContextBootstrappingInitializer().onApplicationEvent(mock(ContextRefreshedEvent.class, + "MockContextRefreshedEvent")); assertUnnotified(testApplicationListener); } @@ -794,7 +918,7 @@ public class SpringContextBootstrappingInitializerTest { private volatile boolean notified = false; - private volatile ContextRefreshedEvent actualEvent; + private volatile ApplicationContextEvent actualEvent; private final String name; @@ -802,8 +926,8 @@ public class SpringContextBootstrappingInitializerTest { this.name = name; } - public ContextRefreshedEvent getActualEvent() { - ContextRefreshedEvent localActualEvent = this.actualEvent; + public ApplicationContextEvent getActualEvent() { + ApplicationContextEvent localActualEvent = this.actualEvent; this.actualEvent = null; return localActualEvent; } diff --git a/src/test/resources/lazy-wiring-declarable-support-function-cache.xml b/src/test/resources/lazy-wiring-declarable-support-function-cache.xml new file mode 100644 index 00000000..203bcde7 --- /dev/null +++ b/src/test/resources/lazy-wiring-declarable-support-function-cache.xml @@ -0,0 +1,13 @@ + + + + + + org.springframework.data.gemfire.LazyWiringDeclarableSupportFunctionBasedIntegrationTest$HelloGemFireFunction + + Everyone + + + + diff --git a/src/test/resources/org/springframework/data/gemfire/LazyWiringDeclarableSupportFunctionBasedIntegrationTest-context.xml b/src/test/resources/org/springframework/data/gemfire/LazyWiringDeclarableSupportFunctionBasedIntegrationTest-context.xml new file mode 100644 index 00000000..bc66cc70 --- /dev/null +++ b/src/test/resources/org/springframework/data/gemfire/LazyWiringDeclarableSupportFunctionBasedIntegrationTest-context.xml @@ -0,0 +1,37 @@ + + + + + Spring + Universe + + + + + + LazyWiringDeclarableSupportFunctionBasedIntegrationTest + 0 + warning + HelloGroup + + + + + + + + +